History

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

Ville Syrjälä committed 12 years ago

Commit 8d7849d1 parent d9ceb954 files · +154 −6Browse files

Unified · Split

4 files
  1. drivers/gpu/drm/i915/i915_irq.c +19 −6
  2. drivers/gpu/drm/i915/intel_display.c +2 −0
  3. drivers/gpu/drm/i915/intel_drv.h +2 −0
  4. drivers/gpu/drm/i915/intel_sprite.c +131 −0
drivers/gpu/drm/i915/i915_irq.c+19−6
@@ -1556,6 +1556,19 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir) · 1555 unmodified lines
15561556 }
15571557 }
15581558
1559+static bool intel_pipe_handle_vblank(struct drm_device *dev, enum pipe pipe)
1560+{
1561+ struct intel_crtc *crtc;
1562+
1563+ if (!drm_handle_vblank(dev, pipe))
1564+ return false;
1565+
1566+ crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
1567+ wake_up(&crtc->vbl_wait);
1568+
1569+ return true;
1570+}
1571+
15591572 static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
15601573 {
15611574 struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1607,7 +1620,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) · 45 unmodified lines
16071620
16081621 for_each_pipe(pipe) {
16091622 if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
1610− drm_handle_vblank(dev, pipe);
1623+ intel_pipe_handle_vblank(dev, pipe);
16111624
16121625 if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
16131626 intel_prepare_page_flip(dev, pipe);
@@ -1850,7 +1863,7 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir) · 236 unmodified lines
18501863
18511864 for_each_pipe(pipe) {
18521865 if (de_iir & DE_PIPE_VBLANK(pipe))
1853− drm_handle_vblank(dev, pipe);
1866+ intel_pipe_handle_vblank(dev, pipe);
18541867
18551868 if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
18561869 if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
@@ -1900,7 +1913,7 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir) · 43 unmodified lines
19001913
19011914 for_each_pipe(pipe) {
19021915 if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
1903− drm_handle_vblank(dev, pipe);
1916+ intel_pipe_handle_vblank(dev, pipe);
19041917
19051918 /* plane/pipes map 1:1 on ilk+ */
19061919 if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
@@ -2043,7 +2056,7 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) · 136 unmodified lines
20432056
20442057 pipe_iir = I915_READ(GEN8_DE_PIPE_IIR(pipe));
20452058 if (pipe_iir & GEN8_PIPE_VBLANK)
2046− drm_handle_vblank(dev, pipe);
2059+ intel_pipe_handle_vblank(dev, pipe);
20472060
20482061 if (pipe_iir & GEN8_PIPE_PRIMARY_FLIP_DONE) {
20492062 intel_prepare_page_flip(dev, pipe);
@@ -3390,7 +3403,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev, · 1340 unmodified lines
33903403 struct drm_i915_private *dev_priv = dev->dev_private;
33913404 u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
33923405
3393− if (!drm_handle_vblank(dev, pipe))
3406+ if (!intel_pipe_handle_vblank(dev, pipe))
33943407 return false;
33953408
33963409 if ((iir & flip_pending) == 0)
@@ -3575,7 +3588,7 @@ static bool i915_handle_vblank(struct drm_device *dev, · 178 unmodified lines
35753588 struct drm_i915_private *dev_priv = dev->dev_private;
35763589 u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
35773590
3578− if (!drm_handle_vblank(dev, pipe))
3591+ if (!intel_pipe_handle_vblank(dev, pipe))
35793592 return false;
35803593
35813594 if ((iir & flip_pending) == 0)
drivers/gpu/drm/i915/intel_display.c+2−0
@@ -10566,6 +10566,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) · 10565 unmodified lines
1056610566 intel_crtc->plane = !pipe;
1056710567 }
1056810568
10569+ init_waitqueue_head(&intel_crtc->vbl_wait);
10570+
1056910571 BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
1057010572 dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL);
1057110573 dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
drivers/gpu/drm/i915/intel_drv.h+2−0
@@ -401,6 +401,8 @@ struct intel_crtc { · 400 unmodified lines
401401 /* watermarks currently being used */
402402 struct intel_pipe_wm active;
403403 } wm;
404+
405+ wait_queue_head_t vbl_wait;
404406 };
405407
406408 struct intel_plane_wm_parameters {
drivers/gpu/drm/i915/intel_sprite.c+131−0
@@ -37,6 +37,89 @@ · 36 unmodified lines
3737 #include <drm/i915_drm.h>
3838 #include "i915_drv.h"
3939
40+static 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+
49+static 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+
110+static 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+
40123 static void
41124 vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
42125 struct drm_framebuffer *fb,
@@ -48,11 +131,14 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, · 5 unmodified lines
48131 struct drm_device *dev = dplane->dev;
49132 struct drm_i915_private *dev_priv = dev->dev_private;
50133 struct intel_plane *intel_plane = to_intel_plane(dplane);
134+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
51135 int pipe = intel_plane->pipe;
52136 int plane = intel_plane->plane;
53137 u32 sprctl;
54138 unsigned long sprsurf_offset, linear_offset;
55139 int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
140+ u32 start_vbl_count;
141+ bool atomic_update;
56142
57143 sprctl = I915_READ(SPCNTR(pipe, plane));
58144
@@ -131,6 +217,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, · 72 unmodified lines
131217 fb->pitches[0]);
132218 linear_offset -= sprsurf_offset;
133219
220+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
221+
134222 I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
135223 I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
136224
@@ -144,6 +232,9 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, · 7 unmodified lines
144232 I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
145233 sprsurf_offset);
146234 POSTING_READ(SPSURF(pipe, plane));
235+
236+ if (atomic_update)
237+ intel_pipe_update_end(intel_crtc, start_vbl_count);
147238 }
148239
149240 static void
@@ -152,8 +243,13 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) · 2 unmodified lines
152243 struct drm_device *dev = dplane->dev;
153244 struct drm_i915_private *dev_priv = dev->dev_private;
154245 struct intel_plane *intel_plane = to_intel_plane(dplane);
246+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
155247 int pipe = intel_plane->pipe;
156248 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);
157253
158254 I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) &
159255 ~SP_ENABLE);
@@ -161,6 +257,9 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) · 1 unmodified line
161257 I915_WRITE(SPSURF(pipe, plane), 0);
162258 POSTING_READ(SPSURF(pipe, plane));
163259
260+ if (atomic_update)
261+ intel_pipe_update_end(intel_crtc, start_vbl_count);
262+
164263 intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false);
165264 }
166265
@@ -226,10 +325,13 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, · 59 unmodified lines
226325 struct drm_device *dev = plane->dev;
227326 struct drm_i915_private *dev_priv = dev->dev_private;
228327 struct intel_plane *intel_plane = to_intel_plane(plane);
328+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
229329 int pipe = intel_plane->pipe;
230330 u32 sprctl, sprscale = 0;
231331 unsigned long sprsurf_offset, linear_offset;
232332 int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
333+ u32 start_vbl_count;
334+ bool atomic_update;
233335
234336 sprctl = I915_READ(SPRCTL(pipe));
235337
@@ -299,6 +401,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, · 63 unmodified lines
299401 pixel_size, fb->pitches[0]);
300402 linear_offset -= sprsurf_offset;
301403
404+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
405+
302406 I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
303407 I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
304408
@@ -318,6 +422,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, · 13 unmodified lines
318422 I915_WRITE(SPRSURF(pipe),
319423 i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
320424 POSTING_READ(SPRSURF(pipe));
425+
426+ if (atomic_update)
427+ intel_pipe_update_end(intel_crtc, start_vbl_count);
321428 }
322429
323430 static void
@@ -326,7 +433,12 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) · 2 unmodified lines
326433 struct drm_device *dev = plane->dev;
327434 struct drm_i915_private *dev_priv = dev->dev_private;
328435 struct intel_plane *intel_plane = to_intel_plane(plane);
436+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
329437 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);
330442
331443 I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
332444 /* Can't leave the scaler enabled... */
@@ -336,6 +448,9 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) · 3 unmodified lines
336448 I915_WRITE(SPRSURF(pipe), 0);
337449 POSTING_READ(SPRSURF(pipe));
338450
451+ if (atomic_update)
452+ intel_pipe_update_end(intel_crtc, start_vbl_count);
453+
339454 /*
340455 * Avoid underruns when disabling the sprite.
341456 * FIXME remove once watermark updates are done properly.
@@ -410,10 +525,13 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, · 68 unmodified lines
410525 struct drm_device *dev = plane->dev;
411526 struct drm_i915_private *dev_priv = dev->dev_private;
412527 struct intel_plane *intel_plane = to_intel_plane(plane);
528+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
413529 int pipe = intel_plane->pipe;
414530 unsigned long dvssurf_offset, linear_offset;
415531 u32 dvscntr, dvsscale;
416532 int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
533+ u32 start_vbl_count;
534+ bool atomic_update;
417535
418536 dvscntr = I915_READ(DVSCNTR(pipe));
419537
@@ -478,6 +596,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, · 58 unmodified lines
478596 pixel_size, fb->pitches[0]);
479597 linear_offset -= dvssurf_offset;
480598
599+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
600+
481601 I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
482602 I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
483603
@@ -492,6 +612,9 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, · 8 unmodified lines
492612 I915_WRITE(DVSSURF(pipe),
493613 i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
494614 POSTING_READ(DVSSURF(pipe));
615+
616+ if (atomic_update)
617+ intel_pipe_update_end(intel_crtc, start_vbl_count);
495618 }
496619
497620 static void
@@ -500,7 +623,12 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) · 2 unmodified lines
500623 struct drm_device *dev = plane->dev;
501624 struct drm_i915_private *dev_priv = dev->dev_private;
502625 struct intel_plane *intel_plane = to_intel_plane(plane);
626+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
503627 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);
504632
505633 I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
506634 /* Disable the scaler */
@@ -509,6 +637,9 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) · 2 unmodified lines
509637 I915_WRITE(DVSSURF(pipe), 0);
510638 POSTING_READ(DVSSURF(pipe));
511639
640+ if (atomic_update)
641+ intel_pipe_update_end(intel_crtc, start_vbl_count);
642+
512643 /*
513644 * Avoid underruns when disabling the sprite.
514645 * FIXME remove once watermark updates are done properly.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t