diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-07-08 22:35:55 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-07-09 20:47:42 -0400 |
commit | 8dda53fca24789acf891ef31a3c5e03332b43cce (patch) | |
tree | 0f2cb2390a2a8e818e6de2410d403c0c837cb6b3 | |
parent | fdfb8332651db7a280851dfccfc4f0cff4bcd052 (diff) |
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: 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/nv50_display.c | 46 |
1 files changed, 35 insertions, 11 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 54dc6355b0c2..8b40a36c1b57 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c | |||
@@ -355,6 +355,7 @@ struct nv50_oimm { | |||
355 | 355 | ||
356 | struct nv50_head { | 356 | struct nv50_head { |
357 | struct nouveau_crtc base; | 357 | struct nouveau_crtc base; |
358 | struct nouveau_bo *image; | ||
358 | struct nv50_curs curs; | 359 | struct nv50_curs curs; |
359 | struct nv50_sync sync; | 360 | struct nv50_sync sync; |
360 | struct nv50_ovly ovly; | 361 | struct nv50_ovly ovly; |
@@ -517,9 +518,10 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
517 | { | 518 | { |
518 | struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); | 519 | struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); |
519 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | 520 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
521 | struct nv50_head *head = nv50_head(crtc); | ||
520 | struct nv50_sync *sync = nv50_sync(crtc); | 522 | struct nv50_sync *sync = nv50_sync(crtc); |
521 | int head = nv_crtc->index, ret; | ||
522 | u32 *push; | 523 | u32 *push; |
524 | int ret; | ||
523 | 525 | ||
524 | swap_interval <<= 4; | 526 | swap_interval <<= 4; |
525 | if (swap_interval == 0) | 527 | if (swap_interval == 0) |
@@ -537,7 +539,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
537 | return ret; | 539 | return ret; |
538 | 540 | ||
539 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); | 541 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); |
540 | OUT_RING (chan, NvEvoSema0 + head); | 542 | OUT_RING (chan, NvEvoSema0 + nv_crtc->index); |
541 | OUT_RING (chan, sync->addr ^ 0x10); | 543 | OUT_RING (chan, sync->addr ^ 0x10); |
542 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); | 544 | BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); |
543 | OUT_RING (chan, sync->data + 1); | 545 | OUT_RING (chan, sync->data + 1); |
@@ -546,7 +548,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
546 | OUT_RING (chan, sync->data); | 548 | OUT_RING (chan, sync->data); |
547 | } else | 549 | } else |
548 | if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { | 550 | if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { |
549 | u64 addr = nv84_fence_crtc(chan, head) + sync->addr; | 551 | u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr; |
550 | ret = RING_SPACE(chan, 12); | 552 | ret = RING_SPACE(chan, 12); |
551 | if (ret) | 553 | if (ret) |
552 | return ret; | 554 | return ret; |
@@ -565,7 +567,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
565 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL); | 567 | OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL); |
566 | } else | 568 | } else |
567 | if (chan) { | 569 | if (chan) { |
568 | u64 addr = nv84_fence_crtc(chan, head) + sync->addr; | 570 | u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr; |
569 | ret = RING_SPACE(chan, 10); | 571 | ret = RING_SPACE(chan, 10); |
570 | if (ret) | 572 | if (ret) |
571 | return ret; | 573 | return ret; |
@@ -630,6 +632,8 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, | |||
630 | evo_mthd(push, 0x0080, 1); | 632 | evo_mthd(push, 0x0080, 1); |
631 | evo_data(push, 0x00000000); | 633 | evo_data(push, 0x00000000); |
632 | evo_kick(push, sync); | 634 | evo_kick(push, sync); |
635 | |||
636 | nouveau_bo_ref(nv_fb->nvbo, &head->image); | ||
633 | return 0; | 637 | return 0; |
634 | } | 638 | } |
635 | 639 | ||
@@ -1038,18 +1042,17 @@ static int | |||
1038 | nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) | 1042 | nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) |
1039 | { | 1043 | { |
1040 | struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); | 1044 | struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); |
1045 | struct nv50_head *head = nv50_head(crtc); | ||
1041 | int ret; | 1046 | int ret; |
1042 | 1047 | ||
1043 | ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); | 1048 | ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); |
1044 | if (ret) | 1049 | if (ret == 0) { |
1045 | return ret; | 1050 | if (head->image) |
1046 | 1051 | nouveau_bo_unpin(head->image); | |
1047 | if (old_fb) { | 1052 | nouveau_bo_ref(nvfb->nvbo, &head->image); |
1048 | nvfb = nouveau_framebuffer(old_fb); | ||
1049 | nouveau_bo_unpin(nvfb->nvbo); | ||
1050 | } | 1053 | } |
1051 | 1054 | ||
1052 | return 0; | 1055 | return ret; |
1053 | } | 1056 | } |
1054 | 1057 | ||
1055 | static int | 1058 | static int |
@@ -1198,6 +1201,15 @@ nv50_crtc_lut_load(struct drm_crtc *crtc) | |||
1198 | } | 1201 | } |
1199 | } | 1202 | } |
1200 | 1203 | ||
1204 | static void | ||
1205 | nv50_crtc_disable(struct drm_crtc *crtc) | ||
1206 | { | ||
1207 | struct nv50_head *head = nv50_head(crtc); | ||
1208 | if (head->image) | ||
1209 | nouveau_bo_unpin(head->image); | ||
1210 | nouveau_bo_ref(NULL, &head->image); | ||
1211 | } | ||
1212 | |||
1201 | static int | 1213 | static int |
1202 | nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, | 1214 | nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, |
1203 | uint32_t handle, uint32_t width, uint32_t height) | 1215 | uint32_t handle, uint32_t width, uint32_t height) |
@@ -1271,18 +1283,29 @@ nv50_crtc_destroy(struct drm_crtc *crtc) | |||
1271 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); | 1283 | struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); |
1272 | struct nv50_disp *disp = nv50_disp(crtc->dev); | 1284 | struct nv50_disp *disp = nv50_disp(crtc->dev); |
1273 | struct nv50_head *head = nv50_head(crtc); | 1285 | struct nv50_head *head = nv50_head(crtc); |
1286 | |||
1274 | nv50_dmac_destroy(disp->core, &head->ovly.base); | 1287 | nv50_dmac_destroy(disp->core, &head->ovly.base); |
1275 | nv50_pioc_destroy(disp->core, &head->oimm.base); | 1288 | nv50_pioc_destroy(disp->core, &head->oimm.base); |
1276 | nv50_dmac_destroy(disp->core, &head->sync.base); | 1289 | nv50_dmac_destroy(disp->core, &head->sync.base); |
1277 | nv50_pioc_destroy(disp->core, &head->curs.base); | 1290 | nv50_pioc_destroy(disp->core, &head->curs.base); |
1291 | |||
1292 | /*XXX: this shouldn't be necessary, but the core doesn't call | ||
1293 | * disconnect() during the cleanup paths | ||
1294 | */ | ||
1295 | if (head->image) | ||
1296 | nouveau_bo_unpin(head->image); | ||
1297 | nouveau_bo_ref(NULL, &head->image); | ||
1298 | |||
1278 | nouveau_bo_unmap(nv_crtc->cursor.nvbo); | 1299 | nouveau_bo_unmap(nv_crtc->cursor.nvbo); |
1279 | if (nv_crtc->cursor.nvbo) | 1300 | if (nv_crtc->cursor.nvbo) |
1280 | nouveau_bo_unpin(nv_crtc->cursor.nvbo); | 1301 | nouveau_bo_unpin(nv_crtc->cursor.nvbo); |
1281 | nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); | 1302 | nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); |
1303 | |||
1282 | nouveau_bo_unmap(nv_crtc->lut.nvbo); | 1304 | nouveau_bo_unmap(nv_crtc->lut.nvbo); |
1283 | if (nv_crtc->lut.nvbo) | 1305 | if (nv_crtc->lut.nvbo) |
1284 | nouveau_bo_unpin(nv_crtc->lut.nvbo); | 1306 | nouveau_bo_unpin(nv_crtc->lut.nvbo); |
1285 | nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); | 1307 | nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); |
1308 | |||
1286 | drm_crtc_cleanup(crtc); | 1309 | drm_crtc_cleanup(crtc); |
1287 | kfree(crtc); | 1310 | kfree(crtc); |
1288 | } | 1311 | } |
@@ -1296,6 +1319,7 @@ static const struct drm_crtc_helper_funcs nv50_crtc_hfunc = { | |||
1296 | .mode_set_base = nv50_crtc_mode_set_base, | 1319 | .mode_set_base = nv50_crtc_mode_set_base, |
1297 | .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic, | 1320 | .mode_set_base_atomic = nv50_crtc_mode_set_base_atomic, |
1298 | .load_lut = nv50_crtc_lut_load, | 1321 | .load_lut = nv50_crtc_lut_load, |
1322 | .disable = nv50_crtc_disable, | ||
1299 | }; | 1323 | }; |
1300 | 1324 | ||
1301 | static const struct drm_crtc_funcs nv50_crtc_func = { | 1325 | static const struct drm_crtc_funcs nv50_crtc_func = { |