aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-07-08 00:15:51 -0400
committerBen Skeggs <bskeggs@redhat.com>2013-07-09 20:47:12 -0400
commit060810d7abaabcab282e062c595871d661561400 (patch)
treed27009af2a9255c10eeccf3f72246515dca11b38
parent06d5a24f08831e167fae42a64ef2083a89f8e617 (diff)
drm/nouveau: fix locking issues in page flipping paths
b580c9e2b7ba5030a795aa2fb73b796523d65a78 introduced additional problems while trying to solve issues that became apparent while porting to the new reservation stuff. The major problem was that the the previously mentioned patch took the client mutex earlier than previously, but the pinning of new_bo can can potentially cause a buffer move, which would result in attempting to acquire the same mutex again. This commit attempts to fix that "fix". Thanks to Maarten for the tips on keeping lockdep happy and cooking :) Reported-by: Maarten Lankhorst <maarten.lankhorst@canonical.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Acked-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c53
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c3
3 files changed, 22 insertions, 36 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 4b1afb131380..85fed108d7e4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -973,7 +973,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
973 struct ttm_mem_reg *old_mem = &bo->mem; 973 struct ttm_mem_reg *old_mem = &bo->mem;
974 int ret; 974 int ret;
975 975
976 mutex_lock(&chan->cli->mutex); 976 mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING);
977 977
978 /* create temporary vmas for the transfer and attach them to the 978 /* create temporary vmas for the transfer and attach them to the
979 * old nouveau_mem node, these will get cleaned up after ttm has 979 * old nouveau_mem node, these will get cleaned up after ttm has
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 708b2d1c0037..61fdef8eac49 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -524,9 +524,12 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
524 struct nouveau_page_flip_state *s; 524 struct nouveau_page_flip_state *s;
525 struct nouveau_channel *chan = NULL; 525 struct nouveau_channel *chan = NULL;
526 struct nouveau_fence *fence; 526 struct nouveau_fence *fence;
527 struct list_head res; 527 struct ttm_validate_buffer resv[2] = {
528 struct ttm_validate_buffer res_val[2]; 528 { .bo = &old_bo->bo },
529 { .bo = &new_bo->bo },
530 };
529 struct ww_acquire_ctx ticket; 531 struct ww_acquire_ctx ticket;
532 LIST_HEAD(res);
530 int ret; 533 int ret;
531 534
532 if (!drm->channel) 535 if (!drm->channel)
@@ -545,27 +548,19 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
545 chan = drm->channel; 548 chan = drm->channel;
546 spin_unlock(&old_bo->bo.bdev->fence_lock); 549 spin_unlock(&old_bo->bo.bdev->fence_lock);
547 550
548 mutex_lock(&chan->cli->mutex);
549
550 if (new_bo != old_bo) { 551 if (new_bo != old_bo) {
551 ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); 552 ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
552 if (likely(!ret)) { 553 if (ret)
553 res_val[0].bo = &old_bo->bo; 554 goto fail_free;
554 res_val[1].bo = &new_bo->bo;
555 INIT_LIST_HEAD(&res);
556 list_add_tail(&res_val[0].head, &res);
557 list_add_tail(&res_val[1].head, &res);
558 ret = ttm_eu_reserve_buffers(&ticket, &res);
559 if (ret)
560 nouveau_bo_unpin(new_bo);
561 }
562 } else
563 ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
564 555
565 if (ret) { 556 list_add(&resv[1].head, &res);
566 mutex_unlock(&chan->cli->mutex);
567 goto fail_free;
568 } 557 }
558 list_add(&resv[0].head, &res);
559
560 mutex_lock(&chan->cli->mutex);
561 ret = ttm_eu_reserve_buffers(&ticket, &res);
562 if (ret)
563 goto fail_unpin;
569 564
570 /* Initialize a page flip struct */ 565 /* Initialize a page flip struct */
571 *s = (struct nouveau_page_flip_state) 566 *s = (struct nouveau_page_flip_state)
@@ -576,10 +571,8 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
576 /* Emit a page flip */ 571 /* Emit a page flip */
577 if (nv_device(drm->device)->card_type >= NV_50) { 572 if (nv_device(drm->device)->card_type >= NV_50) {
578 ret = nv50_display_flip_next(crtc, fb, chan, 0); 573 ret = nv50_display_flip_next(crtc, fb, chan, 0);
579 if (ret) { 574 if (ret)
580 mutex_unlock(&chan->cli->mutex);
581 goto fail_unreserve; 575 goto fail_unreserve;
582 }
583 } 576 }
584 577
585 ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); 578 ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
@@ -590,22 +583,18 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
590 /* Update the crtc struct and cleanup */ 583 /* Update the crtc struct and cleanup */
591 crtc->fb = fb; 584 crtc->fb = fb;
592 585
593 if (old_bo != new_bo) { 586 ttm_eu_fence_buffer_objects(&ticket, &res, fence);
594 ttm_eu_fence_buffer_objects(&ticket, &res, fence); 587 if (old_bo != new_bo)
595 nouveau_bo_unpin(old_bo); 588 nouveau_bo_unpin(old_bo);
596 } else {
597 nouveau_bo_fence(new_bo, fence);
598 ttm_bo_unreserve(&new_bo->bo);
599 }
600 nouveau_fence_unref(&fence); 589 nouveau_fence_unref(&fence);
601 return 0; 590 return 0;
602 591
603fail_unreserve: 592fail_unreserve:
604 if (old_bo != new_bo) { 593 ttm_eu_backoff_reservation(&ticket, &res);
605 ttm_eu_backoff_reservation(&ticket, &res); 594fail_unpin:
595 mutex_unlock(&chan->cli->mutex);
596 if (old_bo != new_bo)
606 nouveau_bo_unpin(new_bo); 597 nouveau_bo_unpin(new_bo);
607 } else
608 ttm_bo_unreserve(&new_bo->bo);
609fail_free: 598fail_free:
610 kfree(s); 599 kfree(s);
611 return ret; 600 return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 218a4b522fe5..4eca52b8d573 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -284,8 +284,6 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
284 return 0; 284 return 0;
285} 285}
286 286
287static struct lock_class_key drm_client_lock_class_key;
288
289static int 287static int
290nouveau_drm_load(struct drm_device *dev, unsigned long flags) 288nouveau_drm_load(struct drm_device *dev, unsigned long flags)
291{ 289{
@@ -297,7 +295,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
297 ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm); 295 ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
298 if (ret) 296 if (ret)
299 return ret; 297 return ret;
300 lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key);
301 298
302 dev->dev_private = drm; 299 dev->dev_private = drm;
303 drm->dev = dev; 300 drm->dev = dev;