diff options
author | Maarten Lankhorst <maarten.lankhorst@canonical.com> | 2014-04-09 10:19:30 -0400 |
---|---|---|
committer | Maarten Lankhorst <maarten.lankhorst@canonical.com> | 2014-09-02 11:28:48 -0400 |
commit | 809e9447b92ffe1346b2d6ec390e212d5307f61c (patch) | |
tree | 11d04d4ef34cd681cf63efa11a90992c7865eb27 /drivers/gpu | |
parent | 9242829a87e970773628f30522d2278dd91890ec (diff) |
drm/nouveau: use shared fences for readable objects
nouveau keeps track in userspace whether a buffer is being
written to or being read, but it doesn't use that information.
Change this to allow multiple readers on the same bo.
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Acked-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bo.c | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bo.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.c | 55 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fence.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gem.c | 37 |
6 files changed, 68 insertions, 47 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 6cf7db070faf..eea74b127b03 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
@@ -94,7 +94,7 @@ nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile, | |||
94 | 94 | ||
95 | if (tile) { | 95 | if (tile) { |
96 | spin_lock(&drm->tile.lock); | 96 | spin_lock(&drm->tile.lock); |
97 | tile->fence = nouveau_fence_ref((struct nouveau_fence *)fence); | 97 | tile->fence = (struct nouveau_fence *)fence_get(fence); |
98 | tile->used = false; | 98 | tile->used = false; |
99 | spin_unlock(&drm->tile.lock); | 99 | spin_unlock(&drm->tile.lock); |
100 | } | 100 | } |
@@ -970,7 +970,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, | |||
970 | } | 970 | } |
971 | 971 | ||
972 | mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING); | 972 | mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING); |
973 | ret = nouveau_fence_sync(nouveau_bo(bo), chan); | 973 | ret = nouveau_fence_sync(nouveau_bo(bo), chan, true); |
974 | if (ret == 0) { | 974 | if (ret == 0) { |
975 | ret = drm->ttm.move(chan, bo, &bo->mem, new_mem); | 975 | ret = drm->ttm.move(chan, bo, &bo->mem, new_mem); |
976 | if (ret == 0) { | 976 | if (ret == 0) { |
@@ -1458,11 +1458,14 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) | |||
1458 | } | 1458 | } |
1459 | 1459 | ||
1460 | void | 1460 | void |
1461 | nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence) | 1461 | nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence, bool exclusive) |
1462 | { | 1462 | { |
1463 | struct reservation_object *resv = nvbo->bo.resv; | 1463 | struct reservation_object *resv = nvbo->bo.resv; |
1464 | 1464 | ||
1465 | reservation_object_add_excl_fence(resv, &fence->base); | 1465 | if (exclusive) |
1466 | reservation_object_add_excl_fence(resv, &fence->base); | ||
1467 | else if (fence) | ||
1468 | reservation_object_add_shared_fence(resv, &fence->base); | ||
1466 | } | 1469 | } |
1467 | 1470 | ||
1468 | struct ttm_bo_driver nouveau_bo_driver = { | 1471 | struct ttm_bo_driver nouveau_bo_driver = { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index 4ef88e84a694..ae95b2d43b36 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h | |||
@@ -78,7 +78,7 @@ u16 nouveau_bo_rd16(struct nouveau_bo *, unsigned index); | |||
78 | void nouveau_bo_wr16(struct nouveau_bo *, unsigned index, u16 val); | 78 | void nouveau_bo_wr16(struct nouveau_bo *, unsigned index, u16 val); |
79 | u32 nouveau_bo_rd32(struct nouveau_bo *, unsigned index); | 79 | u32 nouveau_bo_rd32(struct nouveau_bo *, unsigned index); |
80 | void nouveau_bo_wr32(struct nouveau_bo *, unsigned index, u32 val); | 80 | void nouveau_bo_wr32(struct nouveau_bo *, unsigned index, u32 val); |
81 | void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *); | 81 | void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *, bool exclusive); |
82 | int nouveau_bo_validate(struct nouveau_bo *, bool interruptible, | 82 | int nouveau_bo_validate(struct nouveau_bo *, bool interruptible, |
83 | bool no_wait_gpu); | 83 | bool no_wait_gpu); |
84 | 84 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index ec1960a9412c..a9ec525c0994 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -658,7 +658,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan, | |||
658 | spin_unlock_irqrestore(&dev->event_lock, flags); | 658 | spin_unlock_irqrestore(&dev->event_lock, flags); |
659 | 659 | ||
660 | /* Synchronize with the old framebuffer */ | 660 | /* Synchronize with the old framebuffer */ |
661 | ret = nouveau_fence_sync(old_bo, chan); | 661 | ret = nouveau_fence_sync(old_bo, chan, false); |
662 | if (ret) | 662 | if (ret) |
663 | goto fail; | 663 | goto fail; |
664 | 664 | ||
@@ -722,7 +722,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
722 | goto fail_unpin; | 722 | goto fail_unpin; |
723 | 723 | ||
724 | /* synchronise rendering channel with the kernel's channel */ | 724 | /* synchronise rendering channel with the kernel's channel */ |
725 | ret = nouveau_fence_sync(new_bo, chan); | 725 | ret = nouveau_fence_sync(new_bo, chan, false); |
726 | if (ret) { | 726 | if (ret) { |
727 | ttm_bo_unreserve(&new_bo->bo); | 727 | ttm_bo_unreserve(&new_bo->bo); |
728 | goto fail_unpin; | 728 | goto fail_unpin; |
@@ -780,7 +780,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
780 | /* Update the crtc struct and cleanup */ | 780 | /* Update the crtc struct and cleanup */ |
781 | crtc->primary->fb = fb; | 781 | crtc->primary->fb = fb; |
782 | 782 | ||
783 | nouveau_bo_fence(old_bo, fence); | 783 | nouveau_bo_fence(old_bo, fence, false); |
784 | ttm_bo_unreserve(&old_bo->bo); | 784 | ttm_bo_unreserve(&old_bo->bo); |
785 | if (old_bo != new_bo) | 785 | if (old_bo != new_bo) |
786 | nouveau_bo_unpin(old_bo); | 786 | nouveau_bo_unpin(old_bo); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 5e7fa68bc438..decfe6c4ac07 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c | |||
@@ -342,41 +342,56 @@ nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr) | |||
342 | } | 342 | } |
343 | 343 | ||
344 | int | 344 | int |
345 | nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan) | 345 | nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool exclusive) |
346 | { | 346 | { |
347 | struct nouveau_fence_chan *fctx = chan->fence; | 347 | struct nouveau_fence_chan *fctx = chan->fence; |
348 | struct fence *fence = NULL; | 348 | struct fence *fence; |
349 | struct reservation_object *resv = nvbo->bo.resv; | 349 | struct reservation_object *resv = nvbo->bo.resv; |
350 | struct reservation_object_list *fobj; | 350 | struct reservation_object_list *fobj; |
351 | struct nouveau_fence *f; | ||
351 | int ret = 0, i; | 352 | int ret = 0, i; |
352 | 353 | ||
354 | if (!exclusive) { | ||
355 | ret = reservation_object_reserve_shared(resv); | ||
356 | |||
357 | if (ret) | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | fobj = reservation_object_get_list(resv); | ||
353 | fence = reservation_object_get_excl(resv); | 362 | fence = reservation_object_get_excl(resv); |
354 | 363 | ||
355 | if (fence && !fence_is_signaled(fence)) { | 364 | if (fence && (!exclusive || !fobj || !fobj->shared_count)) { |
356 | struct nouveau_fence *f = from_fence(fence); | 365 | struct nouveau_channel *prev = NULL; |
357 | struct nouveau_channel *prev = f->channel; | ||
358 | 366 | ||
359 | if (prev != chan) { | 367 | f = nouveau_local_fence(fence, chan->drm); |
360 | ret = fctx->sync(f, prev, chan); | 368 | if (f) |
361 | if (unlikely(ret)) | 369 | prev = f->channel; |
362 | ret = nouveau_fence_wait(f, true, true); | 370 | |
363 | } | 371 | if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan)))) |
364 | } | 372 | ret = fence_wait(fence, true); |
365 | 373 | ||
366 | if (ret) | ||
367 | return ret; | 374 | return ret; |
375 | } | ||
368 | 376 | ||
369 | fobj = reservation_object_get_list(resv); | 377 | if (!exclusive || !fobj) |
370 | if (!fobj) | ||
371 | return ret; | 378 | return ret; |
372 | 379 | ||
373 | for (i = 0; i < fobj->shared_count && !ret; ++i) { | 380 | for (i = 0; i < fobj->shared_count && !ret; ++i) { |
381 | struct nouveau_channel *prev = NULL; | ||
382 | |||
374 | fence = rcu_dereference_protected(fobj->shared[i], | 383 | fence = rcu_dereference_protected(fobj->shared[i], |
375 | reservation_object_held(resv)); | 384 | reservation_object_held(resv)); |
376 | 385 | ||
377 | /* should always be true, for now */ | 386 | f = nouveau_local_fence(fence, chan->drm); |
378 | if (!nouveau_local_fence(fence, chan->drm)) | 387 | if (f) |
388 | prev = f->channel; | ||
389 | |||
390 | if (!prev || (ret = fctx->sync(f, prev, chan))) | ||
379 | ret = fence_wait(fence, true); | 391 | ret = fence_wait(fence, true); |
392 | |||
393 | if (ret) | ||
394 | break; | ||
380 | } | 395 | } |
381 | 396 | ||
382 | return ret; | 397 | return ret; |
@@ -390,14 +405,6 @@ nouveau_fence_unref(struct nouveau_fence **pfence) | |||
390 | *pfence = NULL; | 405 | *pfence = NULL; |
391 | } | 406 | } |
392 | 407 | ||
393 | struct nouveau_fence * | ||
394 | nouveau_fence_ref(struct nouveau_fence *fence) | ||
395 | { | ||
396 | if (fence) | ||
397 | fence_get(&fence->base); | ||
398 | return fence; | ||
399 | } | ||
400 | |||
401 | int | 408 | int |
402 | nouveau_fence_new(struct nouveau_channel *chan, bool sysmem, | 409 | nouveau_fence_new(struct nouveau_channel *chan, bool sysmem, |
403 | struct nouveau_fence **pfence) | 410 | struct nouveau_fence **pfence) |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index 0282e88274ff..986c8135e564 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h | |||
@@ -20,15 +20,13 @@ struct nouveau_fence { | |||
20 | 20 | ||
21 | int nouveau_fence_new(struct nouveau_channel *, bool sysmem, | 21 | int nouveau_fence_new(struct nouveau_channel *, bool sysmem, |
22 | struct nouveau_fence **); | 22 | struct nouveau_fence **); |
23 | struct nouveau_fence * | ||
24 | nouveau_fence_ref(struct nouveau_fence *); | ||
25 | void nouveau_fence_unref(struct nouveau_fence **); | 23 | void nouveau_fence_unref(struct nouveau_fence **); |
26 | 24 | ||
27 | int nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *); | 25 | int nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *); |
28 | bool nouveau_fence_done(struct nouveau_fence *); | 26 | bool nouveau_fence_done(struct nouveau_fence *); |
29 | void nouveau_fence_work(struct fence *, void (*)(void *), void *); | 27 | void nouveau_fence_work(struct fence *, void (*)(void *), void *); |
30 | int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr); | 28 | int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr); |
31 | int nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *); | 29 | int nouveau_fence_sync(struct nouveau_bo *, struct nouveau_channel *, bool exclusive); |
32 | 30 | ||
33 | struct nouveau_fence_chan { | 31 | struct nouveau_fence_chan { |
34 | spinlock_t lock; | 32 | spinlock_t lock; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 1ba5f9e0052c..b7dbd16904e0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c | |||
@@ -98,14 +98,23 @@ static void | |||
98 | nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma) | 98 | nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma) |
99 | { | 99 | { |
100 | const bool mapped = nvbo->bo.mem.mem_type != TTM_PL_SYSTEM; | 100 | const bool mapped = nvbo->bo.mem.mem_type != TTM_PL_SYSTEM; |
101 | struct reservation_object *resv = nvbo->bo.resv; | ||
102 | struct reservation_object_list *fobj; | ||
101 | struct fence *fence = NULL; | 103 | struct fence *fence = NULL; |
102 | 104 | ||
105 | fobj = reservation_object_get_list(resv); | ||
106 | |||
103 | list_del(&vma->head); | 107 | list_del(&vma->head); |
104 | 108 | ||
105 | if (mapped) | 109 | if (fobj && fobj->shared_count > 1) |
110 | ttm_bo_wait(&nvbo->bo, true, false, false); | ||
111 | else if (fobj && fobj->shared_count == 1) | ||
112 | fence = rcu_dereference_protected(fobj->shared[0], | ||
113 | reservation_object_held(resv)); | ||
114 | else | ||
106 | fence = reservation_object_get_excl(nvbo->bo.resv); | 115 | fence = reservation_object_get_excl(nvbo->bo.resv); |
107 | 116 | ||
108 | if (fence) { | 117 | if (fence && mapped) { |
109 | nouveau_fence_work(fence, nouveau_gem_object_delete, vma); | 118 | nouveau_fence_work(fence, nouveau_gem_object_delete, vma); |
110 | } else { | 119 | } else { |
111 | if (mapped) | 120 | if (mapped) |
@@ -289,15 +298,18 @@ struct validate_op { | |||
289 | }; | 298 | }; |
290 | 299 | ||
291 | static void | 300 | static void |
292 | validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence) | 301 | validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence, |
302 | struct drm_nouveau_gem_pushbuf_bo *pbbo) | ||
293 | { | 303 | { |
294 | struct nouveau_bo *nvbo; | 304 | struct nouveau_bo *nvbo; |
305 | struct drm_nouveau_gem_pushbuf_bo *b; | ||
295 | 306 | ||
296 | while (!list_empty(&op->list)) { | 307 | while (!list_empty(&op->list)) { |
297 | nvbo = list_entry(op->list.next, struct nouveau_bo, entry); | 308 | nvbo = list_entry(op->list.next, struct nouveau_bo, entry); |
309 | b = &pbbo[nvbo->pbbo_index]; | ||
298 | 310 | ||
299 | if (likely(fence)) | 311 | if (likely(fence)) |
300 | nouveau_bo_fence(nvbo, fence); | 312 | nouveau_bo_fence(nvbo, fence, !!b->write_domains); |
301 | 313 | ||
302 | if (unlikely(nvbo->validate_mapped)) { | 314 | if (unlikely(nvbo->validate_mapped)) { |
303 | ttm_bo_kunmap(&nvbo->kmap); | 315 | ttm_bo_kunmap(&nvbo->kmap); |
@@ -312,9 +324,10 @@ validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence) | |||
312 | } | 324 | } |
313 | 325 | ||
314 | static void | 326 | static void |
315 | validate_fini(struct validate_op *op, struct nouveau_fence *fence) | 327 | validate_fini(struct validate_op *op, struct nouveau_fence *fence, |
328 | struct drm_nouveau_gem_pushbuf_bo *pbbo) | ||
316 | { | 329 | { |
317 | validate_fini_no_ticket(op, fence); | 330 | validate_fini_no_ticket(op, fence, pbbo); |
318 | ww_acquire_fini(&op->ticket); | 331 | ww_acquire_fini(&op->ticket); |
319 | } | 332 | } |
320 | 333 | ||
@@ -370,7 +383,7 @@ retry: | |||
370 | list_splice_tail_init(&vram_list, &op->list); | 383 | list_splice_tail_init(&vram_list, &op->list); |
371 | list_splice_tail_init(&gart_list, &op->list); | 384 | list_splice_tail_init(&gart_list, &op->list); |
372 | list_splice_tail_init(&both_list, &op->list); | 385 | list_splice_tail_init(&both_list, &op->list); |
373 | validate_fini_no_ticket(op, NULL); | 386 | validate_fini_no_ticket(op, NULL, NULL); |
374 | if (unlikely(ret == -EDEADLK)) { | 387 | if (unlikely(ret == -EDEADLK)) { |
375 | ret = ttm_bo_reserve_slowpath(&nvbo->bo, true, | 388 | ret = ttm_bo_reserve_slowpath(&nvbo->bo, true, |
376 | &op->ticket); | 389 | &op->ticket); |
@@ -412,7 +425,7 @@ retry: | |||
412 | list_splice_tail(&gart_list, &op->list); | 425 | list_splice_tail(&gart_list, &op->list); |
413 | list_splice_tail(&both_list, &op->list); | 426 | list_splice_tail(&both_list, &op->list); |
414 | if (ret) | 427 | if (ret) |
415 | validate_fini(op, NULL); | 428 | validate_fini(op, NULL, NULL); |
416 | return ret; | 429 | return ret; |
417 | 430 | ||
418 | } | 431 | } |
@@ -446,7 +459,7 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, | |||
446 | return ret; | 459 | return ret; |
447 | } | 460 | } |
448 | 461 | ||
449 | ret = nouveau_fence_sync(nvbo, chan); | 462 | ret = nouveau_fence_sync(nvbo, chan, !!b->write_domains); |
450 | if (unlikely(ret)) { | 463 | if (unlikely(ret)) { |
451 | if (ret != -ERESTARTSYS) | 464 | if (ret != -ERESTARTSYS) |
452 | NV_PRINTK(error, cli, "fail post-validate sync\n"); | 465 | NV_PRINTK(error, cli, "fail post-validate sync\n"); |
@@ -504,7 +517,7 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, | |||
504 | if (unlikely(ret < 0)) { | 517 | if (unlikely(ret < 0)) { |
505 | if (ret != -ERESTARTSYS) | 518 | if (ret != -ERESTARTSYS) |
506 | NV_PRINTK(error, cli, "validating bo list\n"); | 519 | NV_PRINTK(error, cli, "validating bo list\n"); |
507 | validate_fini(op, NULL); | 520 | validate_fini(op, NULL, NULL); |
508 | return ret; | 521 | return ret; |
509 | } | 522 | } |
510 | *apply_relocs = ret; | 523 | *apply_relocs = ret; |
@@ -610,7 +623,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, | |||
610 | data |= r->vor; | 623 | data |= r->vor; |
611 | } | 624 | } |
612 | 625 | ||
613 | ret = ttm_bo_wait(&nvbo->bo, false, false, false); | 626 | ret = ttm_bo_wait(&nvbo->bo, true, false, false); |
614 | if (ret) { | 627 | if (ret) { |
615 | NV_PRINTK(error, cli, "reloc wait_idle failed: %d\n", ret); | 628 | NV_PRINTK(error, cli, "reloc wait_idle failed: %d\n", ret); |
616 | break; | 629 | break; |
@@ -788,7 +801,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
788 | } | 801 | } |
789 | 802 | ||
790 | out: | 803 | out: |
791 | validate_fini(&op, fence); | 804 | validate_fini(&op, fence, bo); |
792 | nouveau_fence_unref(&fence); | 805 | nouveau_fence_unref(&fence); |
793 | 806 | ||
794 | out_prevalid: | 807 | out_prevalid: |