Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f68d591 authored by Chris Wilson's avatar Chris Wilson Committed by Jani Nikula
Browse files

drm/i915: Stop using RP_DOWN_EI on Baytrail



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>
Cc: <stable@vger.kernel.org> # v4.1+
Link: http://patchwork.freedesktop.org/patch/msgid/20170309211232.28878-1-chris@chris-wilson.co.uk


Reviewed-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>
parent 0f5418e5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1325,7 +1325,7 @@ struct intel_gen6_power_mgmt {
	unsigned boosts;

	/* 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.
+28 −45
Original line number Diff line number Diff line
@@ -1046,68 +1046,51 @@ static void vlv_c0_read(struct drm_i915_private *dev_priv,
	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)
{
	vlv_c0_read(dev_priv, &dev_priv->rps.down_ei);
	dev_priv->rps.up_ei = dev_priv->rps.down_ei;
	memset(&dev_priv->rps.ei, 0, sizeof(dev_priv->rps.ei));
}

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;
	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;

	vlv_c0_read(dev_priv, &now);
	if (now.cz_clock == 0)
		return 0;

	if (pm_iir & GEN6_PM_RP_DOWN_EI_EXPIRED) {
		if (!vlv_c0_above(dev_priv,
				  &dev_priv->rps.down_ei, &now,
				  dev_priv->rps.down_threshold))
			events |= GEN6_PM_RP_DOWN_THRESHOLD;
		dev_priv->rps.down_ei = now;
	}
	if (prev->cz_clock) {
		u64 time, c0;
		unsigned int mul;

		mul = VLV_CZ_CLOCK_TO_MILLI_SEC * 100; /* scale to threshold% */
		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 (vlv_c0_above(dev_priv,
				 &dev_priv->rps.up_ei, &now,
				 dev_priv->rps.up_threshold))
			events |= GEN6_PM_RP_UP_THRESHOLD;
		dev_priv->rps.up_ei = now;
		if (c0 > time * dev_priv->rps.up_threshold)
			events = GEN6_PM_RP_UP_THRESHOLD;
		else if (c0 < time * dev_priv->rps.down_threshold)
			events = GEN6_PM_RP_DOWN_THRESHOLD;
	}

	dev_priv->rps.ei = now;
	return events;
}

@@ -4228,7 +4211,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
	/* Let's track the enabled rps events */
	if (IS_VALLEYVIEW(dev_priv))
		/* 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
		dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;

+3 −2
Original line number Diff line number Diff line
@@ -4928,8 +4928,9 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
{
	u32 mask = 0;

	/* We use UP_EI_EXPIRED interupts for both up/down in manual mode */
	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)
		mask |= GEN6_PM_RP_UP_EI_EXPIRED | GEN6_PM_RP_UP_THRESHOLD;

@@ -5039,7 +5040,7 @@ void gen6_rps_busy(struct drm_i915_private *dev_priv)
{
	mutex_lock(&dev_priv->rps.hw_lock);
	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);
		I915_WRITE(GEN6_PMINTRMSK,
			   gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));