From patchwork Mon Dec 23 15:45:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Stanislav Lisovskiy X-Patchwork-Id: 11308491 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2D9A6138C for ; Mon, 23 Dec 2019 15:48:14 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 16371205C9 for ; Mon, 23 Dec 2019 15:48:13 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 16371205C9 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=intel.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=intel-gfx-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 078166E2CF; Mon, 23 Dec 2019 15:48:12 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by gabe.freedesktop.org (Postfix) with ESMTPS id ED2F86E2CC for ; Mon, 23 Dec 2019 15:48:10 +0000 (UTC) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 23 Dec 2019 07:48:10 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.69,348,1571727600"; d="scan'208";a="207305906" Received: from slisovsk-lenovo-ideapad-720s-13ikb.fi.intel.com ([10.237.72.89]) by orsmga007.jf.intel.com with ESMTP; 23 Dec 2019 07:48:08 -0800 From: Stanislav Lisovskiy To: intel-gfx@lists.freedesktop.org Date: Mon, 23 Dec 2019 17:45:22 +0200 Message-Id: <20191223154522.9797-5-stanislav.lisovskiy@intel.com> X-Mailer: git-send-email 2.24.1.485.gad05a3d8e5 In-Reply-To: <20191223154522.9797-1-stanislav.lisovskiy@intel.com> References: <20191223154522.9797-1-stanislav.lisovskiy@intel.com> MIME-Version: 1.0 Subject: [Intel-gfx] [PATCH v10 4/4] drm/i915: Correctly map DBUF slices to pipes X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" Added proper DBuf slice mapping to correspondent pipes, depending on pipe configuration as stated in BSpec. v2: - Remove unneeded braces - Stop using macro for DBuf assignments as it seems to reduce readability. v3: Start using enabled slices mask in dev_priv v4: Renamed "enabled_slices" used in dev_priv to "enabled_dbuf_slices_mask"(Matt Roper) v5: - Removed redundant parameters from intel_get_ddb_size function.(Matt Roper) - Made i915_possible_dbuf_slices static(Matt Roper) - Renamed total_width into total_width_in_range so that it now reflects that this is not a total pipe width but the one in current dbuf slice allowed range for pipe.(Matt Roper) - Removed 4th pipe for ICL in DBuf assignment table(Matt Roper) - Fixed wrong DBuf slice in DBuf table for TGL (Matt Roper) - Added comment regarding why we currently not using pipe ratio for DBuf assignment for ICL v6: - Changed u32 to unsigned int in icl_get_first_dbuf_slice_offset function signature (Ville Syrjälä) - Changed also u32 to u8 in dbuf slice mask structure (Ville Syrjälä) - Switched from DBUF_S1_BIT to enum + explicit BIT(DBUF_S1) access(Ville Syrjälä) - Switched to named initializers in DBuf assignment arrays(Ville Syrjälä) - DBuf assignment arrays now use autogeneration tool from https://patchwork.freedesktop.org/series/70493/ to avoid typos. - Renamed i915_find_pipe_conf to *_compute_dbuf_slices (Ville Syrjälä) - Changed platforms ordering in skl_compute_dbuf_slices to be from newest to oldest(Ville Syrjälä) Signed-off-by: Stanislav Lisovskiy --- .../drm/i915/display/intel_display_power.c | 2 +- .../drm/i915/display/intel_display_power.h | 8 +- drivers/gpu/drm/i915/intel_pm.c | 386 +++++++++++++++++- drivers/gpu/drm/i915/intel_pm.h | 2 + 4 files changed, 375 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index b30738d2d46c..334bebe61e45 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -4443,7 +4443,7 @@ static void icl_dbuf_enable(struct drm_i915_private *dev_priv) * Just power up 1 slice, we will * figure out later which slices we have and what we need. */ - dev_priv->enabled_dbuf_slices_mask = DBUF_S1_BIT; + dev_priv->enabled_dbuf_slices_mask = BIT(DBUF_S1); icl_dbuf_slices_update(dev_priv, dev_priv->enabled_dbuf_slices_mask); } diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h index f52594ecf577..009e7281a0dd 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.h +++ b/drivers/gpu/drm/i915/display/intel_display_power.h @@ -307,13 +307,15 @@ intel_display_power_put_async(struct drm_i915_private *i915, } #endif +enum dbuf_slice { + DBUF_S1, + DBUF_S2 +}; + #define with_intel_display_power(i915, domain, wf) \ for ((wf) = intel_display_power_get((i915), (domain)); (wf); \ intel_display_power_put_async((i915), (domain), (wf)), (wf) = 0) -#define DBUF_S1_BIT BIT(0) -#define DBUF_S2_BIT BIT(1) - void icl_dbuf_slices_update(struct drm_i915_private *dev_priv, u8 req_slices); int intel_dbuf_max_slices(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index dc6b69f5b6d7..a2101668a468 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3624,7 +3624,7 @@ u8 intel_enabled_dbuf_slices_mask(struct drm_i915_private *dev_priv) /* Gen prior to GEN11 have only one DBuf slice */ if (INTEL_GEN(dev_priv) < 11) - return DBUF_S1_BIT; + return BIT(DBUF_S1); for (i = 0; i < max_slices; i++) { if (I915_READ(DBUF_CTL_S(BIT(i))) & DBUF_POWER_STATE) @@ -3832,13 +3832,29 @@ bool intel_can_enable_sagv(struct intel_atomic_state *state) return true; } -static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv, - const struct intel_crtc_state *crtc_state, - const u64 total_data_rate, - const int num_active) +/* + * Calculate initial DBuf slice offset, based on slice size + * and mask(i.e if slice size is 1024 and second slice is enabled + * offset would be 1024) + */ +static unsigned int +icl_get_first_dbuf_slice_offset(u32 dbuf_slice_mask, + u32 slice_size, + u32 ddb_size) +{ + unsigned int offset = 0; + + if (!dbuf_slice_mask) + return 0; + + offset = (ffs(dbuf_slice_mask) - 1) * slice_size; + + WARN_ON(offset >= ddb_size); + return offset; +} + +static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv) { - struct drm_atomic_state *state = crtc_state->uapi.state; - struct intel_atomic_state *intel_state = to_intel_atomic_state(state); u16 ddb_size = INTEL_INFO(dev_priv)->ddb_size; WARN_ON(ddb_size == 0); @@ -3846,12 +3862,12 @@ static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv, if (INTEL_GEN(dev_priv) < 11) return ddb_size - 4; /* 4 blocks for bypass path allocation */ - intel_state->enabled_dbuf_slices_mask = DBUF_S1_BIT; - ddb_size /= 2; - return ddb_size; } +static u8 skl_compute_dbuf_slices(const struct intel_crtc_state *crtc_state, + u32 active_pipes); + static void skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv, const struct intel_crtc_state *crtc_state, @@ -3863,10 +3879,17 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv, struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct drm_crtc *for_crtc = crtc_state->uapi.crtc; const struct intel_crtc *crtc; - u32 pipe_width = 0, total_width = 0, width_before_pipe = 0; + u32 pipe_width = 0, total_width_in_range = 0, width_before_pipe = 0; enum pipe for_pipe = to_intel_crtc(for_crtc)->pipe; u16 ddb_size; + u32 ddb_range_size; u32 i; + u32 dbuf_slice_mask; + u32 active_pipes; + u32 offset; + u32 slice_size; + u32 total_slice_mask; + u32 start, end; if (WARN_ON(!state) || !crtc_state->hw.active) { alloc->start = 0; @@ -3876,12 +3899,15 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv, } if (intel_state->active_pipe_changes) - *num_active = hweight8(intel_state->active_pipes); + active_pipes = intel_state->active_pipes; else - *num_active = hweight8(dev_priv->active_pipes); + active_pipes = dev_priv->active_pipes; + + *num_active = hweight8(active_pipes); + + ddb_size = intel_get_ddb_size(dev_priv); - ddb_size = intel_get_ddb_size(dev_priv, crtc_state, total_data_rate, - *num_active); + slice_size = ddb_size / INTEL_INFO(dev_priv)->num_supported_dbuf_slices; /* * If the state doesn't change the active CRTC's or there is no @@ -3900,22 +3926,71 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv, return; } + /* + * Get allowed DBuf slices for correspondent pipe and platform. + */ + dbuf_slice_mask = skl_compute_dbuf_slices(crtc_state, active_pipes); + + DRM_DEBUG_KMS("DBuf slice mask %x pipe %d active pipes %x\n", + dbuf_slice_mask, + for_pipe, active_pipes); + + /* + * Figure out at which DBuf slice we start, i.e if we start at Dbuf S2 + * and slice size is 1024, the offset would be 1024 + */ + offset = icl_get_first_dbuf_slice_offset(dbuf_slice_mask, + slice_size, ddb_size); + + /* + * Figure out total size of allowed DBuf slices, which is basically + * a number of allowed slices for that pipe multiplied by slice size. + * Inside of this + * range ddb entries are still allocated in proportion to display width. + */ + ddb_range_size = hweight8(dbuf_slice_mask) * slice_size; + /* * Watermark/ddb requirement highly depends upon width of the * framebuffer, So instead of allocating DDB equally among pipes * distribute DDB based on resolution/width of the display. */ + total_slice_mask = dbuf_slice_mask; for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) { const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; enum pipe pipe = crtc->pipe; int hdisplay, vdisplay; + u32 pipe_dbuf_slice_mask; - if (!crtc_state->hw.enable) + if (!crtc_state->hw.active) + continue; + + pipe_dbuf_slice_mask = skl_compute_dbuf_slices(crtc_state, + active_pipes); + + /* + * According to BSpec pipe can share one dbuf slice with another + * pipes or pipe can use multiple dbufs, in both cases we + * account for other pipes only if they have exactly same mask. + * However we need to account how many slices we should enable + * in total. + */ + total_slice_mask |= pipe_dbuf_slice_mask; + + /* + * Do not account pipes using other slice sets + * luckily as of current BSpec slice sets do not partially + * intersect(pipes share either same one slice or same slice set + * i.e no partial intersection), so it is enough to check for + * equality for now. + */ + if (dbuf_slice_mask != pipe_dbuf_slice_mask) continue; drm_mode_get_hv_timing(adjusted_mode, &hdisplay, &vdisplay); - total_width += hdisplay; + + total_width_in_range += hdisplay; if (pipe < for_pipe) width_before_pipe += hdisplay; @@ -3923,8 +3998,20 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv, pipe_width = hdisplay; } - alloc->start = ddb_size * width_before_pipe / total_width; - alloc->end = ddb_size * (width_before_pipe + pipe_width) / total_width; + intel_state->enabled_dbuf_slices_mask = total_slice_mask; + + start = ddb_range_size * width_before_pipe / total_width_in_range; + end = ddb_range_size * + (width_before_pipe + pipe_width) / total_width_in_range; + + alloc->start = offset + start; + alloc->end = offset + end; + + DRM_DEBUG_KMS("Pipe %d ddb %d-%d\n", for_pipe, + alloc->start, alloc->end); + DRM_DEBUG_KMS("Enabled ddb slices mask %x num supported %d\n", + intel_state->enabled_dbuf_slices_mask, + INTEL_INFO(dev_priv)->num_supported_dbuf_slices); } static int skl_compute_wm_params(const struct intel_crtc_state *crtc_state, @@ -4095,6 +4182,267 @@ skl_plane_downscale_amount(const struct intel_crtc_state *crtc_state, return mul_fixed16(downscale_w, downscale_h); } +struct dbuf_slice_conf_entry { + u8 active_pipes; + u8 dbuf_mask[I915_MAX_PIPES]; +}; + +/* + * Table taken from Bspec 12716 + * Pipes do have some preferred DBuf slice affinity, + * plus there are some hardcoded requirements on how + * those should be distributed for multipipe scenarios. + * For more DBuf slices algorithm can get even more messy + * and less readable, so decided to use a table almost + * as is from BSpec itself - that way it is at least easier + * to compare, change and check. + */ +static struct dbuf_slice_conf_entry icl_allowed_dbufs[] = +/* Autogenerated with igt/tools/intel_dbuf_map tool: */ +{ + { + .active_pipes = BIT(PIPE_A), + { + [PIPE_A] = BIT(DBUF_S1) | BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_B), + { + [PIPE_B] = BIT(DBUF_S1) | BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_A) | BIT(PIPE_B), + { + [PIPE_A] = BIT(DBUF_S1), + [PIPE_B] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_C), + { + [PIPE_C] = BIT(DBUF_S2) | BIT(DBUF_S1) + } + }, + { + .active_pipes = BIT(PIPE_A) | BIT(PIPE_C), + { + [PIPE_A] = BIT(DBUF_S1), + [PIPE_C] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_B) | BIT(PIPE_C), + { + [PIPE_B] = BIT(DBUF_S1), + [PIPE_C] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C), + { + [PIPE_A] = BIT(DBUF_S1), + [PIPE_B] = BIT(DBUF_S1), + [PIPE_C] = BIT(DBUF_S2) + } + }, +}; + +/* + * Table taken from Bspec 49255 + * Pipes do have some preferred DBuf slice affinity, + * plus there are some hardcoded requirements on how + * those should be distributed for multipipe scenarios. + * For more DBuf slices algorithm can get even more messy + * and less readable, so decided to use a table almost + * as is from BSpec itself - that way it is at least easier + * to compare, change and check. + */ +static struct dbuf_slice_conf_entry tgl_allowed_dbufs[] = +/* Autogenerated with igt/tools/intel_dbuf_map tool: */ +{ + { + .active_pipes = BIT(PIPE_A), + { + [PIPE_A] = BIT(DBUF_S1) | BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_B), + { + [PIPE_B] = BIT(DBUF_S1) | BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_A) | BIT(PIPE_B), + { + [PIPE_A] = BIT(DBUF_S2), + [PIPE_B] = BIT(DBUF_S1) + } + }, + { + .active_pipes = BIT(PIPE_C), + { + [PIPE_C] = BIT(DBUF_S2) | BIT(DBUF_S1) + } + }, + { + .active_pipes = BIT(PIPE_A) | BIT(PIPE_C), + { + [PIPE_A] = BIT(DBUF_S1), + [PIPE_C] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_B) | BIT(PIPE_C), + { + [PIPE_B] = BIT(DBUF_S1), + [PIPE_C] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C), + { + [PIPE_A] = BIT(DBUF_S1), + [PIPE_B] = BIT(DBUF_S1), + [PIPE_C] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_D), + { + [PIPE_D] = BIT(DBUF_S2) | BIT(DBUF_S1) + } + }, + { + .active_pipes = BIT(PIPE_A) | BIT(PIPE_D), + { + [PIPE_A] = BIT(DBUF_S1), + [PIPE_D] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_B) | BIT(PIPE_D), + { + [PIPE_B] = BIT(DBUF_S1), + [PIPE_D] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_D), + { + [PIPE_A] = BIT(DBUF_S1), + [PIPE_B] = BIT(DBUF_S1), + [PIPE_D] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_C) | BIT(PIPE_D), + { + [PIPE_C] = BIT(DBUF_S1), + [PIPE_D] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_A) | BIT(PIPE_C) | BIT(PIPE_D), + { + [PIPE_A] = BIT(DBUF_S1), + [PIPE_C] = BIT(DBUF_S2), + [PIPE_D] = BIT(DBUF_S2) + } + }, + { + .active_pipes = BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D), + { + [PIPE_B] = BIT(DBUF_S1), + [PIPE_C] = BIT(DBUF_S2), + [PIPE_D] = BIT(DBUF_S2) + } + }, + { + .active_pipes = + BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D), + { + [PIPE_A] = BIT(DBUF_S1), + [PIPE_B] = BIT(DBUF_S1), + [PIPE_C] = BIT(DBUF_S2), + [PIPE_D] = BIT(DBUF_S2) + } + }, +}; + +static u8 compute_dbuf_slices(enum pipe pipe, + u32 active_pipes, + const struct dbuf_slice_conf_entry *dbuf_slices, + int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (dbuf_slices[i].active_pipes == active_pipes) + return dbuf_slices[i].dbuf_mask[pipe]; + } + return 0; +} + +/* + * This function finds an entry with same enabled pipe configuration and + * returns correspondent DBuf slice mask as stated in BSpec for particular + * platform. + */ +static u32 icl_compute_dbuf_slices(enum pipe pipe, + u32 active_pipes, + const struct intel_crtc_state *crtc_state) +{ + /* + * FIXME: For ICL this is still a bit unclear as prev BSpec revision + * required calculating "pipe ratio" in order to determine + * if one or two slices can be used for single pipe configurations + * as additional constraint to the existing table. + * However based on recent info, it should be not "pipe ratio" + * but rather ratio between pixel_rate and cdclk with additional + * constants, so for now we are using only table until this is + * clarified. Also this is the reason why crtc_state param is + * still here - we will need it once those additional constraints + * pop up. + */ + return compute_dbuf_slices(pipe, active_pipes, + icl_allowed_dbufs, + ARRAY_SIZE(icl_allowed_dbufs)); +} + +static u32 tgl_compute_dbuf_slices(enum pipe pipe, + u32 active_pipes, + const struct intel_crtc_state *crtc_state) +{ + return compute_dbuf_slices(pipe, active_pipes, + tgl_allowed_dbufs, + ARRAY_SIZE(tgl_allowed_dbufs)); +} + +static u8 skl_compute_dbuf_slices(const struct intel_crtc_state *crtc_state, + u32 active_pipes) +{ + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + + if (IS_GEN(dev_priv, 12)) + return tgl_compute_dbuf_slices(pipe, + active_pipes, + crtc_state); + else if (IS_GEN(dev_priv, 11)) + return icl_compute_dbuf_slices(pipe, + active_pipes, + crtc_state); + /* + * For anything else just return one slice yet. + * Should be extended for other platforms. + */ + return BIT(DBUF_S1); +} + static u64 skl_plane_relative_data_rate(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state, diff --git a/drivers/gpu/drm/i915/intel_pm.h b/drivers/gpu/drm/i915/intel_pm.h index d60a85421c5a..f853bc184dd6 100644 --- a/drivers/gpu/drm/i915/intel_pm.h +++ b/drivers/gpu/drm/i915/intel_pm.h @@ -57,6 +57,8 @@ bool ilk_disable_lp_wm(struct drm_i915_private *dev_priv); void intel_init_ipc(struct drm_i915_private *dev_priv); void intel_enable_ipc(struct drm_i915_private *dev_priv); +int intel_dbuf_max_slices(struct drm_i915_private *dev_priv); + bool intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable); #endif /* __INTEL_PM_H__ */