Commit 8dda53fc authored by Ben Skeggs's avatar Ben Skeggs

drm/nv50/kms: fix pin refcnt leaks

Weren't critical previously, the buffers would go away anyway.  But with
recent changes to core drm/ttm lockdep will get pissed off now, so let's
fix it.
Reported-by: default avatarMaarten Lankhorst <maarten.lankhorst@canonical.com>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Acked-by: default avatarMaarten Lankhorst <maarten.lankhorst@canonical.com>
parent fdfb8332
...@@ -355,6 +355,7 @@ struct nv50_oimm { ...@@ -355,6 +355,7 @@ struct nv50_oimm {
struct nv50_head { struct nv50_head {
struct nouveau_crtc base; struct nouveau_crtc base;
struct nouveau_bo *image;
struct nv50_curs curs; struct nv50_curs curs;
struct nv50_sync sync; struct nv50_sync sync;
struct nv50_ovly ovly; struct nv50_ovly ovly;
...@@ -517,9 +518,10 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, ...@@ -517,9 +518,10 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
{ {
struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct nv50_head *head = nv50_head(crtc);
struct nv50_sync *sync = nv50_sync(crtc); struct nv50_sync *sync = nv50_sync(crtc);
int head = nv_crtc->index, ret;
u32 *push; u32 *push;
int ret;
swap_interval <<= 4; swap_interval <<= 4;
if (swap_interval == 0) if (swap_interval == 0)
...@@ -537,7 +539,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, ...@@ -537,7 +539,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
return ret; return ret;
BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
OUT_RING (chan, NvEvoSema0 + head); OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
OUT_RING (chan, sync->addr ^ 0x10); OUT_RING (chan, sync->addr ^ 0x10);
BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
OUT_RING (chan, sync->data + 1); OUT_RING (chan, sync->data + 1);
...@@ -546,7 +548,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, ...@@ -546,7 +548,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
OUT_RING (chan, sync->data); OUT_RING (chan, sync->data);
} else } else
if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) {
u64 addr = nv84_fence_crtc(chan, head) + sync->addr; u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
ret = RING_SPACE(chan, 12); ret = RING_SPACE(chan, 12);
if (ret) if (ret)
return ret; return ret;
...@@ -565,7 +567,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, ...@@ -565,7 +567,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL); OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
} else } else
if (chan) { if (chan) {
u64 addr = nv84_fence_crtc(chan, head) + sync->addr; u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
ret = RING_SPACE(chan, 10); ret = RING_SPACE(chan, 10);
if (ret) if (ret)
return ret; return ret;
...@@ -630,6 +632,8 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, ...@@ -630,6 +632,8 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
evo_mthd(push, 0x0080, 1); evo_mthd(push, 0x0080, 1);
evo_data(push, 0x00000000); evo_data(push, 0x00000000);
evo_kick(push, sync); evo_kick(push, sync);
nouveau_bo_ref(nv_fb->nvbo, &head->image);
return 0; return 0;
} }
...@@ -1038,18 +1042,17 @@ static int ...@@ -1038,18 +1042,17 @@ static int
nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
{ {
struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
struct nv50_head *head = nv50_head(crtc);
int ret; int ret;
ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
if (ret) if (ret == 0) {
return ret; if (head->image)
nouveau_bo_unpin(head->image);
if (old_fb) { nouveau_bo_ref(nvfb->nvbo, &head->image);
nvfb = nouveau_framebuffer(old_fb);
nouveau_bo_unpin(nvfb->nvbo);
} }
return 0; return ret;
} }
static int static int
...@@ -1198,6 +1201,15 @@ nv50_crtc_lut_load(struct drm_crtc *crtc) ...@@ -1198,6 +1201,15 @@ nv50_crtc_lut_load(struct drm_crtc *crtc)
} }
} }
static void
nv50_crtc_disable(struct drm_crtc *crtc)
{
struct nv50_head *head = nv50_head(crtc);
if (head->image)
nouveau_bo_unpin(head->image);
nouveau_bo_ref(NULL, &head->image);
}
static int static int
nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
uint32_t handle, uint32_t width, uint32_t height) uint32_t handle, uint32_t width, uint32_t height)
...@@ -1271,18 +1283,29 @@ nv50_crtc_destroy(struct drm_crtc *crtc) ...@@ -1271,18 +1283,29 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct nv50_disp *disp = nv50_disp(crtc->dev); struct nv50_disp *disp = nv50_disp(crtc->dev);
struct nv50_head *head = nv50_head(crtc); struct nv50_head *head = nv50_head(crtc);
nv50_dmac_destroy(disp->core, &head->ovly.base); nv50_dmac_destroy(disp->core, &head->ovly.base);
nv50_pioc_destroy(disp->core, &head->oimm.base); nv50_pioc_destroy(disp->core, &head->oimm.base);
nv50_dmac_destroy(disp->core, &head->sync.base); nv50_dmac_destroy(disp->core, &head->sync.base);
nv50_pioc_destroy(disp->core, &head->curs.base); nv50_pioc_destroy(disp->core, &head->curs.base);
/*XXX: this shouldn't be necessary, but the core doesn't call
* disconnect() during the cleanup paths
*/
if (head->image)
nouveau_bo_unpin(head->image);
nouveau_bo_ref(NULL, &head->image);
nouveau_bo_unmap(nv_crtc->cursor.nvbo); nouveau_bo_unmap(nv_crtc->cursor.nvbo);
if (nv_crtc->cursor.nvbo) if (nv_crtc->cursor.nvbo)
nouveau_bo_unpin(nv_crtc->cursor.nvbo); nouveau_bo_unpin(nv_crtc->cursor.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
nouveau_bo_unmap(nv_crtc->lut.nvbo); nouveau_bo_unmap(nv_crtc->lut.nvbo);
if (nv_crtc->lut.nvbo) if (nv_crtc->lut.nvbo)
nouveau_bo_unpin(nv_crtc->lut.nvbo); nouveau_bo_unpin(nv_crtc->lut.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
drm_crtc_cleanup(crtc); drm_crtc_cleanup(crtc);
kfree(crtc); kfree(crtc);
} }
...@@ -1296,6 +1319,7 @@ static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = { ...@@ -1296,6 +1319,7 @@ static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = {
.mode_set_base = nv50_crtc_mode_set_base, .mode_set_base = nv50_crtc_mode_set_base,
.mode_set_base_atomic = nv50_crtc_mode_set_base_atomic, .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
.load_lut = nv50_crtc_lut_load, .load_lut = nv50_crtc_lut_load,
.disable = nv50_crtc_disable,
}; };
static const struct drm_crtc_funcs nv50_crtc_func = { static const struct drm_crtc_funcs nv50_crtc_func = {
......
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