aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_sprite.c
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2014-04-29 06:35:46 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2014-05-06 04:18:02 -0400
commit8d7849db3eab7f560deba145dfed3cd4df97c975 (patch)
tree8c953720cdf774cfff43d5b79c3994be444df8b7 /drivers/gpu/drm/i915/intel_sprite.c
parentd9ceb957fd97836c7fb0e403062e68ad2f737021 (diff)
drm/i915: Make sprite updates atomic
Add a mechanism by which we can evade the leading edge of vblank. This guarantees that no two sprite register writes will straddle on either side of the vblank start, and that means all the writes will be latched together in one atomic operation. We do the vblank evade by checking the scanline counter, and if it's too close to the start of vblank (too close has been hardcoded to 100usec for now), we will wait for the vblank start to pass. In order to eliminate random delayes from the rest of the system, we operate with interrupts disabled, except when waiting for the vblank obviously. Note that we now go digging through pipe_to_crtc_mapping[] in the vblank interrupt handler, which is a bit dangerous since we set up interrupts before the crtcs. However in this case since it's the vblank interrupt, we don't actually unmask it until some piece of code requests it. v2: preempt_check_resched() calls after local_irq_enable() (Jesse) Hook up the vblank irq stuff on BDW as well v3: Pass intel_crtc instead of drm_crtc (Daniel) Warn if crtc.mutex isn't locked (Daniel) Add an explicit compiler barrier and document the barriers (Daniel) Note the irq vs. modeset setup madness in the commit message (Daniel) v4: Use prepare_to_wait() & co. directly and eliminate vbl_received v5: Refactor intel_pipe_handle_vblank() vs. drm_handle_vblank() (Chris) Check for min/max scanline <= 0 (Chris) Don't call intel_pipe_update_end() if start failed totally (Chris) Check that the vblank counters match on both sides of the critical section (Chris) v6: Fix atomic update for interlaced modes v7: Reorder code for better readability (Chris) v8: Drop preempt_check_resched(). It's not available to modules anymore and isn't even needed unless we ourselves cause a wakeup needing reschedule while interrupts are off Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Reviewed-by: Sourab Gupta <sourabgupta@gmail.com> Reviewed-by: Akash Goel <akash.goels@gmail.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_sprite.c')
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 336ae6c602f2..a3ed840aadbe 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -37,6 +37,89 @@
37#include <drm/i915_drm.h> 37#include <drm/i915_drm.h>
38#include "i915_drv.h" 38#include "i915_drv.h"
39 39
40static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs)
41{
42 /* paranoia */
43 if (!mode->crtc_htotal)
44 return 1;
45
46 return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal);
47}
48
49static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
50{
51 struct drm_device *dev = crtc->base.dev;
52 const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
53 enum pipe pipe = crtc->pipe;
54 long timeout = msecs_to_jiffies_timeout(1);
55 int scanline, min, max, vblank_start;
56 DEFINE_WAIT(wait);
57
58 WARN_ON(!mutex_is_locked(&crtc->base.mutex));
59
60 vblank_start = mode->crtc_vblank_start;
61 if (mode->flags & DRM_MODE_FLAG_INTERLACE)
62 vblank_start = DIV_ROUND_UP(vblank_start, 2);
63
64 /* FIXME needs to be calibrated sensibly */
65 min = vblank_start - usecs_to_scanlines(mode, 100);
66 max = vblank_start - 1;
67
68 if (min <= 0 || max <= 0)
69 return false;
70
71 if (WARN_ON(drm_vblank_get(dev, pipe)))
72 return false;
73
74 local_irq_disable();
75
76 for (;;) {
77 /*
78 * prepare_to_wait() has a memory barrier, which guarantees
79 * other CPUs can see the task state update by the time we
80 * read the scanline.
81 */
82 prepare_to_wait(&crtc->vbl_wait, &wait, TASK_UNINTERRUPTIBLE);
83
84 scanline = intel_get_crtc_scanline(crtc);
85 if (scanline < min || scanline > max)
86 break;
87
88 if (timeout <= 0) {
89 DRM_ERROR("Potential atomic update failure on pipe %c\n",
90 pipe_name(crtc->pipe));
91 break;
92 }
93
94 local_irq_enable();
95
96 timeout = schedule_timeout(timeout);
97
98 local_irq_disable();
99 }
100
101 finish_wait(&crtc->vbl_wait, &wait);
102
103 drm_vblank_put(dev, pipe);
104
105 *start_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
106
107 return true;
108}
109
110static void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count)
111{
112 struct drm_device *dev = crtc->base.dev;
113 enum pipe pipe = crtc->pipe;
114 u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
115
116 local_irq_enable();
117
118 if (start_vbl_count != end_vbl_count)
119 DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u)\n",
120 pipe_name(pipe), start_vbl_count, end_vbl_count);
121}
122
40static void 123static void
41vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, 124vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
42 struct drm_framebuffer *fb, 125 struct drm_framebuffer *fb,
@@ -48,11 +131,14 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
48 struct drm_device *dev = dplane->dev; 131 struct drm_device *dev = dplane->dev;
49 struct drm_i915_private *dev_priv = dev->dev_private; 132 struct drm_i915_private *dev_priv = dev->dev_private;
50 struct intel_plane *intel_plane = to_intel_plane(dplane); 133 struct intel_plane *intel_plane = to_intel_plane(dplane);
134 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
51 int pipe = intel_plane->pipe; 135 int pipe = intel_plane->pipe;
52 int plane = intel_plane->plane; 136 int plane = intel_plane->plane;
53 u32 sprctl; 137 u32 sprctl;
54 unsigned long sprsurf_offset, linear_offset; 138 unsigned long sprsurf_offset, linear_offset;
55 int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 139 int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
140 u32 start_vbl_count;
141 bool atomic_update;
56 142
57 sprctl = I915_READ(SPCNTR(pipe, plane)); 143 sprctl = I915_READ(SPCNTR(pipe, plane));
58 144
@@ -131,6 +217,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
131 fb->pitches[0]); 217 fb->pitches[0]);
132 linear_offset -= sprsurf_offset; 218 linear_offset -= sprsurf_offset;
133 219
220 atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
221
134 I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]); 222 I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
135 I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x); 223 I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
136 224
@@ -144,6 +232,9 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
144 I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) + 232 I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
145 sprsurf_offset); 233 sprsurf_offset);
146 POSTING_READ(SPSURF(pipe, plane)); 234 POSTING_READ(SPSURF(pipe, plane));
235
236 if (atomic_update)
237 intel_pipe_update_end(intel_crtc, start_vbl_count);
147} 238}
148 239
149static void 240static void
@@ -152,8 +243,13 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
152 struct drm_device *dev = dplane->dev; 243 struct drm_device *dev = dplane->dev;
153 struct drm_i915_private *dev_priv = dev->dev_private; 244 struct drm_i915_private *dev_priv = dev->dev_private;
154 struct intel_plane *intel_plane = to_intel_plane(dplane); 245 struct intel_plane *intel_plane = to_intel_plane(dplane);
246 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
155 int pipe = intel_plane->pipe; 247 int pipe = intel_plane->pipe;
156 int plane = intel_plane->plane; 248 int plane = intel_plane->plane;
249 u32 start_vbl_count;
250 bool atomic_update;
251
252 atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
157 253
158 I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) & 254 I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) &
159 ~SP_ENABLE); 255 ~SP_ENABLE);
@@ -161,6 +257,9 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
161 I915_WRITE(SPSURF(pipe, plane), 0); 257 I915_WRITE(SPSURF(pipe, plane), 0);
162 POSTING_READ(SPSURF(pipe, plane)); 258 POSTING_READ(SPSURF(pipe, plane));
163 259
260 if (atomic_update)
261 intel_pipe_update_end(intel_crtc, start_vbl_count);
262
164 intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false); 263 intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false);
165} 264}
166 265
@@ -226,10 +325,13 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
226 struct drm_device *dev = plane->dev; 325 struct drm_device *dev = plane->dev;
227 struct drm_i915_private *dev_priv = dev->dev_private; 326 struct drm_i915_private *dev_priv = dev->dev_private;
228 struct intel_plane *intel_plane = to_intel_plane(plane); 327 struct intel_plane *intel_plane = to_intel_plane(plane);
328 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
229 int pipe = intel_plane->pipe; 329 int pipe = intel_plane->pipe;
230 u32 sprctl, sprscale = 0; 330 u32 sprctl, sprscale = 0;
231 unsigned long sprsurf_offset, linear_offset; 331 unsigned long sprsurf_offset, linear_offset;
232 int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 332 int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
333 u32 start_vbl_count;
334 bool atomic_update;
233 335
234 sprctl = I915_READ(SPRCTL(pipe)); 336 sprctl = I915_READ(SPRCTL(pipe));
235 337
@@ -299,6 +401,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
299 pixel_size, fb->pitches[0]); 401 pixel_size, fb->pitches[0]);
300 linear_offset -= sprsurf_offset; 402 linear_offset -= sprsurf_offset;
301 403
404 atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
405
302 I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]); 406 I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
303 I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x); 407 I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
304 408
@@ -318,6 +422,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
318 I915_WRITE(SPRSURF(pipe), 422 I915_WRITE(SPRSURF(pipe),
319 i915_gem_obj_ggtt_offset(obj) + sprsurf_offset); 423 i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
320 POSTING_READ(SPRSURF(pipe)); 424 POSTING_READ(SPRSURF(pipe));
425
426 if (atomic_update)
427 intel_pipe_update_end(intel_crtc, start_vbl_count);
321} 428}
322 429
323static void 430static void
@@ -326,7 +433,12 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
326 struct drm_device *dev = plane->dev; 433 struct drm_device *dev = plane->dev;
327 struct drm_i915_private *dev_priv = dev->dev_private; 434 struct drm_i915_private *dev_priv = dev->dev_private;
328 struct intel_plane *intel_plane = to_intel_plane(plane); 435 struct intel_plane *intel_plane = to_intel_plane(plane);
436 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
329 int pipe = intel_plane->pipe; 437 int pipe = intel_plane->pipe;
438 u32 start_vbl_count;
439 bool atomic_update;
440
441 atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
330 442
331 I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE); 443 I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
332 /* Can't leave the scaler enabled... */ 444 /* Can't leave the scaler enabled... */
@@ -336,6 +448,9 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
336 I915_WRITE(SPRSURF(pipe), 0); 448 I915_WRITE(SPRSURF(pipe), 0);
337 POSTING_READ(SPRSURF(pipe)); 449 POSTING_READ(SPRSURF(pipe));
338 450
451 if (atomic_update)
452 intel_pipe_update_end(intel_crtc, start_vbl_count);
453
339 /* 454 /*
340 * Avoid underruns when disabling the sprite. 455 * Avoid underruns when disabling the sprite.
341 * FIXME remove once watermark updates are done properly. 456 * FIXME remove once watermark updates are done properly.
@@ -410,10 +525,13 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
410 struct drm_device *dev = plane->dev; 525 struct drm_device *dev = plane->dev;
411 struct drm_i915_private *dev_priv = dev->dev_private; 526 struct drm_i915_private *dev_priv = dev->dev_private;
412 struct intel_plane *intel_plane = to_intel_plane(plane); 527 struct intel_plane *intel_plane = to_intel_plane(plane);
528 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
413 int pipe = intel_plane->pipe; 529 int pipe = intel_plane->pipe;
414 unsigned long dvssurf_offset, linear_offset; 530 unsigned long dvssurf_offset, linear_offset;
415 u32 dvscntr, dvsscale; 531 u32 dvscntr, dvsscale;
416 int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); 532 int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
533 u32 start_vbl_count;
534 bool atomic_update;
417 535
418 dvscntr = I915_READ(DVSCNTR(pipe)); 536 dvscntr = I915_READ(DVSCNTR(pipe));
419 537
@@ -478,6 +596,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
478 pixel_size, fb->pitches[0]); 596 pixel_size, fb->pitches[0]);
479 linear_offset -= dvssurf_offset; 597 linear_offset -= dvssurf_offset;
480 598
599 atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
600
481 I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]); 601 I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
482 I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x); 602 I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
483 603
@@ -492,6 +612,9 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
492 I915_WRITE(DVSSURF(pipe), 612 I915_WRITE(DVSSURF(pipe),
493 i915_gem_obj_ggtt_offset(obj) + dvssurf_offset); 613 i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
494 POSTING_READ(DVSSURF(pipe)); 614 POSTING_READ(DVSSURF(pipe));
615
616 if (atomic_update)
617 intel_pipe_update_end(intel_crtc, start_vbl_count);
495} 618}
496 619
497static void 620static void
@@ -500,7 +623,12 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
500 struct drm_device *dev = plane->dev; 623 struct drm_device *dev = plane->dev;
501 struct drm_i915_private *dev_priv = dev->dev_private; 624 struct drm_i915_private *dev_priv = dev->dev_private;
502 struct intel_plane *intel_plane = to_intel_plane(plane); 625 struct intel_plane *intel_plane = to_intel_plane(plane);
626 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
503 int pipe = intel_plane->pipe; 627 int pipe = intel_plane->pipe;
628 u32 start_vbl_count;
629 bool atomic_update;
630
631 atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
504 632
505 I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE); 633 I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
506 /* Disable the scaler */ 634 /* Disable the scaler */
@@ -509,6 +637,9 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
509 I915_WRITE(DVSSURF(pipe), 0); 637 I915_WRITE(DVSSURF(pipe), 0);
510 POSTING_READ(DVSSURF(pipe)); 638 POSTING_READ(DVSSURF(pipe));
511 639
640 if (atomic_update)
641 intel_pipe_update_end(intel_crtc, start_vbl_count);
642
512 /* 643 /*
513 * Avoid underruns when disabling the sprite. 644 * Avoid underruns when disabling the sprite.
514 * FIXME remove once watermark updates are done properly. 645 * FIXME remove once watermark updates are done properly.