Commit 8cfaf0ae authored by Chris Wilson's avatar Chris Wilson Committed by Greg Kroah-Hartman

drm/i915: Stop using RP_DOWN_EI on Baytrail

commit 8f68d591 upstream.

On Baytrail, we manually calculate busyness over the evaluation interval
to avoid issues with miscaluations with RC6 enabled. However, it turns
out that the DOWN_EI interrupt generator is completely bust - it
operates in two modes, continuous or never. Neither of which are
conducive to good behaviour. Stop unmask the DOWN_EI interrupt and just
compute everything from the UP_EI which does seem to correspond to the
desired interval.

v2: Fixup gen6_rps_pm_mask() as well
v3: Inline vlv_c0_above() to combine the now identical elapsed
calculation for up/down and simplify the threshold testing

Fixes: 43cf3bf0 ("drm/i915: Improved w/a for rps on Baytrail")
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170309211232.28878-1-chris@chris-wilson.co.ukReviewed-by: default avatarMika Kuoppala <mika.kuoppala@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170313170617.31564-1-chris@chris-wilson.co.uk
(cherry picked from commit e0e8c7cb)
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent cb0a2cba
...@@ -1159,7 +1159,7 @@ struct intel_gen6_power_mgmt { ...@@ -1159,7 +1159,7 @@ struct intel_gen6_power_mgmt {
struct intel_rps_client semaphores, mmioflips; struct intel_rps_client semaphores, mmioflips;
/* manual wa residency calculations */ /* manual wa residency calculations */
struct intel_rps_ei up_ei, down_ei; struct intel_rps_ei ei;
/* /*
* Protects RPS/RC6 register access and PCU communication. * Protects RPS/RC6 register access and PCU communication.
......
...@@ -994,68 +994,51 @@ static void vlv_c0_read(struct drm_i915_private *dev_priv, ...@@ -994,68 +994,51 @@ static void vlv_c0_read(struct drm_i915_private *dev_priv,
ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT); ei->media_c0 = I915_READ(VLV_MEDIA_C0_COUNT);
} }
static bool vlv_c0_above(struct drm_i915_private *dev_priv,
const struct intel_rps_ei *old,
const struct intel_rps_ei *now,
int threshold)
{
u64 time, c0;
unsigned int mul = 100;
if (old->cz_clock == 0)
return false;
if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
mul <<= 8;
time = now->cz_clock - old->cz_clock;
time *= threshold * dev_priv->czclk_freq;
/* Workload can be split between render + media, e.g. SwapBuffers
* being blitted in X after being rendered in mesa. To account for
* this we need to combine both engines into our activity counter.
*/
c0 = now->render_c0 - old->render_c0;
c0 += now->media_c0 - old->media_c0;
c0 *= mul * VLV_CZ_CLOCK_TO_MILLI_SEC;
return c0 >= time;
}
void gen6_rps_reset_ei(struct drm_i915_private *dev_priv) void gen6_rps_reset_ei(struct drm_i915_private *dev_priv)
{ {
vlv_c0_read(dev_priv, &dev_priv->rps.down_ei); memset(&dev_priv->rps.ei, 0, sizeof(dev_priv->rps.ei));
dev_priv->rps.up_ei = dev_priv->rps.down_ei;
} }
static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir) static u32 vlv_wa_c0_ei(struct drm_i915_private *dev_priv, u32 pm_iir)
{ {
const struct intel_rps_ei *prev = &dev_priv->rps.ei;
struct intel_rps_ei now; struct intel_rps_ei now;
u32 events = 0; u32 events = 0;
if ((pm_iir & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED)) == 0) if ((pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) == 0)
return 0; return 0;
vlv_c0_read(dev_priv, &now); vlv_c0_read(dev_priv, &now);
if (now.cz_clock == 0) if (now.cz_clock == 0)
return 0; return 0;
if (pm_iir & GEN6_PM_RP_DOWN_EI_EXPIRED) { if (prev->cz_clock) {
if (!vlv_c0_above(dev_priv, u64 time, c0;
&dev_priv->rps.down_ei, &now, unsigned int mul;
dev_priv->rps.down_threshold))
events |= GEN6_PM_RP_DOWN_THRESHOLD; mul = VLV_CZ_CLOCK_TO_MILLI_SEC * 100; /* scale to threshold% */
dev_priv->rps.down_ei = now; if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
} mul <<= 8;
time = now.cz_clock - prev->cz_clock;
time *= dev_priv->czclk_freq;
/* Workload can be split between render + media,
* e.g. SwapBuffers being blitted in X after being rendered in
* mesa. To account for this we need to combine both engines
* into our activity counter.
*/
c0 = now.render_c0 - prev->render_c0;
c0 += now.media_c0 - prev->media_c0;
c0 *= mul;
if (pm_iir & GEN6_PM_RP_UP_EI_EXPIRED) { if (c0 > time * dev_priv->rps.up_threshold)
if (vlv_c0_above(dev_priv, events = GEN6_PM_RP_UP_THRESHOLD;
&dev_priv->rps.up_ei, &now, else if (c0 < time * dev_priv->rps.down_threshold)
dev_priv->rps.up_threshold)) events = GEN6_PM_RP_DOWN_THRESHOLD;
events |= GEN6_PM_RP_UP_THRESHOLD;
dev_priv->rps.up_ei = now;
} }
dev_priv->rps.ei = now;
return events; return events;
} }
...@@ -4390,7 +4373,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) ...@@ -4390,7 +4373,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
/* Let's track the enabled rps events */ /* Let's track the enabled rps events */
if (IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) if (IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
/* WaGsvRC0ResidencyMethod:vlv */ /* WaGsvRC0ResidencyMethod:vlv */
dev_priv->pm_rps_events = GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED; dev_priv->pm_rps_events = GEN6_PM_RP_UP_EI_EXPIRED;
else else
dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS; dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
......
...@@ -4411,8 +4411,9 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val) ...@@ -4411,8 +4411,9 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
{ {
u32 mask = 0; u32 mask = 0;
/* We use UP_EI_EXPIRED interupts for both up/down in manual mode */
if (val > dev_priv->rps.min_freq_softlimit) if (val > dev_priv->rps.min_freq_softlimit)
mask |= GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT; mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
if (val < dev_priv->rps.max_freq_softlimit) if (val < dev_priv->rps.max_freq_softlimit)
mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD; mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD;
...@@ -4516,7 +4517,7 @@ void gen6_rps_busy(struct drm_i915_private *dev_priv) ...@@ -4516,7 +4517,7 @@ void gen6_rps_busy(struct drm_i915_private *dev_priv)
{ {
mutex_lock(&dev_priv->rps.hw_lock); mutex_lock(&dev_priv->rps.hw_lock);
if (dev_priv->rps.enabled) { if (dev_priv->rps.enabled) {
if (dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED)) if (dev_priv->pm_rps_events & GEN6_PM_RP_UP_EI_EXPIRED)
gen6_rps_reset_ei(dev_priv); gen6_rps_reset_ei(dev_priv);
I915_WRITE(GEN6_PMINTRMSK, I915_WRITE(GEN6_PMINTRMSK,
gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq)); gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment