Skip to content

Commit

Permalink
drm/nouveau: make flipping lockdep safe
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Maarten Lankhorst authored and Dave Airlie committed Jun 28, 2013
1 parent ecff665 commit b580c9e
Showing 1 changed file with 45 additions and 58 deletions.
103 changes: 45 additions & 58 deletions drivers/gpu/drm/nouveau/nouveau_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand All @@ -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;
Expand Down

0 comments on commit b580c9e

Please sign in to comment.