drm/nouveau: make flipping lockdep safe
authorMaarten Lankhorst <m.b.lankhorst@gmail.com>
Thu, 27 Jun 2013 11:48:18 +0000 (13:48 +0200)
committerDave Airlie <airlied@redhat.com>
Fri, 28 Jun 2013 02:03:58 +0000 (12:03 +1000)
cli->mutex was inverted with reservations, and multiple reservations were
used without a ticket, fix both. This commit had to be done after the previous
commit, because otherwise ttm_eu_* calls would use a different seqno counter..

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Acked-by: Ben Skeggs <bskeggs@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/nouveau/nouveau_display.c

index f17dc2ab03ecd25a762e52840f02b8f4652345d4..87afb0cb39cb489cb6374b295c62922a4d8b1cf3 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/ttm/ttm_execbuf_util.h>
 
 #include "nouveau_fbcon.h"
 #include "dispnv04/hw.h"
@@ -456,51 +457,6 @@ nouveau_display_resume(struct drm_device *dev)
        }
 }
 
-static int
-nouveau_page_flip_reserve(struct nouveau_bo *old_bo,
-                         struct nouveau_bo *new_bo)
-{
-       int ret;
-
-       ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
-       if (ret)
-               return ret;
-
-       ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
-       if (ret)
-               goto fail;
-
-       if (likely(old_bo != new_bo)) {
-               ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0);
-               if (ret)
-                       goto fail_unreserve;
-       }
-
-       return 0;
-
-fail_unreserve:
-       ttm_bo_unreserve(&new_bo->bo);
-fail:
-       nouveau_bo_unpin(new_bo);
-       return ret;
-}
-
-static void
-nouveau_page_flip_unreserve(struct nouveau_bo *old_bo,
-                           struct nouveau_bo *new_bo,
-                           struct nouveau_fence *fence)
-{
-       nouveau_bo_fence(new_bo, fence);
-       ttm_bo_unreserve(&new_bo->bo);
-
-       if (likely(old_bo != new_bo)) {
-               nouveau_bo_fence(old_bo, fence);
-               ttm_bo_unreserve(&old_bo->bo);
-       }
-
-       nouveau_bo_unpin(old_bo);
-}
-
 static int
 nouveau_page_flip_emit(struct nouveau_channel *chan,
                       struct nouveau_bo *old_bo,
@@ -563,6 +519,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        struct nouveau_page_flip_state *s;
        struct nouveau_channel *chan = NULL;
        struct nouveau_fence *fence;
+       struct list_head res;
+       struct ttm_validate_buffer res_val[2];
+       struct ww_acquire_ctx ticket;
        int ret;
 
        if (!drm->channel)
@@ -572,25 +531,43 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        if (!s)
                return -ENOMEM;
 
-       /* Don't let the buffers go away while we flip */
-       ret = nouveau_page_flip_reserve(old_bo, new_bo);
-       if (ret)
-               goto fail_free;
-
-       /* Initialize a page flip struct */
-       *s = (struct nouveau_page_flip_state)
-               { { }, event, nouveau_crtc(crtc)->index,
-                 fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
-                 new_bo->bo.offset };
-
        /* Choose the channel the flip will be handled in */
+       spin_lock(&old_bo->bo.bdev->fence_lock);
        fence = new_bo->bo.sync_obj;
        if (fence)
                chan = fence->channel;
        if (!chan)
                chan = drm->channel;
+       spin_unlock(&old_bo->bo.bdev->fence_lock);
+
        mutex_lock(&chan->cli->mutex);
 
+       if (new_bo != old_bo) {
+               ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
+               if (likely(!ret)) {
+                       res_val[0].bo = &old_bo->bo;
+                       res_val[1].bo = &new_bo->bo;
+                       INIT_LIST_HEAD(&res);
+                       list_add_tail(&res_val[0].head, &res);
+                       list_add_tail(&res_val[1].head, &res);
+                       ret = ttm_eu_reserve_buffers(&ticket, &res);
+                       if (ret)
+                               nouveau_bo_unpin(new_bo);
+               }
+       } else
+               ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
+
+       if (ret) {
+               mutex_unlock(&chan->cli->mutex);
+               goto fail_free;
+       }
+
+       /* Initialize a page flip struct */
+       *s = (struct nouveau_page_flip_state)
+               { { }, event, nouveau_crtc(crtc)->index,
+                 fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
+                 new_bo->bo.offset };
+
        /* Emit a page flip */
        if (nv_device(drm->device)->card_type >= NV_50) {
                ret = nv50_display_flip_next(crtc, fb, chan, 0);
@@ -608,12 +585,22 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        /* Update the crtc struct and cleanup */
        crtc->fb = fb;
 
-       nouveau_page_flip_unreserve(old_bo, new_bo, fence);
+       if (old_bo != new_bo) {
+               ttm_eu_fence_buffer_objects(&ticket, &res, fence);
+               nouveau_bo_unpin(old_bo);
+       } else {
+               nouveau_bo_fence(new_bo, fence);
+               ttm_bo_unreserve(&new_bo->bo);
+       }
        nouveau_fence_unref(&fence);
        return 0;
 
 fail_unreserve:
-       nouveau_page_flip_unreserve(old_bo, new_bo, NULL);
+       if (old_bo != new_bo) {
+               ttm_eu_backoff_reservation(&ticket, &res);
+               nouveau_bo_unpin(new_bo);
+       } else
+               ttm_bo_unreserve(&new_bo->bo);
 fail_free:
        kfree(s);
        return ret;