aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_debugfs.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-12-03 06:36:30 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-12-06 08:09:37 -0500
commite7d841ca03b7ab668620045cd7b428eda9f41601 (patch)
tree513a8adda0a306e3e8c4b10d27f31992ed28f6b6 /drivers/gpu/drm/i915/i915_debugfs.c
parentebf69cb8331d7336e4bcd442a2ca69bb61739a58 (diff)
drm/i915: Close race between processing unpin task and queueing the flip
Before queuing the flip but crucially after attaching the unpin-work to the crtc, we continue to setup the unpin-work. However, should the hardware fire early, we see the connected unpin-work and queue the task. The task then promptly runs and unpins the fb before we finish taking the required references or even pinning it... Havoc. To close the race, we use the flip-pending atomic to indicate when the flip is finally setup and enqueued. So during the flip-done processing, we can check more accurately whether the flip was expected. v2: Add the appropriate mb() to ensure that the writes to the page-flip worker are complete prior to marking it active and emitting the MI_FLIP. On the read side, the mb should be enforced by the spinlocks. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@vger.kernel.org [danvet: Review the barriers a bit, we need a write barrier both before and after updating ->pending. Similarly we need a read barrier in the interrupt handler both before and after reading ->pending. With well-ordered irqs only one barrier in each place should be required, but since this patch explicitly sets out to combat spurious interrupts with is staged activation of the unpin work we need to go full-bore on the barriers, too. Discussed with Chris Wilson on irc and changes acked by him.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/i915_debugfs.c')
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 8afc0dd7de64..e6a11ca85eaf 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -317,7 +317,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
317 seq_printf(m, "No flip due on pipe %c (plane %c)\n", 317 seq_printf(m, "No flip due on pipe %c (plane %c)\n",
318 pipe, plane); 318 pipe, plane);
319 } else { 319 } else {
320 if (!work->pending) { 320 if (atomic_read(&work->pending) < INTEL_FLIP_COMPLETE) {
321 seq_printf(m, "Flip queued on pipe %c (plane %c)\n", 321 seq_printf(m, "Flip queued on pipe %c (plane %c)\n",
322 pipe, plane); 322 pipe, plane);
323 } else { 323 } else {
@@ -328,7 +328,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
328 seq_printf(m, "Stall check enabled, "); 328 seq_printf(m, "Stall check enabled, ");
329 else 329 else
330 seq_printf(m, "Stall check waiting for page flip ioctl, "); 330 seq_printf(m, "Stall check waiting for page flip ioctl, ");
331 seq_printf(m, "%d prepares\n", work->pending); 331 seq_printf(m, "%d prepares\n", atomic_read(&work->pending));
332 332
333 if (work->old_fb_obj) { 333 if (work->old_fb_obj) {
334 struct drm_i915_gem_object *obj = work->old_fb_obj; 334 struct drm_i915_gem_object *obj = work->old_fb_obj;