Op 03-05-2019 om 21:08 schreef Ville Syrjala: > From: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > > ICL has so many planes that it can easily exceed the maximum > effective memory bandwidth of the system. We must therefore check > that we don't exceed that limit. > > The algorithm is very magic number heavy and lacks sufficient > explanation for now. We also have no sane way to query the > memory clock and timings, so we must rely on a combination of > raw readout from the memory controller and hardcoded assumptions. > The memory controller values obviously change as the system > jumps between the different SAGV points, so we try to stabilize > it first by disabling SAGV for the duration of the readout. > > The utilized bandwidth is tracked via a device wide atomic > private object. That is actually not robust because we can't > afford to enforce strict global ordering between the pipes. > Thus I think I'll need to change this to simply chop up the > available bandwidth between all the active pipes. Each pipe > can then do whatever it wants as long as it doesn't exceed > its budget. That scheme will also require that we assume that > any number of planes could be active at any time. > > TODO: make it robust and deal with all the open questions > > v2: Sleep longer after disabling SAGV > v3: Poll for the dclk to get raised (seen it take 250ms!) > If the system has 2133MT/s memory then we pointlessly > wait one full second :( > v4: Use the new pcode interface to get the qgv points rather > that using hardcoded numbers > > Signed-off-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > --- Splitting out the HW readout would be nice, it would make it easier to review the separate parts that this patch tries to accomplish. :) > drivers/gpu/drm/i915/Makefile | 1 + > drivers/gpu/drm/i915/i915_drv.c | 229 ++++++++++++++++++++++ > drivers/gpu/drm/i915/i915_drv.h | 10 + > drivers/gpu/drm/i915/i915_reg.h | 3 + > drivers/gpu/drm/i915/intel_atomic_plane.c | 20 ++ > drivers/gpu/drm/i915/intel_atomic_plane.h | 2 + > drivers/gpu/drm/i915/intel_bw.c | 181 +++++++++++++++++ > drivers/gpu/drm/i915/intel_bw.h | 46 +++++ > drivers/gpu/drm/i915/intel_display.c | 40 +++- > drivers/gpu/drm/i915/intel_drv.h | 2 + > 10 files changed, 533 insertions(+), 1 deletion(-) > create mode 100644 drivers/gpu/drm/i915/intel_bw.c > create mode 100644 drivers/gpu/drm/i915/intel_bw.h > > diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile > index 68106fe35a04..139a0fc19390 100644 > --- a/drivers/gpu/drm/i915/Makefile > +++ b/drivers/gpu/drm/i915/Makefile > @@ -138,6 +138,7 @@ i915-y += intel_audio.o \ > intel_atomic.o \ > intel_atomic_plane.o \ > intel_bios.o \ > + intel_bw.o \ > intel_cdclk.o \ > intel_color.o \ > intel_combo_phy.o \ > diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c > index 5ed864752c7b..b7fa7b51c2e2 100644 > --- a/drivers/gpu/drm/i915/i915_drv.c > +++ b/drivers/gpu/drm/i915/i915_drv.c > @@ -70,6 +70,7 @@ > #include "intel_overlay.h" > #include "intel_pipe_crc.h" > #include "intel_pm.h" > +#include "intel_sideband.h" > #include "intel_sprite.h" > #include "intel_uc.h" > > @@ -1435,6 +1436,232 @@ bxt_get_dram_info(struct drm_i915_private *dev_priv) > return 0; > } > > +struct intel_qgv_point { > + u16 dclk, t_rp, t_rdpre, t_rc, t_ras, t_rcd; > +}; > + > +struct intel_sagv_info { > + struct intel_qgv_point points[3]; > + u8 num_points; > + u8 num_channels; > + u8 t_bl; > + enum intel_dram_type dram_type; > +}; > + > +static int icl_pcode_read_mem_global_info(struct drm_i915_private *dev_priv, > + struct intel_sagv_info *si) > +{ > + u32 val = 0; > + int ret; > + > + ret = sandybridge_pcode_read(dev_priv, > + ICL_PCODE_MEM_SUBSYSYSTEM_INFO | > + ICL_PCODE_MEM_SS_READ_GLOBAL_INFO, > + &val, NULL); > + if (ret) > + return ret; > + > + switch (val & 0xf) { > + case 0: > + si->dram_type = INTEL_DRAM_DDR4; > + break; > + case 1: > + si->dram_type = INTEL_DRAM_DDR3; > + break; > + case 2: > + si->dram_type = INTEL_DRAM_LPDDR3; > + break; > + case 3: > + si->dram_type = INTEL_DRAM_LPDDR3; > + break; > + default: > + MISSING_CASE(val & 0xf); > + break; > + } > + > + si->num_channels = (val & 0xf0) >> 4; > + si->num_points = (val & 0xf00) >> 8; > + > + si->t_bl = si->dram_type == INTEL_DRAM_DDR4 ? 4 : 8; > + > + return 0; > +} > + > +static int icl_pcode_read_qgv_point_info(struct drm_i915_private *dev_priv, > + struct intel_qgv_point *sp, > + int point) > +{ > + u32 val = 0, val2; > + int ret; > + > + ret = sandybridge_pcode_read(dev_priv, > + ICL_PCODE_MEM_SUBSYSYSTEM_INFO | > + ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point), > + &val, &val2); > + if (ret) > + return ret; > + > + sp->dclk = val & 0xffff; > + sp->t_rp = (val & 0xff0000) >> 16; > + sp->t_rcd = (val & 0xff000000) >> 24; > + > + sp->t_rdpre = val2 & 0xff; > + sp->t_ras = (val2 & 0xff00) >> 8; > + > + sp->t_rc = sp->t_rp + sp->t_ras; > + > + return 0; > +} > + > +static int icl_get_qgv_points(struct drm_i915_private *dev_priv, > + struct intel_sagv_info *si) > +{ > + int i, ret; > + > + ret = icl_pcode_read_mem_global_info(dev_priv, si); > + if (ret) > + return ret; > + > + if (WARN_ON(si->num_points > ARRAY_SIZE(si->points))) > + si->num_points = ARRAY_SIZE(si->points); > + > + for (i = 0; i < si->num_points; i++) { > + struct intel_qgv_point *sp = &si->points[i]; > + > + ret = icl_pcode_read_qgv_point_info(dev_priv, sp, i); > + if (ret) > + return ret; > + > + DRM_DEBUG_KMS("QGV %d: DCLK=%d tRP=%d tRDPRE=%d tRAS=%d tRCD=%d tRC=%d\n", > + i, sp->dclk, sp->t_rp, sp->t_rdpre, sp->t_ras, > + sp->t_rcd, sp->t_rc); > + } > + > + return 0; > +} > + > +static int icl_calc_bw(int dclk, int num, int den) > +{ > + /* multiples of 16.666MHz (100/6) */ > + return DIV_ROUND_CLOSEST(num * dclk * 100, den * 6); > +} > + > +static int icl_sagv_max_dclk(const struct intel_sagv_info *si) > +{ > + u16 dclk = 0; > + int i; > + > + for (i = 0; i < si->num_points; i++) > + dclk = max(dclk, si->points[i].dclk); > + > + return dclk; > +} > + > +struct intel_sa_info { > + u8 deburst, mpagesize, deprogbwlimit, displayrtids; > +}; > + > +static const struct intel_sa_info icl_sa_info = { > + .deburst = 8, > + .mpagesize = 16, > + .deprogbwlimit = 25, /* GB/s */ > + .displayrtids = 128, > +}; > + > +static int icl_get_bw_info(struct drm_i915_private *dev_priv) > +{ > + struct intel_sagv_info si = {}; > + const struct intel_sa_info *sa = &icl_sa_info; > + bool is_y_tile = true; /* assume y tile may be used */ > + int num_channels; > + int deinterleave; > + int ipqdepth, ipqdepthpch; > + int dclk_max; > + int maxdebw; > + int i, ret; > + > + ret = icl_get_qgv_points(dev_priv, &si); > + if (ret) > + return ret; > + num_channels = si.num_channels; > + > + deinterleave = DIV_ROUND_UP(num_channels, is_y_tile ? 4 : 2); > + dclk_max = icl_sagv_max_dclk(&si); > + > + ipqdepthpch = 16; > + > + maxdebw = min(sa->deprogbwlimit * 1000, > + icl_calc_bw(dclk_max, 16, 1) * 6 / 10); /* 60% */ > + ipqdepth = min(ipqdepthpch, sa->displayrtids / num_channels); > + > + for (i = 0; i < ARRAY_SIZE(dev_priv->max_bw); i++) { > + struct intel_bw_info *bi = &dev_priv->max_bw[i]; > + int clpchgroup; > + int j; > + > + clpchgroup = (sa->deburst * deinterleave / num_channels) << i; > + bi->num_planes = (ipqdepth - clpchgroup) / clpchgroup + 1; > + > + for (j = 0; j < si.num_points; j++) { > + const struct intel_qgv_point *sp = &si.points[j]; > + int ct, bw; > + > + /* > + * Max row cycle time > + * > + * FIXME what is the logic behind the > + * assumed burst length? > + */ > + ct = max_t(int, sp->t_rc, sp->t_rp + sp->t_rcd + > + (clpchgroup - 1) * si.t_bl + sp->t_rdpre); > + bw = icl_calc_bw(sp->dclk, clpchgroup * 32 * num_channels, ct); > + > + bi->deratedbw[j] = min(maxdebw, > + bw * 9 / 10); /* 90% */ > + > + DRM_DEBUG_KMS("BW%d / QGV %d: num_planes=%d deratedbw=%d\n", > + i, j, bi->num_planes, bi->deratedbw[j]); > + } > + > + if (bi->num_planes == 1) > + break; > + } > + > + return 0; > +} > + > +static unsigned int icl_max_bw(struct drm_i915_private *dev_priv, > + int num_planes, int qgv_point) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(dev_priv->max_bw); i++) { > + const struct intel_bw_info *bi = > + &dev_priv->max_bw[i]; > + > + if (num_planes >= bi->num_planes) > + return bi->deratedbw[qgv_point]; > + } > + > + return 0; > +} > + > +unsigned int intel_max_data_rate(struct drm_i915_private *dev_priv, > + int num_planes) > +{ > + if (IS_ICELAKE(dev_priv)) > + /* > + * FIXME with SAGV disabled maybe we can assume > + * point 1 will always be used? Seems to match > + * the behaviour observed in the wild. > + */ > + return min3(icl_max_bw(dev_priv, num_planes, 0), > + icl_max_bw(dev_priv, num_planes, 1), > + icl_max_bw(dev_priv, num_planes, 2)); > + else > + return UINT_MAX; > +} > + > static void > intel_get_dram_info(struct drm_i915_private *dev_priv) > { > @@ -1655,6 +1882,8 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv) > */ > intel_get_dram_info(dev_priv); > > + if (INTEL_GEN(dev_priv) >= 11) > + icl_get_bw_info(dev_priv); > > return 0; > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 64fa353a62bb..d1b9c3fe5802 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -54,6 +54,7 @@ > #include <drm/drm_cache.h> > #include <drm/drm_util.h> > #include <drm/drm_dsc.h> > +#include <drm/drm_atomic.h> > #include <drm/drm_connector.h> > #include <drm/i915_mei_hdcp_interface.h> > > @@ -1837,6 +1838,13 @@ struct drm_i915_private { > } type; > } dram_info; > > + struct intel_bw_info { > + int num_planes; > + int deratedbw[3]; > + } max_bw[6]; > + > + struct drm_private_obj bw_obj; > + > struct i915_runtime_pm runtime_pm; > > struct { > @@ -2706,6 +2714,8 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); > extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); > extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); > int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on); > +unsigned int intel_max_data_rate(struct drm_i915_private *dev_priv, > + int num_planes); > > u32 intel_calculate_mcr_s_ss_select(struct drm_i915_private *dev_priv); > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index e97c47fca645..399366a41524 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -8774,6 +8774,9 @@ enum { > #define GEN6_PCODE_WRITE_MIN_FREQ_TABLE 0x8 > #define GEN6_PCODE_READ_MIN_FREQ_TABLE 0x9 > #define GEN6_READ_OC_PARAMS 0xc > +#define ICL_PCODE_MEM_SUBSYSYSTEM_INFO 0xd > +#define ICL_PCODE_MEM_SS_READ_GLOBAL_INFO (0x0 << 8) > +#define ICL_PCODE_MEM_SS_READ_QGV_POINT_INFO(point) (((point) << 16) | (0x1 << 8)) > #define GEN6_PCODE_READ_D_COMP 0x10 > #define GEN6_PCODE_WRITE_D_COMP 0x11 > #define HSW_PCODE_DE_WRITE_FREQ_REQ 0x17 > diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c > index d11681d71add..f142c5c22d7e 100644 > --- a/drivers/gpu/drm/i915/intel_atomic_plane.c > +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c > @@ -114,6 +114,22 @@ intel_plane_destroy_state(struct drm_plane *plane, > drm_atomic_helper_plane_destroy_state(plane, state); > } > > +unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state, > + const struct intel_plane_state *plane_state) > +{ > + const struct drm_framebuffer *fb = plane_state->base.fb; > + unsigned int cpp = 0; > + int i; > + > + if (!plane_state->base.visible) > + return 0; > + > + for (i = 0; i < fb->format->num_planes; i++) > + cpp += fb->format->cpp[i]; > + > + return cpp * crtc_state->pixel_rate; > +} > + > int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state, > struct intel_crtc_state *new_crtc_state, > const struct intel_plane_state *old_plane_state, > @@ -125,6 +141,7 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_ > new_crtc_state->active_planes &= ~BIT(plane->id); > new_crtc_state->nv12_planes &= ~BIT(plane->id); > new_crtc_state->c8_planes &= ~BIT(plane->id); > + new_crtc_state->data_rate[plane->id] = 0; > new_plane_state->base.visible = false; > > if (!new_plane_state->base.crtc && !old_plane_state->base.crtc) > @@ -149,6 +166,9 @@ int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_ > if (new_plane_state->base.visible || old_plane_state->base.visible) > new_crtc_state->update_planes |= BIT(plane->id); > > + new_crtc_state->data_rate[plane->id] = > + intel_plane_data_rate(new_crtc_state, new_plane_state); > + > return intel_plane_atomic_calc_changes(old_crtc_state, > &new_crtc_state->base, > old_plane_state, > diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.h b/drivers/gpu/drm/i915/intel_atomic_plane.h > index 14678620440f..0a9651376d0e 100644 > --- a/drivers/gpu/drm/i915/intel_atomic_plane.h > +++ b/drivers/gpu/drm/i915/intel_atomic_plane.h > @@ -15,6 +15,8 @@ struct intel_plane_state; > > extern const struct drm_plane_helper_funcs intel_plane_helper_funcs; > > +unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state, > + const struct intel_plane_state *plane_state); > void intel_update_plane(struct intel_plane *plane, > const struct intel_crtc_state *crtc_state, > const struct intel_plane_state *plane_state); > diff --git a/drivers/gpu/drm/i915/intel_bw.c b/drivers/gpu/drm/i915/intel_bw.c > new file mode 100644 > index 000000000000..304bf87f0a2e > --- /dev/null > +++ b/drivers/gpu/drm/i915/intel_bw.c > @@ -0,0 +1,181 @@ > +// SPDX-License-Identifier: MIT > +/* > + * Copyright © 2019 Intel Corporation > + */ > + > +#include <drm/drm_atomic_state_helper.h> > + > +#include "intel_bw.h" > +#include "intel_drv.h" > + > +static unsigned int intel_bw_crtc_num_active_planes(const struct intel_crtc_state *crtc_state) > +{ > + /* > + * We assume cursors are small enough > + * to not not cause bandwidth problems. > + */ > + return hweight8(crtc_state->active_planes & ~BIT(PLANE_CURSOR)); > +} > + > +static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_state) > +{ > + struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); > + unsigned int data_rate = 0; > + enum plane_id plane_id; > + > + for_each_plane_id_on_crtc(crtc, plane_id) { > + /* > + * We assume cursors are small enough > + * to not not cause bandwidth problems. > + */ > + if (plane_id == PLANE_CURSOR) > + continue; > + > + data_rate += crtc_state->data_rate[plane_id]; > + } > + > + return data_rate; > +} > + > +void intel_bw_crtc_update(struct intel_bw_state *bw_state, > + const struct intel_crtc_state *crtc_state) > +{ > + struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); > + > + bw_state->data_rate[crtc->pipe] = > + intel_bw_crtc_data_rate(crtc_state); > + bw_state->num_active_planes[crtc->pipe] = > + intel_bw_crtc_num_active_planes(crtc_state); > + > + DRM_DEBUG_KMS("pipe %c data rate %u num active planes %u\n", > + pipe_name(crtc->pipe), > + bw_state->data_rate[crtc->pipe], > + bw_state->num_active_planes[crtc->pipe]); > +} > + > +static unsigned int intel_bw_num_active_planes(struct drm_i915_private *dev_priv, > + const struct intel_bw_state *bw_state) > +{ > + unsigned int num_active_planes = 0; > + enum pipe pipe; > + > + for_each_pipe(dev_priv, pipe) > + num_active_planes += bw_state->num_active_planes[pipe]; > + > + return num_active_planes; > +} > + > +static unsigned int intel_bw_data_rate(struct drm_i915_private *dev_priv, > + const struct intel_bw_state *bw_state) > +{ > + unsigned int data_rate = 0; > + enum pipe pipe; > + > + for_each_pipe(dev_priv, pipe) > + data_rate += bw_state->data_rate[pipe]; > + > + return data_rate; > +} > + > +int intel_bw_atomic_check(struct intel_atomic_state *state) > +{ > + struct drm_i915_private *dev_priv = to_i915(state->base.dev); > + struct intel_crtc_state *new_crtc_state, *old_crtc_state; > + struct intel_bw_state *bw_state = NULL; > + unsigned int data_rate, max_data_rate; > + unsigned int num_active_planes; > + struct intel_crtc *crtc; > + int i; > + > + /* FIXME earlier gens need some checks too */ > + if (INTEL_GEN(dev_priv) < 11) > + return 0; > + > + for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, > + new_crtc_state, i) { > + unsigned int old_data_rate = > + intel_bw_crtc_data_rate(old_crtc_state); > + unsigned int new_data_rate = > + intel_bw_crtc_data_rate(new_crtc_state); > + unsigned int old_active_planes = > + intel_bw_crtc_num_active_planes(old_crtc_state); > + unsigned int new_active_planes = > + intel_bw_crtc_num_active_planes(new_crtc_state); > + > + /* > + * Avoid locking the bw state when > + * nothing significant has changed. > + */ > + if (old_data_rate == new_data_rate && > + old_active_planes == new_active_planes) > + continue; > + > + bw_state = intel_atomic_get_bw_state(state); > + if (IS_ERR(bw_state)) > + return PTR_ERR(bw_state); > + > + bw_state->data_rate[crtc->pipe] = new_data_rate; > + bw_state->num_active_planes[crtc->pipe] = new_active_planes; > + > + DRM_DEBUG_KMS("pipe %c data rate %u num active planes %u\n", > + pipe_name(crtc->pipe), > + bw_state->data_rate[crtc->pipe], > + bw_state->num_active_planes[crtc->pipe]); > + } > + > + if (!bw_state) > + return 0; > + > + data_rate = intel_bw_data_rate(dev_priv, bw_state); > + num_active_planes = intel_bw_num_active_planes(dev_priv, bw_state); > + > + max_data_rate = intel_max_data_rate(dev_priv, num_active_planes); > + > + data_rate = DIV_ROUND_UP(data_rate, 1000); > + > + if (data_rate > max_data_rate) { > + DRM_DEBUG_KMS("Bandwidth %u MB/s exceeds max available %d MB/s (%d active planes)\n", > + data_rate, max_data_rate, num_active_planes); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static struct drm_private_state *intel_bw_duplicate_state(struct drm_private_obj *obj) > +{ > + struct intel_bw_state *state; > + > + state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); > + if (!state) > + return NULL; > + > + __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); > + > + return &state->base; > +} > + > +static void intel_bw_destroy_state(struct drm_private_obj *obj, > + struct drm_private_state *state) > +{ > + kfree(state); > +} > + > +static const struct drm_private_state_funcs intel_bw_funcs = { > + .atomic_duplicate_state = intel_bw_duplicate_state, > + .atomic_destroy_state = intel_bw_destroy_state, > +}; > + > +int intel_bw_init(struct drm_i915_private *dev_priv) > +{ > + struct intel_bw_state *state; > + > + state = kzalloc(sizeof(*state), GFP_KERNEL); > + if (!state) > + return -ENOMEM; > + > + drm_atomic_private_obj_init(&dev_priv->drm, &dev_priv->bw_obj, > + &state->base, &intel_bw_funcs); > + > + return 0; > +} > diff --git a/drivers/gpu/drm/i915/intel_bw.h b/drivers/gpu/drm/i915/intel_bw.h > new file mode 100644 > index 000000000000..c14272ca5b59 > --- /dev/null > +++ b/drivers/gpu/drm/i915/intel_bw.h > @@ -0,0 +1,46 @@ > +/* SPDX-License-Identifier: MIT */ > +/* > + * Copyright © 2019 Intel Corporation > + */ > + > +#ifndef __INTEL_BW_H__ > +#define __INTEL_BW_H__ > + > +#include <drm/drm_atomic.h> > + > +#include "i915_drv.h" > +#include "intel_display.h" > + > +struct drm_i915_private; > +struct intel_atomic_state; > +struct intel_crtc_state; > + > +struct intel_bw_state { > + struct drm_private_state base; > + > + unsigned int data_rate[I915_MAX_PIPES]; > + u8 num_active_planes[I915_MAX_PIPES]; > +}; > + > +#define to_intel_bw_state(x) container_of((x), struct intel_bw_state, base) > + > +static inline struct intel_bw_state * > +intel_atomic_get_bw_state(struct intel_atomic_state *state) > +{ > + struct drm_i915_private *dev_priv = to_i915(state->base.dev); > + struct drm_private_state *bw_state; > + > + bw_state = drm_atomic_get_private_obj_state(&state->base, > + &dev_priv->bw_obj); > + if (IS_ERR(bw_state)) > + return ERR_CAST(bw_state); > + > + return to_intel_bw_state(bw_state); > +} > + > +int intel_bw_init(struct drm_i915_private *dev_priv); > +int intel_bw_atomic_check(struct intel_atomic_state *state); > +void intel_bw_crtc_update(struct intel_bw_state *bw_state, > + const struct intel_crtc_state *crtc_state); > + > +#endif /* __INTEL_BW_H__ */ > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c > index d81ec80e34f6..a955840b73cb 100644 > --- a/drivers/gpu/drm/i915/intel_display.c > +++ b/drivers/gpu/drm/i915/intel_display.c > @@ -50,6 +50,7 @@ > #include "intel_acpi.h" > #include "intel_atomic.h" > #include "intel_atomic_plane.h" > +#include "intel_bw.h" > #include "intel_color.h" > #include "intel_cdclk.h" > #include "intel_crt.h" > @@ -2863,6 +2864,7 @@ static void intel_plane_disable_noatomic(struct intel_crtc *crtc, > > intel_set_plane_visible(crtc_state, plane_state, false); > fixup_active_planes(crtc_state); > + crtc_state->data_rate[plane->id] = 0; > > if (plane->id == PLANE_PRIMARY) > intel_pre_disable_primary_noatomic(&crtc->base); > @@ -6590,6 +6592,8 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc, > struct intel_encoder *encoder; > struct intel_crtc *intel_crtc = to_intel_crtc(crtc); > struct drm_i915_private *dev_priv = to_i915(crtc->dev); > + struct intel_bw_state *bw_state = > + to_intel_bw_state(dev_priv->bw_obj.state); > enum intel_display_power_domain domain; > struct intel_plane *plane; > u64 domains; > @@ -6652,6 +6656,9 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc, > dev_priv->active_crtcs &= ~(1 << intel_crtc->pipe); > dev_priv->min_cdclk[intel_crtc->pipe] = 0; > dev_priv->min_voltage_level[intel_crtc->pipe] = 0; > + > + bw_state->data_rate[intel_crtc->pipe] = 0; > + bw_state->num_active_planes[intel_crtc->pipe] = 0; > } > > /* > @@ -11176,6 +11183,7 @@ int intel_plane_atomic_calc_changes(const struct intel_crtc_state *old_crtc_stat > if (!is_crtc_enabled) { > plane_state->visible = visible = false; > to_intel_crtc_state(crtc_state)->active_planes &= ~BIT(plane->id); > + to_intel_crtc_state(crtc_state)->data_rate[plane->id] = 0; > } > > if (!was_visible && !visible) > @@ -13296,7 +13304,15 @@ static int intel_atomic_check(struct drm_device *dev, > return ret; > > intel_fbc_choose_crtc(dev_priv, intel_state); > - return calc_watermark_data(intel_state); > + ret = calc_watermark_data(intel_state); > + if (ret) > + return ret; > + > + ret = intel_bw_atomic_check(intel_state); > + if (ret) > + return ret; > + > + return 0; > } > > static int intel_atomic_prepare_commit(struct drm_device *dev, > @@ -15696,6 +15712,10 @@ int intel_modeset_init(struct drm_device *dev) > > drm_mode_config_init(dev); > > + ret = intel_bw_init(dev_priv); > + if (ret) > + return ret; > + > dev->mode_config.min_width = 0; > dev->mode_config.min_height = 0; > > @@ -16318,8 +16338,11 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) > drm_connector_list_iter_end(&conn_iter); > > for_each_intel_crtc(dev, crtc) { > + struct intel_bw_state *bw_state = > + to_intel_bw_state(dev_priv->bw_obj.state); > struct intel_crtc_state *crtc_state = > to_intel_crtc_state(crtc->base.state); > + struct intel_plane *plane; > int min_cdclk = 0; > > memset(&crtc->base.mode, 0, sizeof(crtc->base.mode)); > @@ -16358,6 +16381,21 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) > dev_priv->min_voltage_level[crtc->pipe] = > crtc_state->min_voltage_level; > > + for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) { > + const struct intel_plane_state *plane_state = > + to_intel_plane_state(plane->base.state); > + > + /* > + * FIXME don't have the fb yet, so can't > + * use intel_plane_data_rate() :( > + */ > + if (plane_state->base.visible) > + crtc_state->data_rate[plane->id] = > + 4 * crtc_state->pixel_rate; > + } > + > + intel_bw_crtc_update(bw_state, crtc_state); > + > intel_pipe_config_sanity_check(dev_priv, crtc_state); > } > } > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index 4049e03d2c0d..47f551601a05 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -885,6 +885,8 @@ struct intel_crtc_state { > > struct intel_crtc_wm_state wm; > > + u32 data_rate[I915_MAX_PLANES]; > + > /* Gamma mode programmed on the pipe */ > u32 gamma_mode; > _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx