summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner.de@gmail.com>2016-11-23 07:58:54 +0100
committerBen Skeggs <bskeggs@redhat.com>2016-11-28 15:38:57 +1000
commit70eab5a3e261f7b28da84199a94aa599159279f6 (patch)
tree7c9616cf50786aca09e91c9b0d4749664579981f
parent4e49f8011f1c97e4db04427b0c559eee5e97da67 (diff)
downloadnouveau-70eab5a3e261f7b28da84199a94aa599159279f6.tar.gz
kms/nv50: Fix atomic pageflip events.
The new atomic modesetting/pageflip code for nv50+ for Linux 4.10+ no longer uses pageflip irq's to signal flip completion. Instead it polls for flip completion from within a kthread/work queue. This creates a race between the vblank irq handler updating the vblank count and timestamp for the vblank of flip completion, and the kthread's polling code detecting flip completion and sending out the flip completion event. Depending on who executes a few microseconds earlier, the flip completion event will either contain correct count/timestamp or a stale count/timestamp from the previous vblank. This error was observed for about 50% of all executed flips, e.g., observable under DRI2 by the Xorg.log filling with flip handler warning messages. Call drm_accurate_vblank_count() before sending out flip completion events to enforce a vblank count/ts update for the vblank of flip completion and avoid stale counts/timestamps. This fix leads to one redundant call to drm_update_vblank_count for each completed flip, but no other side effects. On a ~6 year old Core i7 M620@ 2.67GHz the redundant call costs about 10 usecs per flip Successfully tested on GeForce 9500/9600/330M so far. Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com> Cc: Ben Skeggs <bskeggs@redhat.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drm/nouveau/nv50_display.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drm/nouveau/nv50_display.c b/drm/nouveau/nv50_display.c
index 22a8b70a4..7a1aa9161 100644
--- a/drm/nouveau/nv50_display.c
+++ b/drm/nouveau/nv50_display.c
@@ -4090,6 +4090,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
for_each_crtc_in_state(state, crtc, crtc_state, i) {
if (crtc->state->event) {
unsigned long flags;
+ /* Get correct count/ts if racing with vblank irq */
+ drm_accurate_vblank_count(crtc);
spin_lock_irqsave(&crtc->dev->event_lock, flags);
drm_crtc_send_vblank_event(crtc, crtc->state->event);
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);