Commit b580c9e2 authored by Maarten Lankhorst's avatar Maarten Lankhorst Committed by Dave Airlie

drm/nouveau: make flipping lockdep safe

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: default avatarMaarten Lankhorst <maarten.lankhorst@canonical.com>
Acked-by: default avatarBen Skeggs <bskeggs@redhat.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent ecff665f
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_crtc_helper.h> #include <drm/drm_crtc_helper.h>
#include <drm/ttm/ttm_execbuf_util.h>
#include "nouveau_fbcon.h" #include "nouveau_fbcon.h"
#include "dispnv04/hw.h" #include "dispnv04/hw.h"
...@@ -456,51 +457,6 @@ nouveau_display_resume(struct drm_device *dev) ...@@ -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 static int
nouveau_page_flip_emit(struct nouveau_channel *chan, nouveau_page_flip_emit(struct nouveau_channel *chan,
struct nouveau_bo *old_bo, struct nouveau_bo *old_bo,
...@@ -563,6 +519,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, ...@@ -563,6 +519,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct nouveau_page_flip_state *s; struct nouveau_page_flip_state *s;
struct nouveau_channel *chan = NULL; struct nouveau_channel *chan = NULL;
struct nouveau_fence *fence; struct nouveau_fence *fence;
struct list_head res;
struct ttm_validate_buffer res_val[2];
struct ww_acquire_ctx ticket;
int ret; int ret;
if (!drm->channel) if (!drm->channel)
...@@ -572,10 +531,36 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, ...@@ -572,10 +531,36 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
if (!s) if (!s)
return -ENOMEM; return -ENOMEM;
/* Don't let the buffers go away while we flip */ /* Choose the channel the flip will be handled in */
ret = nouveau_page_flip_reserve(old_bo, new_bo); 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) 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; goto fail_free;
}
/* Initialize a page flip struct */ /* Initialize a page flip struct */
*s = (struct nouveau_page_flip_state) *s = (struct nouveau_page_flip_state)
...@@ -583,14 +568,6 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, ...@@ -583,14 +568,6 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y, fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
new_bo->bo.offset }; new_bo->bo.offset };
/* Choose the channel the flip will be handled in */
fence = new_bo->bo.sync_obj;
if (fence)
chan = fence->channel;
if (!chan)
chan = drm->channel;
mutex_lock(&chan->cli->mutex);
/* Emit a page flip */ /* Emit a page flip */
if (nv_device(drm->device)->card_type >= NV_50) { if (nv_device(drm->device)->card_type >= NV_50) {
ret = nv50_display_flip_next(crtc, fb, chan, 0); 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, ...@@ -608,12 +585,22 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
/* Update the crtc struct and cleanup */ /* Update the crtc struct and cleanup */
crtc->fb = fb; 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); nouveau_fence_unref(&fence);
return 0; return 0;
fail_unreserve: 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: fail_free:
kfree(s); kfree(s);
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment