diff mbox

drm/nouveau/kms/nv50: Fix atomic pageflip events.

Message ID 1479884334-9995-1-git-send-email-mario.kleiner.de@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Mario Kleiner Nov. 23, 2016, 6:58 a.m. UTC
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>
---
 drivers/gpu/drm/nouveau/nv50_display.c | 2 ++
 1 file changed, 2 insertions(+)
diff mbox

Patch

diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index a9855a4..ad9aedb 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -4087,6 +4087,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);