drm/i915: make CRTC enable/disable asynchronous This lets us return to userspace more quickly and should improve init and suspend/resume times as well, allowing us to return to userspace sooner. Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 89f0ea0..ecdc455 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -487,7 +487,7 @@ */ mutex_lock(&dev->mode_config.mutex); for_each_crtc(dev, crtc) - dev_priv->display.crtc_disable(crtc); + dev_priv->display._crtc_disable(crtc); mutex_unlock(&dev->mode_config.mutex); intel_modeset_suspend_hw(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index a7cd288..b0724b9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -456,8 +456,8 @@ int (*crtc_mode_set)(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb); - void (*crtc_enable)(struct drm_crtc *crtc); - void (*crtc_disable)(struct drm_crtc *crtc); + void (*_crtc_enable)(struct drm_crtc *crtc); + void (*_crtc_disable)(struct drm_crtc *crtc); void (*off)(struct drm_crtc *crtc); void (*write_eld)(struct drm_connector *connector, struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0f8f9bc..a83de89 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1935,6 +1935,65 @@ I915_WRITE(_TRANSA_CHICKEN2, val); } +static void intel_sync_crtc(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_device *dev = crtc->dev; + + WARN(1, "sync'ing crtc state\n"); + + WARN(!mutex_is_locked(&intel_crtc->base.mutex), "need crtc mutex\n"); + + mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&intel_crtc->base.mutex); + flush_work(&intel_crtc->disable_work); + flush_work(&intel_crtc->enable_work); + mutex_lock(&intel_crtc->base.mutex); + mutex_lock(&dev->mode_config.mutex); +} + +static void intel_crtc_disable_work(struct work_struct *work) +{ + struct intel_crtc *intel_crtc = container_of(work, struct intel_crtc, + disable_work); + struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; + struct drm_device *dev = dev_priv->dev; + + mutex_lock(&dev->mode_config.mutex); + mutex_lock(&intel_crtc->base.mutex); + dev_priv->display._crtc_disable(&intel_crtc->base); + mutex_unlock(&intel_crtc->base.mutex); + mutex_unlock(&dev->mode_config.mutex); +} + +void intel_queue_crtc_disable(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + schedule_work(&intel_crtc->disable_work); +} + +static void intel_crtc_enable_work(struct work_struct *work) +{ + struct intel_crtc *intel_crtc = container_of(work, struct intel_crtc, + enable_work); + struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private; + struct drm_device *dev = dev_priv->dev; + + mutex_lock(&dev->mode_config.mutex); + mutex_lock(&intel_crtc->base.mutex); + dev_priv->display._crtc_enable(&intel_crtc->base); + mutex_unlock(&intel_crtc->base.mutex); + mutex_unlock(&dev->mode_config.mutex); +} + +static void intel_queue_crtc_enable(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + schedule_work(&intel_crtc->enable_work); +} + /** * intel_enable_pipe - enable a pipe, asserting requirements * @crtc: crtc responsible for the pipe @@ -4678,7 +4737,6 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; bool enable = false; @@ -4686,9 +4744,9 @@ enable |= intel_encoder->connectors_active; if (enable) - dev_priv->display.crtc_enable(crtc); + intel_queue_crtc_enable(crtc); else - dev_priv->display.crtc_disable(crtc); + intel_queue_crtc_disable(crtc); intel_crtc_update_sarea(crtc, enable); } @@ -4703,7 +4761,7 @@ /* crtc should still be enabled when we disable it. */ WARN_ON(!crtc->enabled); - dev_priv->display.crtc_disable(crtc); + dev_priv->display._crtc_disable(crtc); intel_crtc->eld_vld = false; intel_crtc_update_sarea(crtc, false); dev_priv->display.off(crtc); @@ -8028,6 +8086,8 @@ goto fail; } + intel_sync_crtc(crtc); + /* we only need to pin inside GTT if cursor is non-phy */ mutex_lock(&dev->struct_mutex); if (!INTEL_INFO(dev)->cursor_needs_physical) { @@ -8118,6 +8178,8 @@ intel_crtc->cursor_x = clamp_t(int, x, SHRT_MIN, SHRT_MAX); intel_crtc->cursor_y = clamp_t(int, y, SHRT_MIN, SHRT_MAX); + intel_sync_crtc(crtc); + if (intel_crtc->active) intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL); @@ -9190,6 +9252,8 @@ if (work == NULL) return -ENOMEM; + intel_sync_crtc(crtc); + work->event = event; work->crtc = crtc; work->old_fb_obj = to_intel_framebuffer(old_fb)->obj; @@ -10221,8 +10285,10 @@ intel_crtc_disable(&intel_crtc->base); for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) { - if (intel_crtc->base.enabled) - dev_priv->display.crtc_disable(&intel_crtc->base); + if (intel_crtc->base.enabled) { + intel_queue_crtc_disable(&intel_crtc->base); + intel_sync_crtc(&intel_crtc->base); + } } /* crtc->mode is already used by the ->mode_set callbacks, hence we need @@ -10263,7 +10329,7 @@ /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc) - dev_priv->display.crtc_enable(&intel_crtc->base); + intel_queue_crtc_enable(&intel_crtc->base); /* FIXME: add subpixel order */ done: @@ -10284,8 +10350,9 @@ ret = __intel_set_mode(crtc, mode, x, y, fb); - if (ret == 0) - intel_modeset_check_state(crtc->dev); + /* FIXME: check after async crtc enable/disable */ +// if (ret == 0) +// intel_modeset_check_state(crtc->dev); return ret; } @@ -10851,6 +10918,9 @@ dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base; drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); + + INIT_WORK(&intel_crtc->enable_work, intel_crtc_enable_work); + INIT_WORK(&intel_crtc->disable_work, intel_crtc_disable_work); } enum pipe intel_get_pipe_from_connector(struct intel_connector *connector) @@ -11259,8 +11329,8 @@ dev_priv->display.get_pipe_config = haswell_get_pipe_config; dev_priv->display.get_plane_config = ironlake_get_plane_config; dev_priv->display.crtc_mode_set = haswell_crtc_mode_set; - dev_priv->display.crtc_enable = haswell_crtc_enable; - dev_priv->display.crtc_disable = haswell_crtc_disable; + dev_priv->display._crtc_enable = haswell_crtc_enable; + dev_priv->display._crtc_disable = haswell_crtc_disable; dev_priv->display.off = haswell_crtc_off; dev_priv->display.update_primary_plane = ironlake_update_primary_plane; @@ -11268,8 +11338,8 @@ dev_priv->display.get_pipe_config = ironlake_get_pipe_config; dev_priv->display.get_plane_config = ironlake_get_plane_config; dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set; - dev_priv->display.crtc_enable = ironlake_crtc_enable; - dev_priv->display.crtc_disable = ironlake_crtc_disable; + dev_priv->display._crtc_enable = ironlake_crtc_enable; + dev_priv->display._crtc_disable = ironlake_crtc_disable; dev_priv->display.off = ironlake_crtc_off; dev_priv->display.update_primary_plane = ironlake_update_primary_plane; @@ -11277,8 +11347,8 @@ dev_priv->display.get_pipe_config = i9xx_get_pipe_config; dev_priv->display.get_plane_config = i9xx_get_plane_config; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; - dev_priv->display.crtc_enable = valleyview_crtc_enable; - dev_priv->display.crtc_disable = i9xx_crtc_disable; + dev_priv->display._crtc_enable = valleyview_crtc_enable; + dev_priv->display._crtc_disable = i9xx_crtc_disable; dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = i9xx_update_primary_plane; @@ -11286,8 +11356,8 @@ dev_priv->display.get_pipe_config = i9xx_get_pipe_config; dev_priv->display.get_plane_config = i9xx_get_plane_config; dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set; - dev_priv->display.crtc_enable = i9xx_crtc_enable; - dev_priv->display.crtc_disable = i9xx_crtc_disable; + dev_priv->display._crtc_enable = i9xx_crtc_enable; + dev_priv->display._crtc_disable = i9xx_crtc_disable; dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = i9xx_update_primary_plane; @@ -11716,7 +11786,7 @@ * ... */ plane = crtc->plane; crtc->plane = !plane; - dev_priv->display.crtc_disable(&crtc->base); + intel_queue_crtc_disable(&crtc->base); crtc->plane = plane; /* ... and break all links. */ @@ -12028,7 +12098,7 @@ intel_modeset_update_staged_output_state(dev); } - intel_modeset_check_state(dev); +// intel_modeset_check_state(dev); } void intel_modeset_gem_init(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 32a74e1..70067c4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -403,6 +403,8 @@ } wm; wait_queue_head_t vbl_wait; + struct work_struct enable_work; + struct work_struct disable_work; }; struct intel_plane_wm_parameters { @@ -792,6 +794,7 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_config *pipe_config); int intel_format_to_fourcc(int format); +void intel_queue_crtc_disable(struct drm_crtc *crtc); /* intel_dp.c */ void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);