[PATCH v2 1/6] drm/i915: Calculate gen3- watermarks semi-atomically, v3.

Maarten Lankhorst
2017-09-13T08:40:30Z

The gen3 watermark calculations are converted to atomic,
but the wm update calls are still done through the legacy
functions.

This will make it easier to bisect things if they go wrong.

CI was having issues on the kms_cursor_legacy tests with too
much debug info printed out, in order to reduce the chattiness
we will kill the prints from intel_calculate_wm.

Changes since v1:
- Neuter intel_calculate_wm spam.
Changes since v2:
- Calculate plane_wm for gen2 correctly. (Mahesh)
- Small fixes from review feedback. (Mahesh)

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---
drivers/gpu/drm/i915/intel_display.c | 3 +-
drivers/gpu/drm/i915/intel_drv.h | 15 +++
drivers/gpu/drm/i915/intel_pm.c | 237 ++++++++++++++++++++---------------
3 files changed, 156 insertions(+), 99 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 524217d6292e..f0e5ab2ac2ee 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -15153,7 +15153,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
skl_wm_get_hw_state(dev);
} else if (HAS_PCH_SPLIT(dev_priv)) {
ilk_wm_get_hw_state(dev);
- }
+ } else if (INTEL_GEN(dev_priv) <= 3 && !IS_PINEVIEW(dev_priv))
+ i9xx_wm_get_hw_state(dev);

for_each_intel_crtc(dev, crtc) {
u64 put_domains;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 307807672896..78554f23e264 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -549,6 +549,15 @@ struct g4x_wm_state {
bool fbc_en;
};

+struct i9xx_wm_state {
+ uint16_t plane_wm;
+ bool cxsr;
+
+ struct {
+ uint16_t plane_wm;
+ } sr;
+};
+
struct intel_crtc_wm_state {
union {
struct {
@@ -593,6 +602,10 @@ struct intel_crtc_wm_state {
/* optimal watermarks */
struct g4x_wm_state optimal;
} g4x;
+
+ struct {
+ struct i9xx_wm_state optimal;
+ } i9xx;
};

/*
@@ -826,6 +839,7 @@ struct intel_crtc {
struct intel_pipe_wm ilk;
struct vlv_wm_state vlv;
struct g4x_wm_state g4x;
+ struct i9xx_wm_state i9xx;
} active;
} wm;

@@ -1877,6 +1891,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv);
void gen6_rps_boost(struct drm_i915_gem_request *rq,
struct intel_rps_client *rps);
void g4x_wm_get_hw_state(struct drm_device *dev);
+void i9xx_wm_get_hw_state(struct drm_device *dev);
void vlv_wm_get_hw_state(struct drm_device *dev);
void ilk_wm_get_hw_state(struct drm_device *dev);
void skl_wm_get_hw_state(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index fa9055a4f790..6f7be0a2be05 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -771,10 +771,8 @@ static unsigned int intel_calculate_wm(int pixel_rate,
latency_ns / 100);
entries = DIV_ROUND_UP(entries, wm->cacheline_size) +
wm->guard_size;
- DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries);

wm_size = fifo_size - entries;
- DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);

/* Don't promote wm_size to unsigned... */
if (wm_size > wm->max_wm)
@@ -2244,89 +2242,156 @@ static void i965_update_wm(struct intel_crtc *unused_crtc)

#undef FW_WM

-static void i9xx_update_wm(struct intel_crtc *unused_crtc)
+static const struct intel_watermark_params *i9xx_get_wm_info(struct drm_i915_private *dev_priv,
+ struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
- const struct intel_watermark_params *wm_info;
- uint32_t fwater_lo;
- uint32_t fwater_hi;
- int cwm, srwm = 1;
- int fifo_size;
- int planea_wm, planeb_wm;
- struct intel_crtc *crtc, *enabled = NULL;
+ struct intel_plane *plane = to_intel_plane(crtc->base.primary);

if (IS_I945GM(dev_priv))
- wm_info = &i945_wm_info;
+ return &i945_wm_info;
else if (!IS_GEN2(dev_priv))
- wm_info = &i915_wm_info;
+ return &i915_wm_info;
+ else if (plane->plane == PLANE_A)
+ return &i830_a_wm_info;
else
- wm_info = &i830_a_wm_info;
+ return &i830_bc_wm_info;
+}

- fifo_size = dev_priv->display.get_fifo_size(dev_priv, 0);
- crtc = intel_get_crtc_for_plane(dev_priv, 0);
- if (intel_crtc_active(crtc)) {
- const struct drm_display_mode *adjusted_mode =
- &crtc->config->base.adjusted_mode;
- const struct drm_framebuffer *fb =
- crtc->base.primary->state->fb;
- int cpp;
+static int i9xx_compute_pipe_wm(struct intel_crtc_state *crtc_state)
+{
+ struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct intel_atomic_state *state =
+ to_intel_atomic_state(crtc_state->base.state);
+ struct i9xx_wm_state *wm_state = &crtc_state->wm.i9xx.optimal;
+ struct intel_plane *plane = to_intel_plane(crtc->base.primary);
+ const struct drm_plane_state *plane_state = NULL;
+ int fifo_size;
+ const struct intel_watermark_params *wm_info;

- if (IS_GEN2(dev_priv))
- cpp = 4;
- else
- cpp = fb->format->cpp[0];
+ fifo_size = dev_priv->display.get_fifo_size(dev_priv, plane->plane);

- planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
- wm_info, fifo_size, cpp,
- pessimal_latency_ns);
- enabled = crtc;
+ wm_info = i9xx_get_wm_info(dev_priv, crtc);
+
+ wm_state->cxsr = false;
+ memset(&wm_state->sr, 0, sizeof(wm_state->sr));
+
+ if (crtc_state->base.plane_mask & BIT(drm_plane_index(&plane->base)))
+ plane_state = __drm_atomic_get_current_plane_state(&state->base, &plane->base);
+
+ if (!plane_state || !intel_wm_plane_visible(crtc_state, to_intel_plane_state(plane_state))) {
+ wm_state->plane_wm = fifo_size - wm_info->guard_size;
+ if (wm_state->plane_wm > (long)wm_info->max_wm)
+ wm_state->plane_wm = wm_info->max_wm;
} else {
- planea_wm = fifo_size - wm_info->guard_size;
- if (planea_wm > (long)wm_info->max_wm)
- planea_wm = wm_info->max_wm;
+ struct drm_framebuffer *fb = plane_state->fb;
+ unsigned cpp = IS_GEN2(dev_priv) ? 4 : fb->format->cpp[0];
+ const struct drm_display_mode *adjusted_mode =
+ &crtc_state->base.adjusted_mode;
+ unsigned active_crtcs;
+ bool may_cxsr = false;
+
+ if (HAS_FW_BLC(dev_priv)) {
+ if (state->modeset)
+ active_crtcs = state->active_crtcs;
+ else
+ active_crtcs = dev_priv->active_crtcs;
+
+ /* CxSR can only be enabled when a single CRTC is enabled. */
+ may_cxsr = active_crtcs == drm_crtc_mask(&crtc->base);
+
+ if (IS_I915GM(dev_priv) && i915_gem_object_is_tiled(intel_fb_obj(fb)))
+ may_cxsr = false;
+ }
+
+ wm_state->plane_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
+ wm_info, fifo_size, cpp,
+ pessimal_latency_ns);
+
+ DRM_DEBUG_KMS("FIFO watermarks - plane watermarks: %d\n", wm_state->plane_wm);
+
+ if (may_cxsr) {
+ static const int sr_latency_ns = 6000;
+ unsigned long entries;
+
+ entries = intel_wm_method2(adjusted_mode->crtc_clock,
+ adjusted_mode->crtc_htotal,
+ crtc_state->pipe_src_w, cpp,
+ sr_latency_ns / 100);
+ entries = DIV_ROUND_UP(entries, wm_info->cacheline_size);
+
+ DRM_DEBUG_KMS("self-refresh entries: %ld\n", entries);
+
+ if (wm_info->fifo_size >= entries) {
+ wm_state->cxsr = true;
+ wm_state->sr.plane_wm = wm_info->fifo_size - entries;
+ }
+ }
+
+ DRM_DEBUG_KMS("FIFO watermarks - plane watermarks: %d, can cxsr: %s, SR size: %d\n",
+ wm_state->plane_wm, yesno(wm_state->cxsr), wm_state->sr.plane_wm);
}

- if (IS_GEN2(dev_priv))
- wm_info = &i830_bc_wm_info;
+ return 0;
+}

- fifo_size = dev_priv->display.get_fifo_size(dev_priv, 1);
- crtc = intel_get_crtc_for_plane(dev_priv, 1);
- if (intel_crtc_active(crtc)) {
- const struct drm_display_mode *adjusted_mode =
- &crtc->config->base.adjusted_mode;
- const struct drm_framebuffer *fb =
- crtc->base.primary->state->fb;
- int cpp;
+void i9xx_wm_get_hw_state(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct intel_crtc *crtc;
+ uint32_t fwater_lo, planea_wm, planeb_wm;
+
+ fwater_lo = I915_READ(FW_BLC);
+
+ planea_wm = fwater_lo & 0x3f;
+ planeb_wm = (fwater_lo >> 16) & 0x3f;
+
+ for_each_intel_crtc(dev, crtc) {
+ struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->base.state);
+ struct i9xx_wm_state *wm_state = &cstate->wm.i9xx.optimal;
+ struct intel_plane *plane = to_intel_plane(crtc->base.primary);
+
+ memset(&wm_state->sr, 0, sizeof(wm_state->sr));
+ wm_state->cxsr = false;

- if (IS_GEN2(dev_priv))
- cpp = 4;
+ if (plane->plane == PLANE_A)
+ wm_state->plane_wm = planea_wm;
else
- cpp = fb->format->cpp[0];
+ wm_state->plane_wm = planeb_wm;
+
+ crtc->wm.active.i9xx = *wm_state;
+ }
+}

- planeb_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
- wm_info, fifo_size, cpp,
- pessimal_latency_ns);
+static void i9xx_update_wm(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ uint32_t fwater_lo;
+ uint32_t fwater_hi;
+ int cwm, srwm = -1;
+ int planea_wm, planeb_wm;
+ struct intel_crtc *enabled = NULL;
+
+ crtc->wm.active.i9xx = crtc->config->wm.i9xx.optimal;
+
+ crtc = intel_get_crtc_for_plane(dev_priv, 0);
+ planea_wm = crtc->wm.active.i9xx.plane_wm;
+ if (intel_crtc_active(crtc))
+ enabled = crtc;
+
+ crtc = intel_get_crtc_for_plane(dev_priv, 1);
+ if (intel_crtc_active(crtc)) {
if (enabled == NULL)
enabled = crtc;
else
enabled = NULL;
- } else {
- planeb_wm = fifo_size - wm_info->guard_size;
- if (planeb_wm > (long)wm_info->max_wm)
- planeb_wm = wm_info->max_wm;
}
+ planeb_wm = crtc->wm.active.i9xx.plane_wm;

DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);

- if (IS_I915GM(dev_priv) && enabled) {
- struct drm_i915_gem_object *obj;
-
- obj = intel_fb_obj(enabled->base.primary->state->fb);
-
- /* self-refresh seems busted with untiled */
- if (!i915_gem_object_is_tiled(obj))
- enabled = NULL;
- }
+ if (!enabled->wm.active.i9xx.cxsr)
+ enabled = NULL;

/*
* Overlay gets an aggressive default since video jitter is bad.
@@ -2337,31 +2402,8 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
intel_set_memory_cxsr(dev_priv, false);

/* Calc sr entries for one plane configs */
- if (HAS_FW_BLC(dev_priv) && enabled) {
- /* self-refresh has much higher latency */
- static const int sr_latency_ns = 6000;
- const struct drm_display_mode *adjusted_mode =
- &enabled->config->base.adjusted_mode;
- const struct drm_framebuffer *fb =
- enabled->base.primary->state->fb;
- int clock = adjusted_mode->crtc_clock;
- int htotal = adjusted_mode->crtc_htotal;
- int hdisplay = enabled->config->pipe_src_w;
- int cpp;
- int entries;
-
- if (IS_I915GM(dev_priv) || IS_I945GM(dev_priv))
- cpp = 4;
- else
- cpp = fb->format->cpp[0];
-
- entries = intel_wm_method2(clock, htotal, hdisplay, cpp,
- sr_latency_ns / 100);
- entries = DIV_ROUND_UP(entries, wm_info->cacheline_size);
- DRM_DEBUG_KMS("self-refresh entries: %d\n", entries);
- srwm = wm_info->fifo_size - entries;
- if (srwm < 0)
- srwm = 1;
+ if (enabled && enabled->wm.active.i9xx.cxsr) {
+ srwm = enabled->wm.active.i9xx.sr.plane_wm;

if (IS_I945G(dev_priv) || IS_I945GM(dev_priv))
I915_WRITE(FW_BLC_SELF,
@@ -2387,23 +2429,18 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
intel_set_memory_cxsr(dev_priv, true);
}

-static void i845_update_wm(struct intel_crtc *unused_crtc)
+static void i845_update_wm(struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
- struct intel_crtc *crtc;
- const struct drm_display_mode *adjusted_mode;
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
uint32_t fwater_lo;
int planea_wm;

- crtc = single_enabled_crtc(dev_priv);
- if (crtc == NULL)
+ if (!intel_crtc_active(crtc))
return;

- adjusted_mode = &crtc->config->base.adjusted_mode;
- planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
- &i845_wm_info,
- dev_priv->display.get_fifo_size(dev_priv, 0),
- 4, pessimal_latency_ns);
+ crtc->wm.active.i9xx = crtc->config->wm.i9xx.optimal;
+ planea_wm = crtc->wm.active.i9xx.plane_wm;
+
fwater_lo = I915_READ(FW_BLC) & ~0xfff;
fwater_lo |= (3<<8) | planea_wm;

@@ -9003,9 +9040,13 @@ void intel_init_pm(struct drm_i915_private *dev_priv)
} else if (IS_GEN4(dev_priv)) {
dev_priv->display.update_wm = i965_update_wm;
} else if (IS_GEN3(dev_priv)) {
+ dev_priv->display.compute_pipe_wm = i9xx_compute_pipe_wm;
dev_priv->display.update_wm = i9xx_update_wm;
+
dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
} else if (IS_GEN2(dev_priv)) {
+ dev_priv->display.compute_pipe_wm = i9xx_compute_pipe_wm;
+
if (INTEL_INFO(dev_priv)->num_pipes == 1) {
dev_priv->display.update_wm = i845_update_wm;
dev_priv->display.get_fifo_size = i845_get_fifo_size;