Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'for-airlied' of git://people.freedesktop.org/~mlankhorst/linux into drm-next

TTM reservations changes, preparing for new reservation mutex system.

* 'for-airlied' of git://people.freedesktop.org/~mlankhorst/linux:
drm/ttm: unexport ttm_bo_wait_unreserved
drm/nouveau: use ttm_bo_reserve_slowpath in validate_init, v2
drm/ttm: use ttm_bo_reserve_slowpath_nolru in ttm_eu_reserve_buffers, v2
drm/ttm: add ttm_bo_reserve_slowpath
drm/ttm: cleanup ttm_eu_reserve_buffers handling
drm/ttm: remove lru_lock around ttm_bo_reserve
drm/nouveau: increase reservation sequence every retry
drm/vmwgfx: always use ttm_bo_is_reserved

+179 -89
+16 -4
drivers/gpu/drm/nouveau/nouveau_gem.c
··· 318 318 uint32_t sequence; 319 319 int trycnt = 0; 320 320 int ret, i; 321 + struct nouveau_bo *res_bo = NULL; 321 322 322 323 sequence = atomic_add_return(1, &drm->ttm.validate_sequence); 323 324 retry: ··· 339 338 return -ENOENT; 340 339 } 341 340 nvbo = gem->driver_private; 341 + if (nvbo == res_bo) { 342 + res_bo = NULL; 343 + drm_gem_object_unreference_unlocked(gem); 344 + continue; 345 + } 342 346 343 347 if (nvbo->reserved_by && nvbo->reserved_by == file_priv) { 344 348 NV_ERROR(drm, "multiple instances of buffer %d on " ··· 356 350 ret = ttm_bo_reserve(&nvbo->bo, true, false, true, sequence); 357 351 if (ret) { 358 352 validate_fini(op, NULL); 359 - if (unlikely(ret == -EAGAIN)) 360 - ret = ttm_bo_wait_unreserved(&nvbo->bo, true); 361 - drm_gem_object_unreference_unlocked(gem); 353 + if (unlikely(ret == -EAGAIN)) { 354 + sequence = atomic_add_return(1, &drm->ttm.validate_sequence); 355 + ret = ttm_bo_reserve_slowpath(&nvbo->bo, true, 356 + sequence); 357 + if (!ret) 358 + res_bo = nvbo; 359 + } 362 360 if (unlikely(ret)) { 361 + drm_gem_object_unreference_unlocked(gem); 363 362 if (ret != -ERESTARTSYS) 364 363 NV_ERROR(drm, "fail reserve\n"); 365 364 return ret; 366 365 } 367 - goto retry; 368 366 } 369 367 370 368 b->user_priv = (uint64_t)(unsigned long)nvbo; ··· 390 380 validate_fini(op, NULL); 391 381 return -EINVAL; 392 382 } 383 + if (nvbo == res_bo) 384 + goto retry; 393 385 } 394 386 395 387 return 0;
+84 -21
drivers/gpu/drm/ttm/ttm_bo.c
··· 158 158 ttm_mem_global_free(bdev->glob->mem_glob, acc_size); 159 159 } 160 160 161 - int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, bool interruptible) 161 + static int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, 162 + bool interruptible) 162 163 { 163 164 if (interruptible) { 164 165 return wait_event_interruptible(bo->event_queue, ··· 169 168 return 0; 170 169 } 171 170 } 172 - EXPORT_SYMBOL(ttm_bo_wait_unreserved); 173 171 174 172 void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) 175 173 { ··· 213 213 return put_count; 214 214 } 215 215 216 - int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, 216 + int ttm_bo_reserve_nolru(struct ttm_buffer_object *bo, 217 217 bool interruptible, 218 218 bool no_wait, bool use_sequence, uint32_t sequence) 219 219 { 220 - struct ttm_bo_global *glob = bo->glob; 221 220 int ret; 222 221 223 - while (unlikely(atomic_read(&bo->reserved) != 0)) { 222 + while (unlikely(atomic_xchg(&bo->reserved, 1) != 0)) { 224 223 /** 225 224 * Deadlock avoidance for multi-bo reserving. 226 225 */ ··· 240 241 if (no_wait) 241 242 return -EBUSY; 242 243 243 - spin_unlock(&glob->lru_lock); 244 244 ret = ttm_bo_wait_unreserved(bo, interruptible); 245 - spin_lock(&glob->lru_lock); 246 245 247 246 if (unlikely(ret)) 248 247 return ret; 249 248 } 250 249 251 - atomic_set(&bo->reserved, 1); 252 250 if (use_sequence) { 251 + bool wake_up = false; 253 252 /** 254 253 * Wake up waiters that may need to recheck for deadlock, 255 254 * if we decreased the sequence number. 256 255 */ 257 256 if (unlikely((bo->val_seq - sequence < (1 << 31)) 258 257 || !bo->seq_valid)) 259 - wake_up_all(&bo->event_queue); 258 + wake_up = true; 260 259 260 + /* 261 + * In the worst case with memory ordering these values can be 262 + * seen in the wrong order. However since we call wake_up_all 263 + * in that case, this will hopefully not pose a problem, 264 + * and the worst case would only cause someone to accidentally 265 + * hit -EAGAIN in ttm_bo_reserve when they see old value of 266 + * val_seq. However this would only happen if seq_valid was 267 + * written before val_seq was, and just means some slightly 268 + * increased cpu usage 269 + */ 261 270 bo->val_seq = sequence; 262 271 bo->seq_valid = true; 272 + if (wake_up) 273 + wake_up_all(&bo->event_queue); 263 274 } else { 264 275 bo->seq_valid = false; 265 276 } ··· 298 289 int put_count = 0; 299 290 int ret; 300 291 301 - spin_lock(&glob->lru_lock); 302 - ret = ttm_bo_reserve_locked(bo, interruptible, no_wait, use_sequence, 303 - sequence); 304 - if (likely(ret == 0)) 292 + ret = ttm_bo_reserve_nolru(bo, interruptible, no_wait, use_sequence, 293 + sequence); 294 + if (likely(ret == 0)) { 295 + spin_lock(&glob->lru_lock); 305 296 put_count = ttm_bo_del_from_lru(bo); 306 - spin_unlock(&glob->lru_lock); 307 - 308 - ttm_bo_list_ref_sub(bo, put_count, true); 297 + spin_unlock(&glob->lru_lock); 298 + ttm_bo_list_ref_sub(bo, put_count, true); 299 + } 309 300 310 301 return ret; 311 302 } 303 + 304 + int ttm_bo_reserve_slowpath_nolru(struct ttm_buffer_object *bo, 305 + bool interruptible, uint32_t sequence) 306 + { 307 + bool wake_up = false; 308 + int ret; 309 + 310 + while (unlikely(atomic_xchg(&bo->reserved, 1) != 0)) { 311 + WARN_ON(bo->seq_valid && sequence == bo->val_seq); 312 + 313 + ret = ttm_bo_wait_unreserved(bo, interruptible); 314 + 315 + if (unlikely(ret)) 316 + return ret; 317 + } 318 + 319 + if ((bo->val_seq - sequence < (1 << 31)) || !bo->seq_valid) 320 + wake_up = true; 321 + 322 + /** 323 + * Wake up waiters that may need to recheck for deadlock, 324 + * if we decreased the sequence number. 325 + */ 326 + bo->val_seq = sequence; 327 + bo->seq_valid = true; 328 + if (wake_up) 329 + wake_up_all(&bo->event_queue); 330 + 331 + return 0; 332 + } 333 + 334 + int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, 335 + bool interruptible, uint32_t sequence) 336 + { 337 + struct ttm_bo_global *glob = bo->glob; 338 + int put_count, ret; 339 + 340 + ret = ttm_bo_reserve_slowpath_nolru(bo, interruptible, sequence); 341 + if (likely(!ret)) { 342 + spin_lock(&glob->lru_lock); 343 + put_count = ttm_bo_del_from_lru(bo); 344 + spin_unlock(&glob->lru_lock); 345 + ttm_bo_list_ref_sub(bo, put_count, true); 346 + } 347 + return ret; 348 + } 349 + EXPORT_SYMBOL(ttm_bo_reserve_slowpath); 312 350 313 351 void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo) 314 352 { ··· 567 511 int ret; 568 512 569 513 spin_lock(&glob->lru_lock); 570 - ret = ttm_bo_reserve_locked(bo, false, true, false, 0); 514 + ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); 571 515 572 516 spin_lock(&bdev->fence_lock); 573 517 (void) ttm_bo_wait(bo, false, false, true); ··· 660 604 return ret; 661 605 662 606 spin_lock(&glob->lru_lock); 663 - ret = ttm_bo_reserve_locked(bo, false, true, false, 0); 607 + ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); 664 608 665 609 /* 666 610 * We raced, and lost, someone else holds the reservation now, ··· 724 668 kref_get(&nentry->list_kref); 725 669 } 726 670 727 - ret = ttm_bo_reserve_locked(entry, false, !remove_all, false, 0); 671 + ret = ttm_bo_reserve_nolru(entry, false, true, false, 0); 672 + if (remove_all && ret) { 673 + spin_unlock(&glob->lru_lock); 674 + ret = ttm_bo_reserve_nolru(entry, false, false, 675 + false, 0); 676 + spin_lock(&glob->lru_lock); 677 + } 678 + 728 679 if (!ret) 729 680 ret = ttm_bo_cleanup_refs_and_unlock(entry, false, 730 681 !remove_all); ··· 879 816 880 817 spin_lock(&glob->lru_lock); 881 818 list_for_each_entry(bo, &man->lru, lru) { 882 - ret = ttm_bo_reserve_locked(bo, false, true, false, 0); 819 + ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); 883 820 if (!ret) 884 821 break; 885 822 } ··· 1860 1797 1861 1798 spin_lock(&glob->lru_lock); 1862 1799 list_for_each_entry(bo, &glob->swap_lru, swap) { 1863 - ret = ttm_bo_reserve_locked(bo, false, true, false, 0); 1800 + ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); 1864 1801 if (!ret) 1865 1802 break; 1866 1803 }
+43 -35
drivers/gpu/drm/ttm/ttm_execbuf_util.c
··· 82 82 } 83 83 } 84 84 85 - static int ttm_eu_wait_unreserved_locked(struct list_head *list, 86 - struct ttm_buffer_object *bo) 87 - { 88 - struct ttm_bo_global *glob = bo->glob; 89 - int ret; 90 - 91 - ttm_eu_del_from_lru_locked(list); 92 - spin_unlock(&glob->lru_lock); 93 - ret = ttm_bo_wait_unreserved(bo, true); 94 - spin_lock(&glob->lru_lock); 95 - if (unlikely(ret != 0)) 96 - ttm_eu_backoff_reservation_locked(list); 97 - return ret; 98 - } 99 - 100 - 101 85 void ttm_eu_backoff_reservation(struct list_head *list) 102 86 { 103 87 struct ttm_validate_buffer *entry; ··· 129 145 entry = list_first_entry(list, struct ttm_validate_buffer, head); 130 146 glob = entry->bo->glob; 131 147 132 - retry: 133 148 spin_lock(&glob->lru_lock); 134 149 val_seq = entry->bo->bdev->val_seq++; 135 150 151 + retry: 136 152 list_for_each_entry(entry, list, head) { 137 153 struct ttm_buffer_object *bo = entry->bo; 138 154 139 - retry_this_bo: 140 - ret = ttm_bo_reserve_locked(bo, true, true, true, val_seq); 155 + /* already slowpath reserved? */ 156 + if (entry->reserved) 157 + continue; 158 + 159 + ret = ttm_bo_reserve_nolru(bo, true, true, true, val_seq); 141 160 switch (ret) { 142 161 case 0: 143 162 break; 144 163 case -EBUSY: 145 - ret = ttm_eu_wait_unreserved_locked(list, bo); 146 - if (unlikely(ret != 0)) { 147 - spin_unlock(&glob->lru_lock); 148 - ttm_eu_list_ref_sub(list); 149 - return ret; 150 - } 151 - goto retry_this_bo; 164 + ttm_eu_del_from_lru_locked(list); 165 + spin_unlock(&glob->lru_lock); 166 + ret = ttm_bo_reserve_nolru(bo, true, false, 167 + true, val_seq); 168 + spin_lock(&glob->lru_lock); 169 + if (!ret) 170 + break; 171 + 172 + if (unlikely(ret != -EAGAIN)) 173 + goto err; 174 + 175 + /* fallthrough */ 152 176 case -EAGAIN: 153 177 ttm_eu_backoff_reservation_locked(list); 178 + 179 + /* 180 + * temporarily increase sequence number every retry, 181 + * to prevent us from seeing our old reservation 182 + * sequence when someone else reserved the buffer, 183 + * but hasn't updated the seq_valid/seqno members yet. 184 + */ 185 + val_seq = entry->bo->bdev->val_seq++; 186 + 154 187 spin_unlock(&glob->lru_lock); 155 188 ttm_eu_list_ref_sub(list); 156 - ret = ttm_bo_wait_unreserved(bo, true); 189 + ret = ttm_bo_reserve_slowpath_nolru(bo, true, val_seq); 157 190 if (unlikely(ret != 0)) 158 191 return ret; 192 + spin_lock(&glob->lru_lock); 193 + entry->reserved = true; 194 + if (unlikely(atomic_read(&bo->cpu_writers) > 0)) { 195 + ret = -EBUSY; 196 + goto err; 197 + } 159 198 goto retry; 160 199 default: 161 - ttm_eu_backoff_reservation_locked(list); 162 - spin_unlock(&glob->lru_lock); 163 - ttm_eu_list_ref_sub(list); 164 - return ret; 200 + goto err; 165 201 } 166 202 167 203 entry->reserved = true; 168 204 if (unlikely(atomic_read(&bo->cpu_writers) > 0)) { 169 - ttm_eu_backoff_reservation_locked(list); 170 - spin_unlock(&glob->lru_lock); 171 - ttm_eu_list_ref_sub(list); 172 - return -EBUSY; 205 + ret = -EBUSY; 206 + goto err; 173 207 } 174 208 } 175 209 ··· 196 194 ttm_eu_list_ref_sub(list); 197 195 198 196 return 0; 197 + 198 + err: 199 + ttm_eu_backoff_reservation_locked(list); 200 + spin_unlock(&glob->lru_lock); 201 + ttm_eu_list_ref_sub(list); 202 + return ret; 199 203 } 200 204 EXPORT_SYMBOL(ttm_eu_reserve_buffers); 201 205
+2 -2
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
··· 959 959 if (new_backup && new_backup != res->backup) { 960 960 961 961 if (res->backup) { 962 - BUG_ON(atomic_read(&res->backup->base.reserved) == 0); 962 + BUG_ON(!ttm_bo_is_reserved(&res->backup->base)); 963 963 list_del_init(&res->mob_head); 964 964 vmw_dmabuf_unreference(&res->backup); 965 965 } 966 966 967 967 res->backup = vmw_dmabuf_reference(new_backup); 968 - BUG_ON(atomic_read(&new_backup->base.reserved) == 0); 968 + BUG_ON(!ttm_bo_is_reserved(&new_backup->base)); 969 969 list_add_tail(&res->mob_head, &new_backup->res_list); 970 970 } 971 971 if (new_backup)
+34 -27
include/drm/ttm/ttm_bo_driver.h
··· 790 790 * to make room for a buffer already reserved. (Buffers are reserved before 791 791 * they are evicted). The following algorithm prevents such deadlocks from 792 792 * occurring: 793 - * 1) Buffers are reserved with the lru spinlock held. Upon successful 794 - * reservation they are removed from the lru list. This stops a reserved buffer 795 - * from being evicted. However the lru spinlock is released between the time 796 - * a buffer is selected for eviction and the time it is reserved. 797 - * Therefore a check is made when a buffer is reserved for eviction, that it 798 - * is still the first buffer in the lru list, before it is removed from the 799 - * list. @check_lru == 1 forces this check. If it fails, the function returns 800 - * -EINVAL, and the caller should then choose a new buffer to evict and repeat 801 - * the procedure. 802 - * 2) Processes attempting to reserve multiple buffers other than for eviction, 793 + * Processes attempting to reserve multiple buffers other than for eviction, 803 794 * (typically execbuf), should first obtain a unique 32-bit 804 795 * validation sequence number, 805 796 * and call this function with @use_sequence == 1 and @sequence == the unique ··· 821 830 bool interruptible, 822 831 bool no_wait, bool use_sequence, uint32_t sequence); 823 832 833 + /** 834 + * ttm_bo_reserve_slowpath_nolru: 835 + * @bo: A pointer to a struct ttm_buffer_object. 836 + * @interruptible: Sleep interruptible if waiting. 837 + * @sequence: Set (@bo)->sequence to this value after lock 838 + * 839 + * This is called after ttm_bo_reserve returns -EAGAIN and we backed off 840 + * from all our other reservations. Because there are no other reservations 841 + * held by us, this function cannot deadlock any more. 842 + * 843 + * Will not remove reserved buffers from the lru lists. 844 + * Otherwise identical to ttm_bo_reserve_slowpath. 845 + */ 846 + extern int ttm_bo_reserve_slowpath_nolru(struct ttm_buffer_object *bo, 847 + bool interruptible, 848 + uint32_t sequence); 849 + 824 850 825 851 /** 826 - * ttm_bo_reserve_locked: 852 + * ttm_bo_reserve_slowpath: 853 + * @bo: A pointer to a struct ttm_buffer_object. 854 + * @interruptible: Sleep interruptible if waiting. 855 + * @sequence: Set (@bo)->sequence to this value after lock 856 + * 857 + * This is called after ttm_bo_reserve returns -EAGAIN and we backed off 858 + * from all our other reservations. Because there are no other reservations 859 + * held by us, this function cannot deadlock any more. 860 + */ 861 + extern int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, 862 + bool interruptible, uint32_t sequence); 863 + 864 + /** 865 + * ttm_bo_reserve_nolru: 827 866 * 828 867 * @bo: A pointer to a struct ttm_buffer_object. 829 868 * @interruptible: Sleep interruptible if waiting. ··· 861 840 * @use_sequence: If @bo is already reserved, Only sleep waiting for 862 841 * it to become unreserved if @sequence < (@bo)->sequence. 863 842 * 864 - * Must be called with struct ttm_bo_global::lru_lock held, 865 - * and will not remove reserved buffers from the lru lists. 866 - * The function may release the LRU spinlock if it needs to sleep. 843 + * Will not remove reserved buffers from the lru lists. 867 844 * Otherwise identical to ttm_bo_reserve. 868 845 * 869 846 * Returns: ··· 874 855 * -EDEADLK: Bo already reserved using @sequence. This error code will only 875 856 * be returned if @use_sequence is set to true. 876 857 */ 877 - extern int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, 858 + extern int ttm_bo_reserve_nolru(struct ttm_buffer_object *bo, 878 859 bool interruptible, 879 860 bool no_wait, bool use_sequence, 880 861 uint32_t sequence); ··· 897 878 * Needs to be called with struct ttm_bo_global::lru_lock held. 898 879 */ 899 880 extern void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo); 900 - 901 - /** 902 - * ttm_bo_wait_unreserved 903 - * 904 - * @bo: A pointer to a struct ttm_buffer_object. 905 - * 906 - * Wait for a struct ttm_buffer_object to become unreserved. 907 - * This is typically used in the execbuf code to relax cpu-usage when 908 - * a potential deadlock condition backoff. 909 - */ 910 - extern int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, 911 - bool interruptible); 912 881 913 882 /* 914 883 * ttm_bo_util.c