On Tue, Oct 15, 2019 at 04:50:13PM +0300, Stanislav Lisovskiy wrote: > According to BSpec 53998, we should try to > restrict qgv points, which can't provide > enough bandwidth for desired display configuration. > > Currently we are just comparing against all of > those and take minimum(worst case). > > v2: Fixed wrong PCode reply mask, removed hardcoded > values. > > v3: Forbid simultaneous legacy SAGV PCode requests and > restricting qgv points. Put the actual restriction > to commit function, added serialization(thanks to Ville) > to prevent commit being applied out of order in case of > nonblocking and/or nomodeset commits. > > v4: > - Minor code refactoring, fixed few typos(thanks to James Ausmus) > - Change the naming of qgv point > masking/unmasking functions(James Ausmus). > - Simplify the masking/unmasking operation itself, > as we don't need to mask only single point per request(James Ausmus) > - Reject and stick to highest bandwidth point if SAGV > can't be enabled(BSpec) > > Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy@xxxxxxxxx> > Cc: Ville Syrjälä <ville.syrjala@xxxxxxxxx> > Cc: James Ausmus <james.ausmus@xxxxxxxxx> > --- > drivers/gpu/drm/i915/display/intel_atomic.c | 16 +++ > drivers/gpu/drm/i915/display/intel_atomic.h | 3 + > drivers/gpu/drm/i915/display/intel_bw.c | 105 ++++++++++++++---- > drivers/gpu/drm/i915/display/intel_bw.h | 2 + > drivers/gpu/drm/i915/display/intel_display.c | 58 +++++++++- > .../drm/i915/display/intel_display_types.h | 3 + > drivers/gpu/drm/i915/i915_drv.h | 2 + > drivers/gpu/drm/i915/i915_reg.h | 3 + > 8 files changed, 166 insertions(+), 26 deletions(-) > > diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c > index c5a552a69752..b3f4f02f380b 100644 > --- a/drivers/gpu/drm/i915/display/intel_atomic.c > +++ b/drivers/gpu/drm/i915/display/intel_atomic.c > @@ -207,6 +207,22 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) > return &crtc_state->base; > } > > +int intel_atomic_serialize_global_state(struct intel_atomic_state *state) > +{ > + struct drm_i915_private *dev_priv = to_i915(state->base.dev); > + struct intel_crtc *crtc; > + > + for_each_intel_crtc(&dev_priv->drm, crtc) { > + struct intel_crtc_state *crtc_state; > + > + crtc_state = intel_atomic_get_crtc_state(&state->base, crtc); > + if (IS_ERR(crtc_state)) > + return PTR_ERR(crtc_state); > + } > + > + return 0; > +} > + > /** > * intel_crtc_destroy_state - destroy crtc state > * @crtc: drm crtc > diff --git a/drivers/gpu/drm/i915/display/intel_atomic.h b/drivers/gpu/drm/i915/display/intel_atomic.h > index 58065d3161a3..fd17b3ca257f 100644 > --- a/drivers/gpu/drm/i915/display/intel_atomic.h > +++ b/drivers/gpu/drm/i915/display/intel_atomic.h > @@ -7,6 +7,7 @@ > #define __INTEL_ATOMIC_H__ > > #include <linux/types.h> > +#include "intel_display_types.h" > > struct drm_atomic_state; > struct drm_connector; > @@ -38,6 +39,8 @@ void intel_crtc_destroy_state(struct drm_crtc *crtc, > struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev); > void intel_atomic_state_clear(struct drm_atomic_state *state); > > +int intel_atomic_serialize_global_state(struct intel_atomic_state *state); > + > struct intel_crtc_state * > intel_atomic_get_crtc_state(struct drm_atomic_state *state, > struct intel_crtc *crtc); > diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c > index 22e83f857de8..09f786cfdfaa 100644 > --- a/drivers/gpu/drm/i915/display/intel_bw.c > +++ b/drivers/gpu/drm/i915/display/intel_bw.c > @@ -8,6 +8,8 @@ > #include "intel_bw.h" > #include "intel_display_types.h" > #include "intel_sideband.h" > +#include "intel_atomic.h" > +#include "intel_pm.h" > > /* Parameters for Qclk Geyserville (QGV) */ > struct intel_qgv_point { > @@ -113,6 +115,27 @@ static int icl_pcode_read_qgv_point_info(struct drm_i915_private *dev_priv, > return 0; > } > > +int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv, > + u32 points_mask) > +{ > + int ret; > + > + /* bspec says to keep retrying for at least 1 ms */ > + ret = skl_pcode_request(dev_priv, ICL_PCODE_SAGV_DE_MEM_SS_CONFIG, > + points_mask, > + GEN11_PCODE_POINTS_RESTRICTED_MASK, > + GEN11_PCODE_POINTS_RESTRICTED, > + 1); > + > + if (ret < 0) { > + DRM_ERROR("Failed to disable qgv points (%d)\n", ret); This could also be enabling qgv points, so this might better be "Failed to set qgv point mask". > + return ret; > + } > + > + return 0; > +} > + > + > static int icl_get_qgv_points(struct drm_i915_private *dev_priv, > struct intel_qgv_info *qi) > { > @@ -270,22 +293,6 @@ void intel_bw_init_hw(struct drm_i915_private *dev_priv) > icl_get_bw_info(dev_priv, &icl_sa_info); > } > > -static unsigned int intel_max_data_rate(struct drm_i915_private *dev_priv, > - int num_planes) > -{ > - if (INTEL_GEN(dev_priv) >= 11) > - /* > - * 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 unsigned int intel_bw_crtc_num_active_planes(const struct intel_crtc_state *crtc_state) > { > /* > @@ -377,7 +384,10 @@ int intel_bw_atomic_check(struct intel_atomic_state *state) > unsigned int data_rate, max_data_rate; > unsigned int num_active_planes; > struct intel_crtc *crtc; > - int i; > + int i, ret; > + struct intel_qgv_info qi = {}; > + u32 allowed_points = 0; > + unsigned int max_bw_point = 0, max_bw = 0; > > /* FIXME earlier gens need some checks too */ > if (INTEL_GEN(dev_priv) < 11) > @@ -421,16 +431,67 @@ int intel_bw_atomic_check(struct intel_atomic_state *state) > 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); > + ret = icl_get_qgv_points(dev_priv, &qi); > + if (ret < 0) > + return 0; > + > + for (i = 0; i < qi.num_points; i++) { > + max_data_rate = icl_max_bw(dev_priv, num_active_planes, i); > + /* > + * We need to know which qgv point gives us > + * maximum bandwidth in order to disable SAGV > + * if we find that we exceed SAGV block time > + * with watermarks. By that moment we already > + * have those, as it is calculated earlier in > + * intel_atomic_check, > + */ > + if (max_data_rate > max_bw) { > + max_bw_point = i; > + max_bw = max_data_rate; > + } > + if (max_data_rate >= data_rate) > + allowed_points |= 1 << i; > + DRM_DEBUG_KMS("QGV point %d: max bw %d required %d\n", > + i, max_data_rate, data_rate); > + } > + > + /* > + * BSpec states that we always should have at least one allowed point > + * left, so if we couldn't - simply reject the configuration for obvious > + * reasons. > + */ > + if (allowed_points == 0) { > + DRM_DEBUG_KMS("Could not find any suitable QGV points\n"); > return -EINVAL; > } > > + /* > + * Leave only single point with highest bandwidth, if > + * we can't enable SAGV according to BSpec. > + */ > + if (!intel_can_enable_sagv(state)) > + allowed_points = 1 << max_bw_point; > + > + /* > + * We store the ones which need to be masked as that is what PCode > + * actually accepts as a parameter. > + */ > + state->qgv_points_mask = (~allowed_points) & ((1 << qi.num_points) - 1); > + > + /* > + * If the actual mask had changed we need to make sure that > + * the commits are serialized(in case this is a nomodeset, nonblocking) > + */ > + if (state->qgv_points_mask != dev_priv->qgv_points_mask) { > + ret = intel_atomic_serialize_global_state(state); > + if (ret) { > + DRM_DEBUG_KMS("Could not serialize global state\n"); > + return ret; > + } > + } > + > return 0; > } > > diff --git a/drivers/gpu/drm/i915/display/intel_bw.h b/drivers/gpu/drm/i915/display/intel_bw.h > index 9db10af012f4..66bf9bc10b73 100644 > --- a/drivers/gpu/drm/i915/display/intel_bw.h > +++ b/drivers/gpu/drm/i915/display/intel_bw.h > @@ -28,5 +28,7 @@ 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); > +int icl_pcode_restrict_qgv_points(struct drm_i915_private *dev_priv, > + u32 points_mask); > > #endif /* __INTEL_BW_H__ */ > diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c > index a8168e2aacd5..4aaf66955149 100644 > --- a/drivers/gpu/drm/i915/display/intel_display.c > +++ b/drivers/gpu/drm/i915/display/intel_display.c > @@ -14003,6 +14003,48 @@ static void intel_atomic_cleanup_work(struct work_struct *work) > intel_atomic_helper_free_state(i915); > } > > +static void intel_qgv_points_mask(struct intel_atomic_state *state) > +{ > + struct drm_device *dev = state->base.dev; > + struct drm_i915_private *dev_priv = to_i915(dev); > + int ret; > + u32 new_mask = dev_priv->qgv_points_mask | state->qgv_points_mask; > + > + /* > + * Restrict required qgv points before updating the configuration. > + * According to BSpec we can't mask and unmask qgv points at the same > + * time. Also masking should be done before updating the configuration > + * and unmasking afterwards. > + */ > + ret = icl_pcode_restrict_qgv_points(dev_priv, new_mask); > + if (ret < 0) > + DRM_DEBUG_KMS("Could not restrict required qgv points(%d)\n", Nit: "Could not mask unusable qgv points" > + ret); > + else > + dev_priv->qgv_points_mask = new_mask; > +} > + > +static void intel_qgv_points_unmask(struct intel_atomic_state *state) > +{ > + struct drm_device *dev = state->base.dev; > + struct drm_i915_private *dev_priv = to_i915(dev); > + int ret; > + u32 new_mask = dev_priv->qgv_points_mask & state->qgv_points_mask; > + > + /* > + * Allow required qgv points after updating the configuration. > + * According to BSpec we can't mask and unmask qgv points at the same > + * time. Also masking should be done before updating the configuration > + * and unmasking afterwards. > + */ > + ret = icl_pcode_restrict_qgv_points(dev_priv, new_mask); > + if (ret < 0) > + DRM_DEBUG_KMS("Could not restrict required qgv points(%d)\n", Nit: "Could not unmask allowed qgv points" With those: Reviewed-by: James Ausmus <james.ausmus@xxxxxxxxx> > + ret); > + else > + dev_priv->qgv_points_mask = new_mask; > +} > + > static void intel_atomic_commit_tail(struct intel_atomic_state *state) > { > struct drm_device *dev = state->base.dev; > @@ -14030,6 +14072,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) > } > } > > + if ((INTEL_GEN(dev_priv) >= 11)) > + intel_qgv_points_mask(state); > + > intel_commit_modeset_disables(state); > > /* FIXME: Eventually get rid of our crtc->config pointer */ > @@ -14048,8 +14093,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) > * SKL workaround: bspec recommends we disable the SAGV when we > * have more then one pipe enabled > */ > - if (!intel_can_enable_sagv(state)) > - intel_disable_sagv(dev_priv); > + if (INTEL_GEN(dev_priv) < 11) > + if (!intel_can_enable_sagv(state)) > + intel_disable_sagv(dev_priv); > > intel_modeset_verify_disabled(dev_priv, state); > } > @@ -14127,8 +14173,12 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) > if (state->modeset) > intel_verify_planes(state); > > - if (state->modeset && intel_can_enable_sagv(state)) > - intel_enable_sagv(dev_priv); > + if (INTEL_GEN(dev_priv) < 11) { > + if (state->modeset && intel_can_enable_sagv(state)) > + intel_enable_sagv(dev_priv); > + } > + else > + intel_qgv_points_unmask(state); > > drm_atomic_helper_commit_hw_done(&state->base); > > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h > index 40390d855815..8750a34c3e28 100644 > --- a/drivers/gpu/drm/i915/display/intel_display_types.h > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h > @@ -512,6 +512,9 @@ struct intel_atomic_state { > struct i915_sw_fence commit_ready; > > struct llist_node freed; > + > + /* Gen11+ only */ > + u32 qgv_points_mask; > }; > > struct intel_plane_state { > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index c46b339064c0..0b1b641a280f 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -1335,6 +1335,8 @@ struct drm_i915_private { > u8 num_planes; > } max_bw[6]; > > + u32 qgv_points_mask; > + > struct drm_private_obj bw_obj; > > struct intel_runtime_pm runtime_pm; > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index e24991e54897..1f3402547ba5 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -8869,6 +8869,7 @@ enum { > #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 ICL_PCODE_SAGV_DE_MEM_SS_CONFIG 0xe > #define GEN6_PCODE_READ_D_COMP 0x10 > #define GEN6_PCODE_WRITE_D_COMP 0x11 > #define HSW_PCODE_DE_WRITE_FREQ_REQ 0x17 > @@ -8881,6 +8882,8 @@ enum { > #define GEN9_SAGV_IS_DISABLED 0x1 > #define GEN9_SAGV_ENABLE 0x3 > #define GEN12_PCODE_READ_SAGV_BLOCK_TIME_US 0x23 > +#define GEN11_PCODE_POINTS_RESTRICTED 0x0 > +#define GEN11_PCODE_POINTS_RESTRICTED_MASK 0x1 > #define GEN6_PCODE_DATA _MMIO(0x138128) > #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 > #define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16 > -- > 2.17.1 > _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx