Skip to content

Commit ed4a6a7

Browse files
committed
drm/i915: Add two-stage ILK-style watermark programming (v11)
In addition to calculating final watermarks, let's also pre-calculate a set of intermediate watermark values at atomic check time. These intermediate watermarks are a combination of the watermarks for the old state and the new state; they should satisfy the requirements of both states which means they can be programmed immediately when we commit the atomic state (without waiting for a vblank). Once the vblank does happen, we can then re-program watermarks to the more optimal final value. v2: Significant rebasing/rewriting. v3: - Move 'need_postvbl_update' flag to CRTC state (Daniel) - Don't forget to check intermediate watermark values for validity (Maarten) - Don't due async watermark optimization; just do it at the end of the atomic transaction, after waiting for vblanks. We do want it to be async eventually, but adding that now will cause more trouble for Maarten's in-progress work. (Maarten) - Don't allocate space in crtc_state for intermediate watermarks on platforms that don't need it (gen9+). - Move WaCxSRDisabledForSpriteScaling:ivb into intel_begin_crtc_commit now that ilk_update_wm is gone. v4: - Add a wm_mutex to cover updates to intel_crtc->active and the need_postvbl_update flag. Since we don't have async yet it isn't terribly important yet, but might as well add it now. - Change interface to program watermarks. Platforms will now expose .initial_watermarks() and .optimize_watermarks() functions to do watermark programming. These should lock wm_mutex, copy the appropriate state values into intel_crtc->active, and then call the internal program watermarks function. v5: - Skip intermediate watermark calculation/check during initial hardware readout since we don't trust the existing HW values (and don't have valid values of our own yet). - Don't try to call .optimize_watermarks() on platforms that don't have atomic watermarks yet. (Maarten) v6: - Rebase v7: - Further rebase v8: - A few minor indentation and line length fixes v9: - Yet another rebase since Maarten's patches reworked a bunch of the code (wm_pre, wm_post, etc.) that this was previously based on. v10: - Move wm_mutex to dev_priv to protect against racing commits against disjoint CRTC sets. (Maarten) - Drop unnecessary clearing of cstate->wm.need_postvbl_update (Maarten) v11: - Now that we've moved to atomic watermark updates, make sure we call the proper function to program watermarks in {ironlake,haswell}_crtc_enable(); the failure to do so on the previous patch iteration led to us not actually programming the watermarks before turning on the CRTC, which was the cause of the underruns that the CI system was seeing. - Fix inverted logic for determining when to optimize watermarks. We were needlessly optimizing when the intermediate/optimal values were the same (harmless), but not actually optimizing when they differed (also harmless, but wasteful from a power/bandwidth perspective). Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Matt Roper <matthew.d.roper@intel.com> Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/1456276813-5689-1-git-send-email-matthew.d.roper@intel.com
1 parent 5790ff7 commit ed4a6a7

File tree

6 files changed

+244
-58
lines changed

6 files changed

+244
-58
lines changed

drivers/gpu/drm/i915/i915_dma.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,6 +1010,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
10101010
mutex_init(&dev_priv->sb_lock);
10111011
mutex_init(&dev_priv->modeset_restore_lock);
10121012
mutex_init(&dev_priv->av_mutex);
1013+
mutex_init(&dev_priv->wm.wm_mutex);
10131014

10141015
ret = i915_workqueues_init(dev_priv);
10151016
if (ret < 0)

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,11 @@ struct drm_i915_display_funcs {
631631
struct dpll *best_clock);
632632
int (*compute_pipe_wm)(struct intel_crtc *crtc,
633633
struct drm_atomic_state *state);
634-
void (*program_watermarks)(struct intel_crtc_state *cstate);
634+
int (*compute_intermediate_wm)(struct drm_device *dev,
635+
struct intel_crtc *intel_crtc,
636+
struct intel_crtc_state *newstate);
637+
void (*initial_watermarks)(struct intel_crtc_state *cstate);
638+
void (*optimize_watermarks)(struct intel_crtc_state *cstate);
635639
void (*update_wm)(struct drm_crtc *crtc);
636640
int (*modeset_calc_cdclk)(struct drm_atomic_state *state);
637641
void (*modeset_commit_cdclk)(struct drm_atomic_state *state);
@@ -1980,6 +1984,13 @@ struct drm_i915_private {
19801984
};
19811985

19821986
uint8_t max_level;
1987+
1988+
/*
1989+
* Should be held around atomic WM register writing; also
1990+
* protects * intel_crtc->wm.active and
1991+
* cstate->wm.need_postvbl_update.
1992+
*/
1993+
struct mutex wm_mutex;
19831994
} wm;
19841995

19851996
struct i915_runtime_pm pm;

drivers/gpu/drm/i915/intel_atomic.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
9898
crtc_state->disable_cxsr = false;
9999
crtc_state->wm_changed = false;
100100
crtc_state->fb_changed = false;
101+
crtc_state->wm.need_postvbl_update = false;
101102

102103
return &crtc_state->base;
103104
}

drivers/gpu/drm/i915/intel_display.c

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4843,7 +4843,42 @@ static void intel_pre_plane_update(struct intel_crtc_state *old_crtc_state)
48434843
intel_set_memory_cxsr(dev_priv, false);
48444844
}
48454845

4846-
if (!needs_modeset(&pipe_config->base) && pipe_config->wm_changed)
4846+
/*
4847+
* IVB workaround: must disable low power watermarks for at least
4848+
* one frame before enabling scaling. LP watermarks can be re-enabled
4849+
* when scaling is disabled.
4850+
*
4851+
* WaCxSRDisabledForSpriteScaling:ivb
4852+
*/
4853+
if (pipe_config->disable_lp_wm) {
4854+
ilk_disable_lp_wm(dev);
4855+
intel_wait_for_vblank(dev, crtc->pipe);
4856+
}
4857+
4858+
/*
4859+
* If we're doing a modeset, we're done. No need to do any pre-vblank
4860+
* watermark programming here.
4861+
*/
4862+
if (needs_modeset(&pipe_config->base))
4863+
return;
4864+
4865+
/*
4866+
* For platforms that support atomic watermarks, program the
4867+
* 'intermediate' watermarks immediately. On pre-gen9 platforms, these
4868+
* will be the intermediate values that are safe for both pre- and
4869+
* post- vblank; when vblank happens, the 'active' values will be set
4870+
* to the final 'target' values and we'll do this again to get the
4871+
* optimal watermarks. For gen9+ platforms, the values we program here
4872+
* will be the final target values which will get automatically latched
4873+
* at vblank time; no further programming will be necessary.
4874+
*
4875+
* If a platform hasn't been transitioned to atomic watermarks yet,
4876+
* we'll continue to update watermarks the old way, if flags tell
4877+
* us to.
4878+
*/
4879+
if (dev_priv->display.initial_watermarks != NULL)
4880+
dev_priv->display.initial_watermarks(pipe_config);
4881+
else if (pipe_config->wm_changed)
48474882
intel_update_watermarks(&crtc->base);
48484883
}
48494884

@@ -4922,7 +4957,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
49224957
*/
49234958
intel_crtc_load_lut(crtc);
49244959

4925-
intel_update_watermarks(crtc);
4960+
dev_priv->display.initial_watermarks(intel_crtc->config);
49264961
intel_enable_pipe(intel_crtc);
49274962

49284963
if (intel_crtc->config->has_pch_encoder)
@@ -5021,7 +5056,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
50215056
if (!intel_crtc->config->has_dsi_encoder)
50225057
intel_ddi_enable_transcoder_func(crtc);
50235058

5024-
intel_update_watermarks(crtc);
5059+
dev_priv->display.initial_watermarks(pipe_config);
50255060
intel_enable_pipe(intel_crtc);
50265061

50275062
if (intel_crtc->config->has_pch_encoder)
@@ -11785,6 +11820,7 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
1178511820
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1178611821
struct drm_plane *plane = plane_state->plane;
1178711822
struct drm_device *dev = crtc->dev;
11823+
struct drm_i915_private *dev_priv = to_i915(dev);
1178811824
struct intel_plane_state *old_plane_state =
1178911825
to_intel_plane_state(plane->state);
1179011826
int idx = intel_crtc->base.base.id, ret;
@@ -11843,6 +11879,11 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state,
1184311879
pipe_config->wm_changed = true;
1184411880
}
1184511881

11882+
/* Pre-gen9 platforms need two-step watermark updates */
11883+
if (pipe_config->wm_changed && INTEL_INFO(dev)->gen < 9 &&
11884+
dev_priv->display.optimize_watermarks)
11885+
to_intel_crtc_state(crtc_state)->wm.need_postvbl_update = true;
11886+
1184611887
if (visible || was_visible)
1184711888
intel_crtc->atomic.fb_bits |=
1184811889
to_intel_plane(plane)->frontbuffer_bit;
@@ -11954,8 +11995,29 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc,
1195411995
ret = 0;
1195511996
if (dev_priv->display.compute_pipe_wm) {
1195611997
ret = dev_priv->display.compute_pipe_wm(intel_crtc, state);
11957-
if (ret)
11998+
if (ret) {
11999+
DRM_DEBUG_KMS("Target pipe watermarks are invalid\n");
12000+
return ret;
12001+
}
12002+
}
12003+
12004+
if (dev_priv->display.compute_intermediate_wm &&
12005+
!to_intel_atomic_state(state)->skip_intermediate_wm) {
12006+
if (WARN_ON(!dev_priv->display.compute_pipe_wm))
12007+
return 0;
12008+
12009+
/*
12010+
* Calculate 'intermediate' watermarks that satisfy both the
12011+
* old state and the new state. We can program these
12012+
* immediately.
12013+
*/
12014+
ret = dev_priv->display.compute_intermediate_wm(crtc->dev,
12015+
intel_crtc,
12016+
pipe_config);
12017+
if (ret) {
12018+
DRM_DEBUG_KMS("No valid intermediate pipe watermarks are possible\n");
1195812019
return ret;
12020+
}
1195912021
}
1196012022

1196112023
if (INTEL_INFO(dev)->gen >= 9) {
@@ -13488,6 +13550,7 @@ static int intel_atomic_commit(struct drm_device *dev,
1348813550
struct drm_i915_private *dev_priv = dev->dev_private;
1348913551
struct drm_crtc_state *crtc_state;
1349013552
struct drm_crtc *crtc;
13553+
struct intel_crtc_state *intel_cstate;
1349113554
int ret = 0, i;
1349213555
bool hw_check = intel_state->modeset;
1349313556
unsigned long put_domains[I915_MAX_PIPES] = {};
@@ -13603,6 +13666,20 @@ static int intel_atomic_commit(struct drm_device *dev,
1360313666
if (intel_state->modeset)
1360413667
intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET);
1360513668

13669+
/*
13670+
* Now that the vblank has passed, we can go ahead and program the
13671+
* optimal watermarks on platforms that need two-step watermark
13672+
* programming.
13673+
*
13674+
* TODO: Move this (and other cleanup) to an async worker eventually.
13675+
*/
13676+
for_each_crtc_in_state(state, crtc, crtc_state, i) {
13677+
intel_cstate = to_intel_crtc_state(crtc->state);
13678+
13679+
if (dev_priv->display.optimize_watermarks)
13680+
dev_priv->display.optimize_watermarks(intel_cstate);
13681+
}
13682+
1360613683
mutex_lock(&dev->struct_mutex);
1360713684
drm_atomic_helper_cleanup_planes(dev, state);
1360813685
mutex_unlock(&dev->struct_mutex);
@@ -15273,7 +15350,7 @@ static void sanitize_watermarks(struct drm_device *dev)
1527315350
int i;
1527415351

1527515352
/* Only supported on platforms that use atomic watermark design */
15276-
if (!dev_priv->display.program_watermarks)
15353+
if (!dev_priv->display.optimize_watermarks)
1527715354
return;
1527815355

1527915356
/*
@@ -15294,6 +15371,13 @@ static void sanitize_watermarks(struct drm_device *dev)
1529415371
if (WARN_ON(IS_ERR(state)))
1529515372
goto fail;
1529615373

15374+
/*
15375+
* Hardware readout is the only time we don't want to calculate
15376+
* intermediate watermarks (since we don't trust the current
15377+
* watermarks).
15378+
*/
15379+
to_intel_atomic_state(state)->skip_intermediate_wm = true;
15380+
1529715381
ret = intel_atomic_check(dev, state);
1529815382
if (ret) {
1529915383
/*
@@ -15316,7 +15400,8 @@ static void sanitize_watermarks(struct drm_device *dev)
1531615400
for_each_crtc_in_state(state, crtc, cstate, i) {
1531715401
struct intel_crtc_state *cs = to_intel_crtc_state(cstate);
1531815402

15319-
dev_priv->display.program_watermarks(cs);
15403+
cs->wm.need_postvbl_update = true;
15404+
dev_priv->display.optimize_watermarks(cs);
1532015405
}
1532115406

1532215407
drm_atomic_state_free(state);

drivers/gpu/drm/i915/intel_drv.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ struct intel_atomic_state {
260260

261261
struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS];
262262
struct intel_wm_config wm_config;
263+
264+
/*
265+
* Current watermarks can't be trusted during hardware readout, so
266+
* don't bother calculating intermediate watermarks.
267+
*/
268+
bool skip_intermediate_wm;
263269
};
264270

265271
struct intel_plane_state {
@@ -510,13 +516,29 @@ struct intel_crtc_state {
510516

511517
struct {
512518
/*
513-
* optimal watermarks, programmed post-vblank when this state
514-
* is committed
519+
* Optimal watermarks, programmed post-vblank when this state
520+
* is committed.
515521
*/
516522
union {
517523
struct intel_pipe_wm ilk;
518524
struct skl_pipe_wm skl;
519525
} optimal;
526+
527+
/*
528+
* Intermediate watermarks; these can be programmed immediately
529+
* since they satisfy both the current configuration we're
530+
* switching away from and the new configuration we're switching
531+
* to.
532+
*/
533+
struct intel_pipe_wm intermediate;
534+
535+
/*
536+
* Platforms with two-step watermark programming will need to
537+
* update watermark programming post-vblank to switch from the
538+
* safe intermediate watermarks to the optimal final
539+
* watermarks.
540+
*/
541+
bool need_postvbl_update;
520542
} wm;
521543
};
522544

@@ -600,6 +622,7 @@ struct intel_crtc {
600622
struct intel_pipe_wm ilk;
601623
struct skl_pipe_wm skl;
602624
} active;
625+
603626
/* allow CxSR on this pipe */
604627
bool cxsr_allowed;
605628
} wm;
@@ -1565,6 +1588,7 @@ void skl_wm_get_hw_state(struct drm_device *dev);
15651588
void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
15661589
struct skl_ddb_allocation *ddb /* out */);
15671590
uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config);
1591+
bool ilk_disable_lp_wm(struct drm_device *dev);
15681592
int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6);
15691593

15701594
/* intel_sdvo.c */

0 commit comments

Comments
 (0)