drm/i915: Calculate watermark configuration during atomic check (v2)

v2: Don't forget to actually check the cstate->active value when
    tallying up the number of active CRTC's.  (Ander)

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Smoke-tested-by: Paulo Zanoni <przanoni@gmail.com>
Link: http://patchwork.freedesktop.org/patch/59561/
This commit is contained in:
Matt Roper 2015-09-24 15:53:18 -07:00
parent 19b8d3875e
commit aa36313686
4 changed files with 72 additions and 55 deletions

View File

@ -1692,6 +1692,13 @@ struct i915_execbuffer_params {
struct drm_i915_gem_request *request;
};
/* used in computing the new watermarks state */
struct intel_wm_config {
unsigned int num_pipes_active;
bool sprites_enabled;
bool sprites_scaled;
};
struct drm_i915_private {
struct drm_device *dev;
struct kmem_cache *objects;
@ -1917,6 +1924,9 @@ struct drm_i915_private {
*/
uint16_t skl_latency[8];
/* Committed wm config */
struct intel_wm_config config;
/*
* The skl_wm_values structure is a bit too big for stack
* allocation, so we keep the staging struct where we store

View File

@ -13050,6 +13050,45 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
return 0;
}
/*
* Handle calculation of various watermark data at the end of the atomic check
* phase. The code here should be run after the per-crtc and per-plane 'check'
* handlers to ensure that all derived state has been updated.
*/
static void calc_watermark_data(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct drm_crtc *crtc;
struct drm_crtc_state *cstate;
struct drm_plane *plane;
struct drm_plane_state *pstate;
/*
* Calculate watermark configuration details now that derived
* plane/crtc state is all properly updated.
*/
drm_for_each_crtc(crtc, dev) {
cstate = drm_atomic_get_existing_crtc_state(state, crtc) ?:
crtc->state;
if (cstate->active)
intel_state->wm_config.num_pipes_active++;
}
drm_for_each_legacy_plane(plane, dev) {
pstate = drm_atomic_get_existing_plane_state(state, plane) ?:
plane->state;
if (!to_intel_plane_state(pstate)->visible)
continue;
intel_state->wm_config.sprites_enabled = true;
if (pstate->crtc_w != pstate->src_w >> 16 ||
pstate->crtc_h != pstate->src_h >> 16)
intel_state->wm_config.sprites_scaled = true;
}
}
/**
* intel_atomic_check - validate state object
* @dev: drm device
@ -13058,6 +13097,7 @@ static int intel_modeset_checks(struct drm_atomic_state *state)
static int intel_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
int ret, i;
@ -13121,10 +13161,15 @@ static int intel_atomic_check(struct drm_device *dev,
if (ret)
return ret;
} else
to_intel_atomic_state(state)->cdclk =
to_i915(state->dev)->cdclk_freq;
intel_state->cdclk = to_i915(state->dev)->cdclk_freq;
return drm_atomic_helper_check_planes(state->dev, state);
ret = drm_atomic_helper_check_planes(state->dev, state);
if (ret)
return ret;
calc_watermark_data(state);
return 0;
}
/**
@ -13164,6 +13209,7 @@ static int intel_atomic_commit(struct drm_device *dev,
return ret;
drm_atomic_helper_swap_state(dev, state);
dev_priv->wm.config = to_intel_atomic_state(state)->wm_config;
for_each_crtc_in_state(state, crtc, crtc_state, i) {
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);

View File

@ -250,6 +250,7 @@ struct intel_atomic_state {
unsigned int cdclk;
bool dpll_set;
struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS];
struct intel_wm_config wm_config;
};
struct intel_plane_state {

View File

@ -1715,13 +1715,6 @@ struct ilk_wm_maximums {
uint16_t fbc;
};
/* used in computing the new watermarks state */
struct intel_wm_config {
unsigned int num_pipes_active;
bool sprites_enabled;
bool sprites_scaled;
};
/*
* For both WM_PIPE and WM_LP.
* mem_value must be in 0.1us units.
@ -2251,24 +2244,6 @@ static void skl_setup_wm_latency(struct drm_device *dev)
intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency);
}
static void ilk_compute_wm_config(struct drm_device *dev,
struct intel_wm_config *config)
{
struct intel_crtc *intel_crtc;
/* Compute the currently _active_ config */
for_each_intel_crtc(dev, intel_crtc) {
const struct intel_pipe_wm *wm = &intel_crtc->wm.active.ilk;
if (!wm->pipe_enabled)
continue;
config->sprites_enabled |= wm->sprites_enabled;
config->sprites_scaled |= wm->sprites_scaled;
config->num_pipes_active++;
}
}
/* Compute new watermarks for the pipe */
static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
struct drm_atomic_state *state)
@ -2917,11 +2892,12 @@ skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate)
static void
skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
const struct intel_wm_config *config,
struct skl_ddb_allocation *ddb /* out */)
{
struct drm_crtc *crtc = cstate->base.crtc;
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_wm_config *config = &dev_priv->wm.config;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_plane *intel_plane;
enum pipe pipe = intel_crtc->pipe;
@ -3096,15 +3072,6 @@ static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb,
return false;
}
static void skl_compute_wm_global_parameters(struct drm_device *dev,
struct intel_wm_config *config)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
config->num_pipes_active += to_intel_crtc(crtc)->active;
}
static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
struct intel_crtc_state *cstate,
struct intel_plane *intel_plane,
@ -3507,14 +3474,13 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
}
static bool skl_update_pipe_wm(struct drm_crtc *crtc,
struct intel_wm_config *config,
struct skl_ddb_allocation *ddb, /* out */
struct skl_pipe_wm *pipe_wm /* out */)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
skl_allocate_pipe_ddb(cstate, config, ddb);
skl_allocate_pipe_ddb(cstate, ddb);
skl_compute_pipe_wm(cstate, ddb, pipe_wm);
if (!memcmp(&intel_crtc->wm.active.skl, pipe_wm, sizeof(*pipe_wm)))
@ -3527,7 +3493,6 @@ static bool skl_update_pipe_wm(struct drm_crtc *crtc,
static void skl_update_other_pipe_wm(struct drm_device *dev,
struct drm_crtc *crtc,
struct intel_wm_config *config,
struct skl_wm_values *r)
{
struct intel_crtc *intel_crtc;
@ -3557,7 +3522,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev,
if (!intel_crtc->active)
continue;
wm_changed = skl_update_pipe_wm(&intel_crtc->base, config,
wm_changed = skl_update_pipe_wm(&intel_crtc->base,
&r->ddb, &pipe_wm);
/*
@ -3600,7 +3565,6 @@ static void skl_update_wm(struct drm_crtc *crtc)
struct skl_wm_values *results = &dev_priv->wm.skl_results;
struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
struct skl_pipe_wm *pipe_wm = &cstate->wm.optimal.skl;
struct intel_wm_config config = {};
/* Clear all dirty flags */
@ -3608,15 +3572,13 @@ static void skl_update_wm(struct drm_crtc *crtc)
skl_clear_wm(results, intel_crtc->pipe);
skl_compute_wm_global_parameters(dev, &config);
if (!skl_update_pipe_wm(crtc, &config, &results->ddb, pipe_wm))
if (!skl_update_pipe_wm(crtc, &results->ddb, pipe_wm))
return;
skl_compute_wm_results(dev, pipe_wm, results, intel_crtc);
results->dirty[intel_crtc->pipe] = true;
skl_update_other_pipe_wm(dev, crtc, &config, results);
skl_update_other_pipe_wm(dev, crtc, results);
skl_write_wm_values(dev_priv, results);
skl_flush_wm_values(dev_priv, results);
@ -3629,20 +3591,18 @@ static void ilk_program_watermarks(struct drm_i915_private *dev_priv)
struct drm_device *dev = dev_priv->dev;
struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
struct ilk_wm_maximums max;
struct intel_wm_config config = {};
struct intel_wm_config *config = &dev_priv->wm.config;
struct ilk_wm_values results = {};
enum intel_ddb_partitioning partitioning;
ilk_compute_wm_config(dev, &config);
ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max);
ilk_wm_merge(dev, &config, &max, &lp_wm_1_2);
ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_1_2, &max);
ilk_wm_merge(dev, config, &max, &lp_wm_1_2);
/* 5/6 split only in single pipe config on IVB+ */
if (INTEL_INFO(dev)->gen >= 7 &&
config.num_pipes_active == 1 && config.sprites_enabled) {
ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max);
ilk_wm_merge(dev, &config, &max, &lp_wm_5_6);
config->num_pipes_active == 1 && config->sprites_enabled) {
ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_5_6, &max);
ilk_wm_merge(dev, config, &max, &lp_wm_5_6);
best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6);
} else {