Re: [PATCH v5] drm/i915/edp: Be less aggressive about changing link config on eDP

Jim Bride
2017-08-17T19:56:55Z

On Thu, Aug 17, 2017 at 12:20:03PM -0700, Manasi Navare wrote:
> On Thu, Aug 17, 2017 at 10:50:04AM -0700, Jim Bride wrote:
> > On Wed, Aug 16, 2017 at 03:13:06PM -0700, Manasi Navare wrote:
> > > On Wed, Aug 09, 2017 at 02:21:07PM -0700, Jim Bride wrote:
> > > > This set of changes has some history to them. There were several attempts
> > > > to add what was called "fast link training" to i915, which actually wasn't
> > > > fast link training as per the DP spec. These changes were:
> > > >
> > > > commit 5fa836a9d859 ("drm/i915: DP link training optimization")
> > > > commit 4e96c97742f4 ("drm/i915: eDP link training optimization")
> > > >
> > > > which were eventually hand-reverted by:
> > > >
> > > > commit 34511dce4b35 ("drm/i915: Revert DisplayPort fast link training
> > > > feature")
> > > >
> > > > in kernel 4.7-rc4. The eDP pieces of the above revert, however, had some
> > > > very bad side-effects on PSR functionality on Skylake. The issue at
> > > > hand is that when PSR exits i915 briefly emits TP1 followed by TP2/3
> > > > (depending on the original link configuration) in order to quickly get
> > > > the source and sink back in synchronization across the link before handing
> > > > control back to the i915. There's an assumption that none of the link
> > > > configuration information has changed (and thus it's still valid) since the
> > > > last full link training operation. The revert above was identified via a
> > > > bisect as the cause of some of Skylake's PSR woes. This patch, largely
> > > > based on commit 4e96c97742f4 ("drm/i915: eDP link training optimization")
> > > > puts the eDP portions of this patch back in place. None of the flickering
> > > > issues that spurred the revert have been seen, and I suspect the real
> > > > culprits here were addressed by some of the recent link training changes
> > > > that Manasi has implemented, and PSR on Skylake is definitely more happy
> > > > with these changes in-place.
> > > >
> > > > v2 and v3: Rebase
> > > > v4: * Clean up accesses to train_set_valid a bit for easier
> > > > reading. (Chris)
> > > > * Rebase
> > > > v5: * Checkpatch cleanup
> > > > * Rebase
> > > >
> > > > Cc: Chris Wilson <chris@chris-wilson.co.uk>
> > > > Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > > > Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
> > > > Cc: Manasi D Navare <manasi.d.navare@intel.com>
> > > > Cc: Mika Kahola <mika.kahola@intel.com>
> > > > Cc: Jani Nikula <jani.nikula@intel.com>
> > > > Fixes: 34511dce4 ("drm/i915: Revert DisplayPort fast link training feature")
> > > > Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> > > > ---
> > > > drivers/gpu/drm/i915/intel_dp.c | 4 +++-
> > > > drivers/gpu/drm/i915/intel_dp_link_training.c | 15 ++++++++++++++-
> > > > drivers/gpu/drm/i915/intel_drv.h | 2 ++
> > > > 3 files changed, 19 insertions(+), 2 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > > > index 76c8a0b..4bd409c 100644
> > > > --- a/drivers/gpu/drm/i915/intel_dp.c
> > > > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > > > @@ -106,7 +106,7 @@ static const int default_rates[] = { 162000, 270000, 540000 };
> > > > * If a CPU or PCH DP output is attached to an eDP panel, this function
> > > > * will return true, and false otherwise.
> > > > */
> > > > -static bool is_edp(struct intel_dp *intel_dp)
> > > > +bool is_edp(struct intel_dp *intel_dp)
> > > > {
> > > > struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> > > >
> > > > @@ -4711,6 +4711,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
> > > > intel_dp->max_link_rate = intel_dp_max_common_rate(intel_dp);
> > > >
> > > > intel_dp->reset_link_params = false;
> > > > + intel_dp->train_set_valid = false;
> > > > }
> > > >
> > > > intel_dp_print_rates(intel_dp);
> > > > @@ -5979,6 +5980,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
> > > > intel_dp_set_source_rates(intel_dp);
> > > >
> > > > intel_dp->reset_link_params = true;
> > > > + intel_dp->train_set_valid = false;
> > > > intel_dp->pps_pipe = INVALID_PIPE;
> > > > intel_dp->active_pipe = INVALID_PIPE;
> > > >
> > > > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > > index 05907fa..67032cf 100644
> > > > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > > @@ -94,7 +94,8 @@ static bool
> > > > intel_dp_reset_link_train(struct intel_dp *intel_dp,
> > > > uint8_t dp_train_pat)
> > > > {
> > > > - memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
> > > > + if (!intel_dp->train_set_valid)
> > > > + memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
> > > > intel_dp_set_signal_levels(intel_dp);
> > > > return intel_dp_set_link_train(intel_dp, dp_train_pat);
> > > > }
> > > > @@ -162,9 +163,18 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > > DP_TRAINING_PATTERN_1 |
> > > > DP_LINK_SCRAMBLING_DISABLE)) {
> > > > DRM_ERROR("failed to enable link training\n");
> > > > + intel_dp->train_set_valid = false;
> > > > return false;
> > > > }
> > > >
> > > > + /*
> > > > + * The initial set of link parameters are set by this point, so go
> > > > + * ahead and set intel_dp->train_set_valid to false in case any of
> > > > + * the succeeding steps fail. It will be set back to true if we were
> > > > + * able to achieve clock recovery in the specified configuration.
> > > > + */
> > > > + intel_dp->train_set_valid = false;
> > > > +
> > > > voltage_tries = 1;
> > > > max_vswing_tries = 0;
> > > > for (;;) {
> > > > @@ -179,6 +189,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > >
> > > > if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
> > > > DRM_DEBUG_KMS("clock recovery OK\n");
> > > > + intel_dp->train_set_valid = is_edp(intel_dp);
> > > > return true;
> > > > }
> > > >
> > > > @@ -256,6 +267,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> > > > training_pattern |
> > > > DP_LINK_SCRAMBLING_DISABLE)) {
> > > > DRM_ERROR("failed to start channel equalization\n");
> > > > + intel_dp->train_set_valid = false;
> > > > return false;
> > > > }
> > > >
> > > > @@ -296,6 +308,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> > > > /* Try 5 times, else fail and try at lower BW */
> > > > if (tries == 5) {
> > > > intel_dp_dump_link_status(link_status);
> > > > + intel_dp->train_set_valid = false;
> > > > DRM_DEBUG_KMS("Channel equalization failed 5 times\n");
> > > > }
> > >
> > > There are other cases in the channel equalization loop of 5 tries where if drm_dp_clock_recover_ok
> > > is not true then it just breaks from the for loop. Same in case of failure to update link train or
> > > failure to get link status. In this case we dont set train_set_valid to false sinec the tries is not 5 yet
> > > In this case since the train_set_valid was true when it entered this function, it will
> > > stay true without actually succeeding at ch eq.
> > > Shouldnt we be setting train_set_valid to false in these cases?
> > > Or is there something I am missing here?
> >
> > It's set to false before all of those, and then set back to true if the
> > retrain works and we're on eDP. Making the change to do this was some
> > review feedback from Chris on an earlier version of the patch.
> >
> > Jim
> >
> >
>
> I see that it is set to false before starting the clock recovery but after clock recovery
> succeeds, this is set to true and only then you will proceed with channel equalization.
> And in channel equalization, it never gets set to false in case of the failures I mentioned above since
> we just break there.
> It then gets set to false only if the tries are 5 but it should also be set to false in case
> of other failures that I mentioned else we will end up leaving it to true even when channel EQ never
> succeeded.

I see where you're talking about now. I honestly believe that the code
as written is broken. All of those failing 'break' statements should be
'continue' statements (the break for success is fine.) As the code is written,
we break out of the loop on the first failure, and if (tries == 5) will never
be true. If we actually loop through five times before we give up, then
this patch as written is fine.

Jim

> Manasi
>
> > > Regards
> > > Manasi
> > >
> > > >
> > > > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > > > index f91de9c..792bf547 100644
> > > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > > @@ -994,6 +994,7 @@ struct intel_dp {
> > > > struct drm_dp_aux aux;
> > > > enum intel_display_power_domain aux_power_domain;
> > > > uint8_t train_set[4];
> > > > + bool train_set_valid;
> > > > int panel_power_up_delay;
> > > > int panel_power_down_delay;
> > > > int panel_power_cycle_delay;
> > > > @@ -1548,6 +1549,7 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count)
> > > > }
> > > >
> > > > bool intel_dp_read_dpcd(struct intel_dp *intel_dp);
> > > > +bool is_edp(struct intel_dp *intel_dp);
> > > > int intel_dp_link_required(int pixel_clock, int bpp);
> > > > int intel_dp_max_data_rate(int max_link_clock, int max_lanes);
> > > > bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
> > > > --
> > > > 2.7.4
> > > >