On Tue, Oct 29, 2019 at 06:12:26PM +0200, 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) > > v5: > - Add new mailbox reply codes, which seems to happen during boot > time for TGL and indicate that QGV setting is not yet available. > > v6: > - Increase number of supported QGV points to be in sync with BSpec. > > Reviewed-by: James Ausmus <james.ausmus@xxxxxxxxx> > 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 | 111 ++++++++++++++---- > drivers/gpu/drm/i915/display/intel_bw.h | 2 + > drivers/gpu/drm/i915/display/intel_display.c | 57 ++++++++- > .../drm/i915/display/intel_display_types.h | 3 + > drivers/gpu/drm/i915/i915_drv.h | 2 + > drivers/gpu/drm/i915/i915_reg.h | 5 + > drivers/gpu/drm/i915/intel_sideband.c | 27 ++++- > 9 files changed, 198 insertions(+), 28 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..60249d9776d1 100644 > --- a/drivers/gpu/drm/i915/display/intel_bw.c > +++ b/drivers/gpu/drm/i915/display/intel_bw.c > @@ -8,14 +8,20 @@ > #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 { > u16 dclk, t_rp, t_rdpre, t_rc, t_ras, t_rcd; > }; > > + > +/* BSpec precisely defines this */ > +#define NUM_SAGV_POINTS 4 As noted before, this should be 8, and should be defined in the .h file. With that addressed, my R-b sticks for this version. Thanks! -James > + > struct intel_qgv_info { > - struct intel_qgv_point points[3]; > + struct intel_qgv_point points[NUM_SAGV_POINTS]; > u8 num_points; > u8 num_channels; > u8 t_bl; > @@ -113,6 +119,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); > + return ret; > + } > + > + return 0; > +} > + > + > static int icl_get_qgv_points(struct drm_i915_private *dev_priv, > struct intel_qgv_info *qi) > { > @@ -270,22 +297,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 +388,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 +435,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 d870ce1709ea..525eaefce6b8 100644 > --- a/drivers/gpu/drm/i915/display/intel_display.c > +++ b/drivers/gpu/drm/i915/display/intel_display.c > @@ -14471,6 +14471,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", > + 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", > + 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; > @@ -14498,6 +14540,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 */ > @@ -14516,8 +14561,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); > } > @@ -14599,8 +14645,11 @@ 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 f87f98b7ef0d..c6975d9b4696 100644 > --- a/drivers/gpu/drm/i915/display/intel_display_types.h > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h > @@ -520,6 +520,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 aa8babe6b77d..fe7dd6213e5c 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -1333,6 +1333,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 855db888516c..93823443036f 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -8858,6 +8858,8 @@ enum { > #define GEN6_PCODE_UNIMPLEMENTED_CMD 0xFF > #define GEN7_PCODE_TIMEOUT 0x2 > #define GEN7_PCODE_ILLEGAL_DATA 0x3 > +#define GEN11_PCODE_MAIL_BOX_LOCKED 0x6 > +#define GEN11_PCODE_REJECTED 0x11 > #define GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE 0x10 > #define GEN6_PCODE_WRITE_RC6VIDS 0x4 > #define GEN6_PCODE_READ_RC6VIDS 0x5 > @@ -8879,6 +8881,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 > @@ -8891,6 +8894,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 > diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c > index e06b35b844a0..ff9dbed094d8 100644 > --- a/drivers/gpu/drm/i915/intel_sideband.c > +++ b/drivers/gpu/drm/i915/intel_sideband.c > @@ -371,6 +371,29 @@ static inline int gen7_check_mailbox_status(u32 mbox) > } > } > > +static inline int gen11_check_mailbox_status(u32 mbox) > +{ > + switch (mbox & GEN6_PCODE_ERROR_MASK) { > + case GEN6_PCODE_SUCCESS: > + return 0; > + case GEN6_PCODE_ILLEGAL_CMD: > + return -ENXIO; > + case GEN7_PCODE_TIMEOUT: > + return -ETIMEDOUT; > + case GEN7_PCODE_ILLEGAL_DATA: > + return -EINVAL; > + case GEN7_PCODE_MIN_FREQ_TABLE_GT_RATIO_OUT_OF_RANGE: > + return -EOVERFLOW; > + case GEN11_PCODE_MAIL_BOX_LOCKED: > + return -EAGAIN; > + case GEN11_PCODE_REJECTED: > + return -EACCES; > + default: > + MISSING_CASE(mbox & GEN6_PCODE_ERROR_MASK); > + return 0; > + } > +} > + > static int __sandybridge_pcode_rw(struct drm_i915_private *i915, > u32 mbox, u32 *val, u32 *val1, > int fast_timeout_us, > @@ -408,7 +431,9 @@ static int __sandybridge_pcode_rw(struct drm_i915_private *i915, > if (is_read && val1) > *val1 = intel_uncore_read_fw(uncore, GEN6_PCODE_DATA1); > > - if (INTEL_GEN(i915) > 6) > + if (INTEL_GEN(i915) >= 11) > + return gen11_check_mailbox_status(mbox); > + else if (INTEL_GEN(i915) > 6) > return gen7_check_mailbox_status(mbox); > else > return gen6_check_mailbox_status(mbox); > -- > 2.17.1 > _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx