aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2016-12-21 05:23:30 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-30 03:41:28 -0400
commitc75fe7899538890109aad7bbf92b2f304389e825 (patch)
treeebc294add9fd8504372981f420ddb1ebe9903852 /drivers/gpu
parent56769e7a05268de991ef24e77383d44c56ad9141 (diff)
drm: reference count event->completion
commit 24835e442f289813aa568d142a755672a740503c upstream. When writing the generic nonblocking commit code I assumed that through clever lifetime management I can assure that the completion (stored in drm_crtc_commit) only gets freed after it is completed. And that worked. I also wanted to make nonblocking helpers resilient against driver bugs, by having timeouts everywhere. And that worked too. Unfortunately taking boths things together results in oopses :( Well, at least sometimes: What seems to happen is that the drm event hangs around forever stuck in limbo land. The nonblocking helpers eventually time out, move on and release it. Now the bug I tested all this against is drivers that just entirely fail to deliver the vblank events like they should, and in those cases the event is simply leaked. But what seems to happen, at least sometimes, on i915 is that the event is set up correctly, but somohow the vblank fails to fire in time. Which means the event isn't leaked, it's still there waiting for eventually a vblank to fire. That tends to happen when re-enabling the pipe, and then the trap springs and the kernel oopses. The correct fix here is simply to refcount the crtc commit to make sure that the event sticks around even for drivers which only sometimes fail to deliver vblanks for some arbitrary reasons. Since crtc commits are already refcounted that's easy to do. References: https://bugs.freedesktop.org/show_bug.cgi?id=96781 Cc: Jim Rees <rees@umich.edu> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/20161221102331.31033-1-daniel.vetter@ffwll.ch Cc: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c11
-rw-r--r--drivers/gpu/drm/drm_fops.c2
2 files changed, 12 insertions, 1 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 2e42a0584a84..50acd799babe 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1382,6 +1382,15 @@ static int stall_checks(struct drm_crtc *crtc, bool nonblock)
1382 return ret < 0 ? ret : 0; 1382 return ret < 0 ? ret : 0;
1383} 1383}
1384 1384
1385void release_crtc_commit(struct completion *completion)
1386{
1387 struct drm_crtc_commit *commit = container_of(completion,
1388 typeof(*commit),
1389 flip_done);
1390
1391 drm_crtc_commit_put(commit);
1392}
1393
1385/** 1394/**
1386 * drm_atomic_helper_setup_commit - setup possibly nonblocking commit 1395 * drm_atomic_helper_setup_commit - setup possibly nonblocking commit
1387 * @state: new modeset state to be committed 1396 * @state: new modeset state to be committed
@@ -1474,6 +1483,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
1474 } 1483 }
1475 1484
1476 crtc_state->event->base.completion = &commit->flip_done; 1485 crtc_state->event->base.completion = &commit->flip_done;
1486 crtc_state->event->base.completion_release = release_crtc_commit;
1487 drm_crtc_commit_get(commit);
1477 } 1488 }
1478 1489
1479 return 0; 1490 return 0;
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index e84faecf5225..f5815e1a4390 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -686,8 +686,8 @@ void drm_send_event_locked(struct drm_device *dev, struct drm_pending_event *e)
686 assert_spin_locked(&dev->event_lock); 686 assert_spin_locked(&dev->event_lock);
687 687
688 if (e->completion) { 688 if (e->completion) {
689 /* ->completion might disappear as soon as it signalled. */
690 complete_all(e->completion); 689 complete_all(e->completion);
690 e->completion_release(e->completion);
691 e->completion = NULL; 691 e->completion = NULL;
692 } 692 }
693 693