[Intel-gfx] [PATCH] drm/i915: Match all PSR mode entry conditions before enabling it.
Rodrigo Vivi
rodrigo.vivi at gmail.com
Thu Jul 11 20:09:57 CEST 2013
On Mon, Jul 8, 2013 at 7:25 PM, Rodrigo Vivi <rodrigo.vivi at gmail.com> wrote:
> On Fri, Jul 5, 2013 at 5:32 PM, Daniel Vetter <daniel at ffwll.ch> wrote:
>> On Mon, Jul 01, 2013 at 05:47:39PM -0300, Rodrigo Vivi wrote:
>>> Again, Thank you very much for your comments.
>>>
>>> Replying what I did and why I didn't here and patches coming later.
>>
>> Paulo asked me to drop by maintainer bikeshed on this patch. So here I'l
>> comply ;-)
>
> Mainteiner's complies are always good ;)
> Thanks for jumping in this discussion
>
>>
>>>
>>>
>>> On Fri, Jun 28, 2013 at 5:46 PM, Paulo Zanoni <przanoni at gmail.com> wrote:
>>> > 2013/6/28 Rodrigo Vivi <rodrigo.vivi at gmail.com>:
>>> >> v2: Prefer seq_puts to seq_printf by Paulo Zanoni.
>>> >>
>>> >> Cc: Paulo Zanoni <paulo.r.zanoni at intel.com>
>>> >> Signed-off-by: Rodrigo Vivi <rodrigo.vivi at gmail.com>
>>> >> ---
>>> >> drivers/gpu/drm/i915/i915_debugfs.c | 39 ++++++++++++++++++---
>>> >> drivers/gpu/drm/i915/i915_drv.h | 12 +++++++
>>> >> drivers/gpu/drm/i915/intel_dp.c | 68 ++++++++++++++++++++++++++++++++++++-
>>> >> 3 files changed, 114 insertions(+), 5 deletions(-)
>>> >>
>>> >> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
>>> >> index 67c777f..95b27ac 100644
>>> >> --- a/drivers/gpu/drm/i915/i915_debugfs.c
>>> >> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
>>> >> @@ -1882,11 +1882,42 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
>>> >> struct drm_info_node *node = m->private;
>>> >> struct drm_device *dev = node->minor->dev;
>>> >> struct drm_i915_private *dev_priv = dev->dev_private;
>>> >> - u32 psrctl, psrstat, psrperf;
>>> >> + u32 psrstat, psrperf;
>>> >>
>>> >> - psrctl = I915_READ(EDP_PSR_CTL);
>>> >> - seq_printf(m, "PSR Enabled: %s\n",
>>> >> - yesno(psrctl & EDP_PSR_ENABLE));
>>> >> + if (I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE) {
>>> >> + seq_puts(m, "PSR enabled\n");
>>> >> + } else {
>>> >> + seq_puts(m, "PSR disabled: ");
>>> >> + switch (dev_priv->no_psr_reason) {
>>> >> + case PSR_NO_SOURCE:
>>> >> + seq_puts(m, "not supported on this platform");
>>> >> + break;
>>> >> + case PSR_NO_SINK:
>>> >> + seq_puts(m, "not supported by panel");
>>> >> + break;
>>> >> + case PSR_CRTC_NOT_ACTIVE:
>>> >> + seq_puts(m, "crtc not active");
>>> >> + break;
>>> >> + case PSR_PWR_WELL_ENABLED:
>>> >> + seq_puts(m, "power well enabled");
>>> >> + break;
>>> >> + case PSR_NOT_TILED:
>>> >> + seq_puts(m, "not tiled");
>>> >> + break;
>>> >> + case PSR_SPRITE_ENABLED:
>>> >> + seq_puts(m, "sprite enabled");
>>> >> + break;
>>> >> + case PSR_INTERLACED_ENABLED:
>>> >> + seq_puts(m, "interlaced enabled");
>>> >> + break;
>>> >> + case PSR_HSW_NOT_DDIA:
>>> >> + seq_puts(m, "HSW ties PSR to DDI A (eDP)");
>>> >> + break;
>>> >> + default:
>>> >> + seq_puts(m, "unknown reason");
>>> >> + }
>>> >> + seq_puts(m, "\n");
>>> >> + }
>>> >>
>>> >> psrstat = I915_READ(EDP_PSR_STATUS_CTL);
>>> >>
>>> >> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>>> >> index 56bd82b..f08c1d9 100644
>>> >> --- a/drivers/gpu/drm/i915/i915_drv.h
>>> >> +++ b/drivers/gpu/drm/i915/i915_drv.h
>>> >> @@ -543,6 +543,17 @@ enum no_fbc_reason {
>>> >> FBC_CHIP_DEFAULT, /* disabled by default on this chip */
>>> >> };
>>> >>
>>> >> +enum no_psr_reason {
>>> >> + PSR_NO_SOURCE, /* Not supported on platform */
>>> >> + PSR_NO_SINK, /* Not supported by panel */
>>> >> + PSR_CRTC_NOT_ACTIVE,
>>> >> + PSR_PWR_WELL_ENABLED,
>>> >> + PSR_NOT_TILED,
>>> >> + PSR_SPRITE_ENABLED,
>>> >> + PSR_INTERLACED_ENABLED,
>>> >> + PSR_HSW_NOT_DDIA,
>>> >
>>> > I see you left a few reasons listed on the spec, for example S3D,
>>> > which we don't support yet. I'm pretty sure that when we implement S3D
>>> > we'll totally forget about adding the PSR_S3D_ENABLED condition, so
>>> > shouldn't we do it now? Also, why did we not add the eDP hotplug
>>> > reason?
>>>
>>> Since it isn't implemented I'm not sure how to check that.
>>> Maybe we will have a function, maybe just a bit in some register or
>>> maybe somehow else.
>>> So I prefer to stay without it until we have a proper way.
>>
>> Imo adding the S3D_ENABLED reason is good, since that increases the
>> chances that we won'd forget about it. Maybe even add a comment in the
>> psr_match_conditions function below saying that we need to do this.
>
> ok, I'll do that then.
>
>>
>> Wrt hotplug I've just chatted a bit and it sounds like the hw doesn't like
>> our hpd setup for port A. I guess we should fix that up first ...
>
> Since we don't have any known issue with psr, couldn't we just move
> forward and after we get hotplug fixed we remove this workaround from
> here?
> Also, if we wait this we will have to say Chris and Ville finish that
> rework with vblank waits you mentioned on the other email.
>
> If you perfer, on next series I can send psr disabled by default.
>
>>
>>>
>>> >
>>> >
>>> >> +};
>>> >> +
>>> >> enum intel_pch {
>>> >> PCH_NONE = 0, /* No PCH present */
>>> >> PCH_IBX, /* Ibexpeak PCH */
>>> >> @@ -1146,6 +1157,7 @@ typedef struct drm_i915_private {
>>> >> struct i915_power_well power_well;
>>> >>
>>> >> enum no_fbc_reason no_fbc_reason;
>>> >> + enum no_psr_reason no_psr_reason;
>>> >>
>>> >> struct drm_mm_node *compressed_fb;
>>> >> struct drm_mm_node *compressed_llb;
>>> >> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>>> >> index c10be94..9730d6b 100644
>>> >> --- a/drivers/gpu/drm/i915/intel_dp.c
>>> >> +++ b/drivers/gpu/drm/i915/intel_dp.c
>>> >> @@ -1471,11 +1471,77 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
>>> >> EDP_PSR_ENABLE);
>>> >> }
>>> >>
>>> >> +static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
>>> >> +{
>>> >> + struct drm_device *dev = intel_dp_to_dev(intel_dp);
>>> >> + struct drm_i915_private *dev_priv = dev->dev_private;
>>> >> + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
>>> >> + struct drm_crtc *crtc = dig_port->base.base.crtc;
>>> >> + struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>>> >> + struct drm_i915_gem_object *obj = to_intel_framebuffer(crtc->fb)->obj;
>>> >> + struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
>>> >
>>> > Again, you have intel_dp_to_dev and also call dp_to_dig_port twice.
>>>
>>> done.
>>>
>>> >
>>> >
>>> >> +
>>> >> + if (!IS_HASWELL(dev)) {
>>> >> + DRM_DEBUG_KMS("PSR not supported on this platform\n");
>>> >> + dev_priv->no_psr_reason = PSR_NO_SOURCE;
>>> >> + return false;
>>> >> + }
>>> >> +
>>> >> + if ((intel_encoder->type != INTEL_OUTPUT_EDP) ||
>>> >> + (enc_to_dig_port(&intel_encoder->base)->port != PORT_A)) {
>>> >
>>> > Here you're calling enc_to_dig_port, but you already defined dig_port
>>> > above. Use it.
>>>
>>> done
>>
>> Just to check: Does this really work for DDI port D with dekstop eDP? I'm
>> pretty sure you actually want to check for cpu_transcoder = EPD here ...
>
> doc says psr on hsw is tied to DDI A (eDP)... I used same check Paulo
> used on IPS.
>
>>
>>>
>>> >
>>> >
>>> >> + DRM_DEBUG_KMS("HSW ties PSR to DDI A (eDP)\n");
>>> >> + dev_priv->no_psr_reason = PSR_HSW_NOT_DDIA;
>>> >> + return false;
>>> >> + }
>>> >> +
>>> >> + if (!is_edp_psr(intel_dp)) {
>>> >> + DRM_DEBUG_KMS("PSR not supported by this panel\n");
>>> >> + dev_priv->no_psr_reason = PSR_NO_SINK;
>>> >> + return false;
>>> >> + }
>>> >> +
>>> >> + if (!intel_crtc->active || !crtc->fb || !crtc->mode.clock) {
>>> >
>>> > Why do we check for crtc->fb and crtc->mode.clock here? Also, there's
>>> > intel_crtc->primary_disabled which you could use.
>>>
>>> This is how it is done at update_fbc checking for active crtc and it
>>> is properly workig.
>>> So I prefer to let it like this.
>>
>> That check is to avoid division-by-zero on state we've taken over from the
>> BIOS. Since we should only ever enable psr after a modeset that should be
>> a problem.
>>
>> Now one thing which is a bit urky here with the psr code (same
>> comment applies to the fbc code really) is that a lot of the conditions
>> here _never_ change between modesets. So I think a ->fbc_possible and a
>> ->psr_possible flag in pipe_config would make an awful lot of sense.
>>
>
> I liked your _possible flag in pipe_config suggestion..
>
>> But I guess we can do that later on, once it's a bit clearer how this will
>> all work out.
>
> ... but yes, I think we can do this later and fix both psr and fbc
>
>
>>
>>>
>>> >
>>> >
>>> >> + DRM_DEBUG_KMS("crtc not active for PSR\n");
>>> >> + dev_priv->no_psr_reason = PSR_CRTC_NOT_ACTIVE;
>>> >> + return false;
>>> >> + }
>>> >> +
>>> >> + if ((I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_ENABLE) |
>>> >
>>> > I'd use "||" instead of "|" at the end of the line since this is a
>>> > logical statement.
>>>
>>> done
>>>
>>> >
>>> >
>>> >> + (I915_READ(HSW_PWR_WELL_KVMR) & HSW_PWR_WELL_ENABLE)) {
>>> >
>>> > I know the spec says we should check for this, but there's absolutely
>>> > no guarantee that the KVMr won't be enabled exactly after we read this
>>> > bit. I don't know if there's a sane way to check for an active KVMr
>>> > session. We should also probably get an interrupt somehow if someone
>>> > enables KVMr after PSR is enabled.
>>>
>>> You are right, it can be enabled by someone else later, but this will
>>> only cause the continue PSR exit like mem up and hpd if they weren't
>>> being masked.
>>> So, this is just a check saying psr wont work if this is enabled but
>>> not really needed to worry if this is enabled later. Wont break
>>> anything for sure.
>>
>> tbh I don't understand why we need to check for the power well at all.
>> Is this really a hw requirement?
>
> yes, it is... if it is on it forces psr exit by definition... so if it
> is on since the begining it is not worth turn psr on...
>
>>
>> Paulo is right that we can't check for the power well enabling from the
>> kvmr in a race-free manner, so this needs some more thinking.
>
> also later? because as I said it doesn't cause any bug if power well
> is on... it just forces psr exit state...
>
>>
>>>
>>> >
>>> >
>>> >> + DRM_DEBUG_KMS("PSR condition failed: Power Well is Enabled\n");
>>> >> + dev_priv->no_psr_reason = PSR_PWR_WELL_ENABLED;
>>> >> + return false;
>>> >> + }
>>> >> +
>>> >> + if (obj->tiling_mode != I915_TILING_X ||
>>> >> + obj->fence_reg == I915_FENCE_REG_NONE) {
>>> >> + DRM_DEBUG_KMS("PSR condition failed: fb not tiled or fenced\n");
>>> >> + dev_priv->no_psr_reason = PSR_NOT_TILED;
>>> >> + return false;
>>> >> + }
>>> >> +
>>> >> + if (I915_READ(SPRCTL(intel_crtc->pipe)) & SPRITE_ENABLE) {
>>> >
>>> > We should probably check "struct intel_plane" instead of I915_READ here.
>>>
>>> I prefer to stay this way that is the way used on
>>> asser_sprite_disabled in intel_display.
>>
>> I agree with paulo, pls check sw tracked state, not hw state. If we move
>> to state precomputation and similar tricks you simply can't rely on the hw
>> state. Similar comment applies to the power well check above (if we really
>> need that one, I kinda expect that this is not so).
>
> I just don't understand why... Should we change the assert_sprite
> also? is it wrong?
I tried to find a way to do it with sw check with intel_plane, etc but
I didn't find any other way.
Do you have any other idea how to do that?
>
>>
>>>
>>> >
>>> >
>>> >> + DRM_DEBUG_KMS("PSR condition failed: Sprite is Enabled\n");
>>> >> + dev_priv->no_psr_reason = PSR_SPRITE_ENABLED;
>>> >> + return false;
>>> >> + }
>>> >> +
>>> >> + if ((I915_READ(PIPECONF(intel_crtc->config.cpu_transcoder)) &
>>> >> + PIPECONF_INTERLACE_MASK) == PIPECONF_INTERLACED_ILK) {
>>> >
>>> > I'd prefer checking for "crtc->mode.flags & DRM_MODE_FLAG_INTERLACE".
>>>
>>> I prefer to stay this way that is the way used in intel_display.
>>
>> Where? Again I think we should use sw tracked state ...
>
> at ironlake_enable_pch_transcoder.... is it wrong there? should we fix?
>
> but anyway, how is the correct way to check it in sw tracked state?
Changed to check interlace flag as paulo suggested. Really much better ;)
Thanks
>
>>
>>>
>>> >
>>> >
>>> >> + DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n");
>>> >> + dev_priv->no_psr_reason = PSR_INTERLACED_ENABLED;
>>> >> + return false;
>>> >> + }
>>> >> +
>>> >> + return true;
>>> >> +}
>>> >> +
>>> >> void intel_edp_psr_enable(struct intel_dp *intel_dp)
>>> >> {
>>> >> struct drm_device *dev = intel_dp_to_dev(intel_dp);
>>> >>
>>> >> - if (!is_edp_psr(intel_dp) || intel_edp_is_psr_enabled(dev))
>>> >> + if (!intel_edp_psr_match_conditions(intel_dp) ||
>>> >> + intel_edp_is_psr_enabled(dev))
>>> >> return;
>>> >>
>>> >> /* Enable PSR on the panel */
>>> >> --
>>> >> 1.8.1.4
>>> >>
>>> >> _______________________________________________
>>> >> Intel-gfx mailing list
>>> >> Intel-gfx at lists.freedesktop.org
>>> >> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>> >
>>> >
>>> >
>>> > --
>>> > Paulo Zanoni
>>>
>>>
>>>
>>> --
>>> Rodrigo Vivi
>>> Blog: http://blog.vivi.eng.br
>>> _______________________________________________
>>> Intel-gfx mailing list
>>> Intel-gfx at lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>
>> --
>> Daniel Vetter
>> Software Engineer, Intel Corporation
>> +41 (0) 79 365 57 48 - http://blog.ffwll.ch
>
>
>
> --
> Rodrigo Vivi
> Blog: http://blog.vivi.eng.br
--
Rodrigo Vivi
Blog: http://blog.vivi.eng.br
More information about the Intel-gfx
mailing list