From patchwork Wed Nov 26 15:25:00 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Roper X-Patchwork-Id: 5386241 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 55C7CC11AC for ; Wed, 26 Nov 2014 15:25:57 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C026D201FE for ; Wed, 26 Nov 2014 15:25:55 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 39990201EC for ; Wed, 26 Nov 2014 15:25:53 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7D95C6E2EB; Wed, 26 Nov 2014 07:25:51 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by gabe.freedesktop.org (Postfix) with ESMTP id 2CAF96E2EB for ; Wed, 26 Nov 2014 07:25:50 -0800 (PST) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga102.fm.intel.com with ESMTP; 26 Nov 2014 07:25:49 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.07,462,1413270000"; d="scan'208";a="638463850" Received: from mdroper-hswdev.fm.intel.com (HELO mdroper-hswdev) ([10.1.134.215]) by fmsmga002.fm.intel.com with ESMTP; 26 Nov 2014 07:25:49 -0800 Received: from mattrope by mdroper-hswdev with local (Exim 4.82) (envelope-from ) id 1XteTV-00076k-02; Wed, 26 Nov 2014 07:25:49 -0800 From: Matt Roper To: intel-gfx@lists.freedesktop.org Date: Wed, 26 Nov 2014 07:25:00 -0800 Message-Id: <1417015507-27265-4-git-send-email-matthew.d.roper@intel.com> X-Mailer: git-send-email 1.8.5.1 In-Reply-To: <1417015507-27265-1-git-send-email-matthew.d.roper@intel.com> References: <1417015507-27265-1-git-send-email-matthew.d.roper@intel.com> Subject: [Intel-gfx] [PATCH 03/10] drm/i915: Refactor work that can sleep out of commit X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Once we integrate our work into the atomic pipeline, plane commit operations will need to happen with interrupts disabled, due to vblank evasion. Create new 'pre_commit' and 'post_commit' handlers to cover hardware programming operations that can sleep and thus must happen outside the vblank evasion window. Signed-off-by: Matt Roper --- drivers/gpu/drm/i915/intel_display.c | 174 +++++++++++++++++++++++------------ drivers/gpu/drm/i915/intel_drv.h | 14 +++ drivers/gpu/drm/i915/intel_sprite.c | 93 +++++++++++-------- 3 files changed, 182 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d746cb4..8daa053 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11647,24 +11647,22 @@ intel_check_primary_plane(struct drm_plane *plane, } } + state->primary_was_enabled = to_intel_crtc(crtc)->primary_enabled; + return 0; } static void -intel_commit_primary_plane(struct drm_plane *plane, - struct intel_plane_state *state) +intel_pre_commit_primary(struct drm_plane *plane, + struct intel_plane_state *state) { - struct drm_crtc *crtc = state->base.crtc; - struct drm_framebuffer *fb = state->base.fb; struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - 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; + struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); + enum pipe pipe = intel_crtc->pipe; - if (!fb) { + if (!state->base.fb) { /* * 'prepare' is never called when plane is being disabled, so * we need to handle frontbuffer tracking here @@ -11675,20 +11673,6 @@ intel_commit_primary_plane(struct drm_plane *plane, mutex_unlock(&dev->struct_mutex); } - plane->fb = fb; - crtc->x = src->x1 >> 16; - crtc->y = src->y1 >> 16; - - intel_plane->crtc_x = state->orig_dst.x1; - intel_plane->crtc_y = state->orig_dst.y1; - intel_plane->crtc_w = drm_rect_width(&state->orig_dst); - intel_plane->crtc_h = drm_rect_height(&state->orig_dst); - intel_plane->src_x = state->orig_src.x1; - intel_plane->src_y = state->orig_src.y1; - intel_plane->src_w = drm_rect_width(&state->orig_src); - intel_plane->src_h = drm_rect_height(&state->orig_src); - intel_plane->obj = obj; - if (intel_crtc->active) { /* * FBC does not work on some platforms for rotated @@ -11706,10 +11690,65 @@ intel_commit_primary_plane(struct drm_plane *plane, intel_plane->rotation != BIT(DRM_ROTATE_0)) { intel_disable_fbc(dev); } + } +} +static void +intel_post_commit_primary(struct drm_plane *plane, + struct intel_plane_state *state) +{ + struct drm_device *dev = plane->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); + enum pipe pipe = intel_crtc->pipe; + + if (intel_crtc->active) { if (state->visible) { - bool was_enabled = intel_crtc->primary_enabled; + /* + * 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) && !state->primary_was_enabled) + intel_wait_for_vblank(dev, intel_crtc->pipe); + } + + intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); + + mutex_lock(&dev->struct_mutex); + intel_update_fbc(dev); + mutex_unlock(&dev->struct_mutex); + } +} + +static void +intel_commit_primary_plane(struct drm_plane *plane, + struct intel_plane_state *state) +{ + struct drm_crtc *crtc = state->base.crtc; + struct drm_framebuffer *fb = state->base.fb; + struct drm_device *dev = plane->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + 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; + + plane->fb = fb; + crtc->x = src->x1 >> 16; + crtc->y = src->y1 >> 16; + + intel_plane->crtc_x = state->orig_dst.x1; + intel_plane->crtc_y = state->orig_dst.y1; + intel_plane->crtc_w = drm_rect_width(&state->orig_dst); + intel_plane->crtc_h = drm_rect_height(&state->orig_dst); + intel_plane->src_x = state->orig_src.x1; + intel_plane->src_y = state->orig_src.y1; + intel_plane->src_w = drm_rect_width(&state->orig_src); + intel_plane->src_h = drm_rect_height(&state->orig_src); + intel_plane->obj = obj; + if (intel_crtc->active) { + if (state->visible) { /* FIXME: kill this fastboot hack */ intel_update_pipe_size(intel_crtc); @@ -11717,14 +11756,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, @@ -11735,12 +11766,6 @@ intel_commit_primary_plane(struct drm_plane *plane, */ intel_disable_primary_hw_plane(plane, plane->crtc); } - - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); - - mutex_lock(&dev->struct_mutex); - intel_update_fbc(dev); - mutex_unlock(&dev->struct_mutex); } } @@ -11753,7 +11778,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, { struct drm_device *dev = plane->dev; 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; @@ -11791,7 +11816,11 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, return ret; } + if (intel_plane->pre_commit) + intel_plane->pre_commit(plane, &state); intel_plane->commit_plane(plane, &state); + if (intel_plane->post_commit) + intel_plane->post_commit(plane, &state); if (fb != old_fb) { if (intel_crtc->active) @@ -11856,6 +11885,8 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, primary->rotation = BIT(DRM_ROTATE_0); primary->check_plane = intel_check_primary_plane; primary->commit_plane = intel_commit_primary_plane; + primary->pre_commit = intel_pre_commit_primary; + primary->post_commit = intel_post_commit_primary; if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4) primary->plane = !pipe; @@ -11944,6 +11975,46 @@ intel_check_cursor_plane(struct drm_plane *plane, } static void +intel_pre_commit_cursor(struct drm_plane *plane, + struct intel_plane_state *state) +{ + struct drm_device *dev = plane->dev; + struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb); + struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); + struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); + enum pipe pipe = intel_crtc->pipe; + + /* + * '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 (intel_crtc->active) { + if (intel_crtc->cursor_width != + drm_rect_width(&state->orig_dst)) + intel_update_watermarks(&intel_crtc->base); + } +} + +static void +intel_post_commit_cursor(struct drm_plane *plane, + struct intel_plane_state *state) +{ + struct drm_device *dev = plane->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); + enum pipe pipe = intel_crtc->pipe; + + if (intel_crtc->active) + intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe)); +} + +static void intel_commit_cursor_plane(struct drm_plane *plane, struct intel_plane_state *state) { @@ -11952,9 +12023,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; crtc->cursor_x = state->orig_dst.x1; @@ -11973,17 +12041,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) @@ -11994,18 +12051,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 = { @@ -12031,6 +12081,8 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev, cursor->rotation = BIT(DRM_ROTATE_0); cursor->check_plane = intel_check_cursor_plane; cursor->commit_plane = intel_commit_cursor_plane; + cursor->pre_commit = intel_pre_commit_cursor; + cursor->post_commit = intel_post_commit_cursor; drm_universal_plane_init(dev, &cursor->base, 0, &intel_cursor_plane_funcs, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index da4da2c..c2fcb82 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -251,6 +251,16 @@ struct intel_plane_state { struct drm_rect orig_src; struct drm_rect orig_dst; bool visible; + + /* + * used only for sprite planes to determine when to implicitly + * enable/disable the primary plane + */ + bool hides_primary; + bool need_primary_enable; + + /* used only for primary plane */ + bool primary_was_enabled; }; struct intel_plane_config { @@ -513,6 +523,10 @@ struct intel_plane { struct intel_plane_state *state); void (*commit_plane)(struct drm_plane *plane, struct intel_plane_state *state); + void (*pre_commit)(struct drm_plane *plane, + struct intel_plane_state *state); + void (*post_commit)(struct drm_plane *plane, + struct intel_plane_state *state); int (*update_colorkey)(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key); void (*get_colorkey)(struct drm_plane *plane, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index bc5834b..d18da5d 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1260,44 +1260,75 @@ intel_check_sprite_plane(struct drm_plane *plane, dst->y1 = crtc_y; dst->y2 = crtc_y + crtc_h; + /* + * Does this plane completely hide the primary plane? If so, we can + * disable the primary to save power. + */ + if (drm_rect_equals(dst, clip) && !colorkey_enabled(intel_plane)) + state->hides_primary = true; + else + state->hides_primary = false; + return 0; } static void -intel_commit_sprite_plane(struct drm_plane *plane, - struct intel_plane_state *state) +intel_pre_commit_sprite(struct drm_plane *plane, + struct intel_plane_state *state) { struct drm_device *dev = plane->dev; 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); - enum pipe pipe = intel_crtc->pipe; - struct drm_framebuffer *fb = state->base.fb; - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - int crtc_x, crtc_y; - unsigned int crtc_w, crtc_h; - uint32_t src_x, src_y, src_w, src_h; - struct drm_rect *dst = &state->dst; - const struct drm_rect *clip = &state->clip; - bool primary_enabled; /* - * 'prepare' is never called when plane is being disabled, so we need - * to handle frontbuffer tracking here + * 'prepare' is never called when plane is being disabled, so + * we need to handle frontbuffer tracking here */ - if (!fb) { + if (!state->base.fb) { mutex_lock(&dev->struct_mutex); i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, - INTEL_FRONTBUFFER_SPRITE(pipe)); + INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe)); mutex_unlock(&dev->struct_mutex); } - /* - * If the sprite is completely covering the primary plane, - * we can disable the primary and save power. - */ - primary_enabled = !drm_rect_equals(dst, clip) || colorkey_enabled(intel_plane); - WARN_ON(!primary_enabled && !state->visible && intel_crtc->active); + if (intel_crtc->primary_enabled && state->hides_primary) { + intel_crtc_wait_for_pending_flips(crtc); + intel_pre_disable_primary(crtc); + } + + if (!intel_crtc->primary_enabled && !state->hides_primary) + state->need_primary_enable = true; + + intel_crtc->primary_enabled = !state->hides_primary; +} + +static void +intel_post_commit_sprite(struct drm_plane *plane, + struct intel_plane_state *state) +{ + struct drm_device *dev = plane->dev; + struct drm_crtc *crtc = state->base.crtc; + struct intel_plane *intel_plane = to_intel_plane(plane); + + intel_frontbuffer_flip(dev, + INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe)); + + if (state->need_primary_enable) + intel_post_enable_primary(crtc); +} + +static void +intel_commit_sprite_plane(struct drm_plane *plane, + struct intel_plane_state *state) +{ + 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_i915_gem_object *obj = intel_fb_obj(fb); + int crtc_x, crtc_y; + unsigned int crtc_w, crtc_h; + uint32_t src_x, src_y, src_w, src_h; intel_plane->crtc_x = state->orig_dst.x1; intel_plane->crtc_y = state->orig_dst.y1; @@ -1310,16 +1341,6 @@ intel_commit_sprite_plane(struct drm_plane *plane, intel_plane->obj = obj; if (intel_crtc->active) { - bool primary_was_enabled = intel_crtc->primary_enabled; - - intel_crtc->primary_enabled = primary_enabled; - - if (primary_was_enabled != primary_enabled) - intel_crtc_wait_for_pending_flips(crtc); - - if (primary_was_enabled && !primary_enabled) - intel_pre_disable_primary(crtc); - if (state->visible) { crtc_x = state->dst.x1; crtc_y = state->dst.y1; @@ -1335,12 +1356,6 @@ intel_commit_sprite_plane(struct drm_plane *plane, } else { intel_plane->disable_plane(plane, crtc); } - - - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_SPRITE(pipe)); - - if (!primary_was_enabled && primary_enabled) - intel_post_enable_primary(crtc); } } @@ -1589,6 +1604,8 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) intel_plane->rotation = BIT(DRM_ROTATE_0); intel_plane->check_plane = intel_check_sprite_plane; intel_plane->commit_plane = intel_commit_sprite_plane; + intel_plane->pre_commit = intel_pre_commit_sprite; + intel_plane->post_commit = intel_post_commit_sprite; possible_crtcs = (1 << pipe); ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, &intel_plane_funcs,