From 32b7eeec4d1e861230b09d437e95d76c86ff4a68 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Wed, 24 Dec 2014 07:59:06 -0800 Subject: drm/i915: Refactor work that can sleep out of commit (v7) Once we integrate our work into the atomic pipeline, plane commit operations will need to happen with interrupts disabled, due to vblank evasion. Our commit functions today include sleepable work, so those operations need to be split out and run either before or after the atomic register programming. The solution here calculates which of those operations will need to be performed during the 'check' phase and sets flags in an intel_crtc sub-struct. New intel_begin_crtc_commit() and intel_finish_crtc_commit() functions are added before and after the actual register programming; these will eventually be called from the atomic plane helper's .atomic_begin() and .atomic_end() entrypoints. v2: Fix broken sprite code split v3: Make the pre/post commit work crtc-based to match how we eventually want this to be called from the atomic plane helpers. v4: Some platforms that haven't had their watermark code reworked were waiting for vblank, then calling update_sprite_watermarks in their platform-specific disable code. These also need to be flagged out of the critical section. v5: Sprite plane test for primary show/hide should just set the flag to wait for pending flips, not actually perform the wait. (Ander) v6: - Rebase onto latest di-nightly; picks up an important runtime PM fix. - Handle 'wait_for_flips' flag in intel_begin_crtc_commit(). (Ander) - Use wait_for_flips flag for primary plane update rather than performing the wait in the check routine. - Added kerneldoc to pre_disable/post_enable functions that are no longer static. (Ander) - Replace assert_pipe_enabled() in intel_disable_primary_hw_plane() with an intel_crtc->active test; it turns out assert_pipe_enabled() grabs some mutexes and can sleep, which we can't do with interrupts disabled. v7: - Check for fb != NULL when deciding whether the sprite plane hides the primary plane during a sprite update. (PRTS) Signed-off-by: Matt Roper Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 199 ++++++++++++++++++++++------------- 1 file changed, 127 insertions(+), 72 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_display.c') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a340f51c790a..260b91c4cbbf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2165,7 +2165,8 @@ static void intel_disable_primary_hw_plane(struct drm_plane *plane, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - assert_pipe_enabled(dev_priv, intel_crtc->pipe); + if (WARN_ON(!intel_crtc->active)) + return; if (!intel_crtc->primary_enabled) return; @@ -11737,7 +11738,11 @@ static int intel_check_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) { + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = state->base.crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_framebuffer *fb = state->base.fb; struct drm_rect *dest = &state->dst; struct drm_rect *src = &state->src; @@ -11752,10 +11757,40 @@ intel_check_primary_plane(struct drm_plane *plane, if (ret) return ret; - intel_crtc_wait_for_pending_flips(crtc); - if (intel_crtc_has_pending_flip(crtc)) { - DRM_ERROR("pipe is still busy with an old pageflip\n"); - return -EBUSY; + if (intel_crtc->active) { + intel_crtc->atomic.wait_for_flips = true; + + /* + * FBC does not work on some platforms for rotated + * planes, so disable it when rotation is not 0 and + * update it when rotation is set back to 0. + * + * FIXME: This is redundant with the fbc update done in + * the primary plane enable function except that that + * one is done too late. We eventually need to unify + * this. + */ + if (intel_crtc->primary_enabled && + INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && + dev_priv->fbc.plane == intel_crtc->plane && + intel_plane->rotation != BIT(DRM_ROTATE_0)) { + intel_crtc->atomic.disable_fbc = true; + } + + if (state->visible) { + /* + * BDW signals flip done immediately if the plane + * is disabled, even if the plane enable is already + * armed to occur at the next vblank :( + */ + if (IS_BROADWELL(dev) && !intel_crtc->primary_enabled) + intel_crtc->atomic.wait_vblank = true; + } + + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); + + intel_crtc->atomic.update_fbc = true; } return 0; @@ -11773,18 +11808,6 @@ intel_commit_primary_plane(struct drm_plane *plane, struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_rect *src = &state->src; - enum pipe pipe = intel_plane->pipe; - - if (!fb) { - /* - * 'prepare' is never called when plane is being disabled, so - * we need to handle frontbuffer tracking here - */ - mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, - INTEL_FRONTBUFFER_PRIMARY(pipe)); - mutex_unlock(&dev->struct_mutex); - } plane->fb = fb; crtc->x = src->x1 >> 16; @@ -11801,26 +11824,7 @@ intel_commit_primary_plane(struct drm_plane *plane, intel_plane->obj = obj; if (intel_crtc->active) { - /* - * FBC does not work on some platforms for rotated - * planes, so disable it when rotation is not 0 and - * update it when rotation is set back to 0. - * - * FIXME: This is redundant with the fbc update done in - * the primary plane enable function except that that - * one is done too late. We eventually need to unify - * this. - */ - if (intel_crtc->primary_enabled && - INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && - dev_priv->fbc.plane == intel_crtc->plane && - intel_plane->rotation != BIT(DRM_ROTATE_0)) { - intel_fbc_disable(dev); - } - if (state->visible) { - bool was_enabled = intel_crtc->primary_enabled; - /* FIXME: kill this fastboot hack */ intel_update_pipe_size(intel_crtc); @@ -11828,14 +11832,6 @@ intel_commit_primary_plane(struct drm_plane *plane, dev_priv->display.update_primary_plane(crtc, plane->fb, crtc->x, crtc->y); - - /* - * BDW signals flip done immediately if the plane - * is disabled, even if the plane enable is already - * armed to occur at the next vblank :( - */ - if (IS_BROADWELL(dev) && !was_enabled) - intel_wait_for_vblank(dev, intel_crtc->pipe); } else { /* * If clipping results in a non-visible primary plane, @@ -11846,13 +11842,59 @@ intel_commit_primary_plane(struct drm_plane *plane, */ intel_disable_primary_hw_plane(plane, crtc); } + } +} + +static void intel_begin_crtc_commit(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); + if (intel_crtc->atomic.wait_for_flips) + intel_crtc_wait_for_pending_flips(crtc); + if (intel_crtc->atomic.disable_fbc) + intel_fbc_disable(dev); + + if (intel_crtc->atomic.pre_disable_primary) + intel_pre_disable_primary(crtc); + + if (intel_crtc->atomic.update_wm) + intel_update_watermarks(crtc); + + intel_runtime_pm_get(dev_priv); +} + +static void intel_finish_crtc_commit(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_plane *p; + + intel_runtime_pm_put(dev_priv); + + if (intel_crtc->atomic.wait_vblank) + intel_wait_for_vblank(dev, intel_crtc->pipe); + + intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits); + + if (intel_crtc->atomic.update_fbc) { mutex_lock(&dev->struct_mutex); intel_fbc_update(dev); mutex_unlock(&dev->struct_mutex); } + + if (intel_crtc->atomic.post_enable_primary) + intel_post_enable_primary(crtc); + + drm_for_each_legacy_plane(p, &dev->mode_config.plane_list) + if (intel_crtc->atomic.update_sprite_watermarks & drm_plane_index(p)) + intel_update_sprite_watermarks(p, crtc, 0, 0, 0, + false, false); + + memset(&intel_crtc->atomic, 0, sizeof(intel_crtc->atomic)); } int @@ -11863,9 +11905,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_w, uint32_t src_h) { struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_framebuffer *old_fb = plane->fb; - struct intel_plane_state state; + struct intel_plane_state state = {{ 0 }}; struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int ret; @@ -11903,9 +11944,33 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, return ret; } - intel_runtime_pm_get(dev_priv); + if (!state.base.fb) { + unsigned fb_bits = 0; + + switch (plane->type) { + case DRM_PLANE_TYPE_PRIMARY: + fb_bits = INTEL_FRONTBUFFER_PRIMARY(intel_plane->pipe); + break; + case DRM_PLANE_TYPE_CURSOR: + fb_bits = INTEL_FRONTBUFFER_CURSOR(intel_plane->pipe); + break; + case DRM_PLANE_TYPE_OVERLAY: + fb_bits = INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe); + break; + } + + /* + * 'prepare' is never called when plane is being disabled, so + * we need to handle frontbuffer tracking here + */ + mutex_lock(&dev->struct_mutex); + i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, fb_bits); + mutex_unlock(&dev->struct_mutex); + } + + intel_begin_crtc_commit(crtc); intel_plane->commit_plane(plane, &state); - intel_runtime_pm_put(dev_priv); + intel_finish_crtc_commit(crtc); if (fb != old_fb && old_fb) { if (intel_crtc->active) @@ -12012,6 +12077,7 @@ intel_check_cursor_plane(struct drm_plane *plane, struct drm_rect *src = &state->src; const struct drm_rect *clip = &state->clip; struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int crtc_w, crtc_h; unsigned stride; int ret; @@ -12027,7 +12093,7 @@ intel_check_cursor_plane(struct drm_plane *plane, /* if we want to turn off the cursor ignore width and height */ if (!obj) - return 0; + goto finish; /* Check for which cursor types we support */ crtc_w = drm_rect_width(&state->orig_dst); @@ -12054,6 +12120,16 @@ intel_check_cursor_plane(struct drm_plane *plane, } mutex_unlock(&dev->struct_mutex); +finish: + if (intel_crtc->active) { + if (intel_crtc->cursor_width != + drm_rect_width(&state->orig_dst)) + intel_crtc->atomic.update_wm = true; + + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe); + } + return ret; } @@ -12066,9 +12142,6 @@ intel_commit_cursor_plane(struct drm_plane *plane, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb); - struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); - enum pipe pipe = intel_crtc->pipe; - unsigned old_width; uint32_t addr; plane->fb = state->base.fb; @@ -12088,17 +12161,6 @@ intel_commit_cursor_plane(struct drm_plane *plane, if (intel_crtc->cursor_bo == obj) goto update; - /* - * 'prepare' is only called when fb != NULL; we still need to update - * frontbuffer tracking for the 'disable' case here. - */ - if (!obj) { - mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(old_obj, NULL, - INTEL_FRONTBUFFER_CURSOR(pipe)); - mutex_unlock(&dev->struct_mutex); - } - if (!obj) addr = 0; else if (!INTEL_INFO(dev)->cursor_needs_physical) @@ -12109,18 +12171,11 @@ intel_commit_cursor_plane(struct drm_plane *plane, intel_crtc->cursor_addr = addr; intel_crtc->cursor_bo = obj; update: - old_width = intel_crtc->cursor_width; - intel_crtc->cursor_width = drm_rect_width(&state->orig_dst); intel_crtc->cursor_height = drm_rect_height(&state->orig_dst); - if (intel_crtc->active) { - if (old_width != intel_crtc->cursor_width) - intel_update_watermarks(crtc); + if (intel_crtc->active) intel_crtc_update_cursor(crtc, state->visible); - - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe)); - } } static const struct drm_plane_funcs intel_cursor_plane_funcs = { -- cgit v1.2.2