On Mon, Aug 22, 2016 at 05:56:24PM +0100, Chris Wilson wrote: > When we check whether we are in the danger region before a vblank at the > start of a pipe update, the irq must be enabled. This is so that as > decide whether or not to sleep there is no race between us and the irq > delivery - i.e. we want to immediately wake up if the irq arrives > before we try to sleep. Whilst here also remove the DRM_ERROR() for > hitting a jiffie count of 0 as that also has a race against the timer > irq - instead replace it with a simple check if the sleep was for more > than a jiffie (at high resolution >1ms, at low resolution >10ms) as we > know we only try to wait for the irq within 100us of the vblank. > > We replace the early irq_disable for the pipe update critical section > with a preempt disable to hog the cpu, disabling irq later when we > go to program the pipe and queue the following vblank event. > > Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/i915/intel_sprite.c | 47 ++++++++++++++++++------------------- > 1 file changed, 23 insertions(+), 24 deletions(-) > > diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c > index 11f3b38229dd..a6a51f16ae0b 100644 > --- a/drivers/gpu/drm/i915/intel_sprite.c > +++ b/drivers/gpu/drm/i915/intel_sprite.c > @@ -82,10 +82,9 @@ int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode, > void intel_pipe_update_start(struct intel_crtc *crtc) > { > const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode; > - long timeout = msecs_to_jiffies_timeout(1); > int scanline, min, max, vblank_start; > - wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); > - DEFINE_WAIT(wait); > + > + preempt_disable(); > > vblank_start = adjusted_mode->crtc_vblank_start; > if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) > @@ -95,19 +94,21 @@ void intel_pipe_update_start(struct intel_crtc *crtc) > min = vblank_start - intel_usecs_to_scanlines(adjusted_mode, 100); > max = vblank_start - 1; > > - local_irq_disable(); > + crtc->debug.min_vbl = min; > + crtc->debug.max_vbl = max; > + > + trace_i915_pipe_update_start(crtc); > > if (min <= 0 || max <= 0) > - return; > + goto out; > > if (WARN_ON(drm_crtc_vblank_get(&crtc->base))) > - return; > + goto out; > > - crtc->debug.min_vbl = min; > - crtc->debug.max_vbl = max; > - trace_i915_pipe_update_start(crtc); > + do { > + wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base); > + DEFINE_WAIT(wait); > > - for (;;) { > /* > * prepare_to_wait() has a memory barrier, which guarantees > * other CPUs can see the task state update by the time we > @@ -119,26 +120,22 @@ void intel_pipe_update_start(struct intel_crtc *crtc) > if (scanline < min || scanline > max) > break; Hmm, prepare_to_wait() itself has a might_sleep() check, preventing the preempt fun. The challenge is that we do not want to be interrupted once we decide to apply the update (reading the scanline) - but that read has to be after prepare_to_wait to prevent any races before sleeping. -Chris -- Chris Wilson, Intel Open Source Technology Centre _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx