drm/i915: Use spinlocks for checking when to waitboost
In commit 1854d5ca0d
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date: Tue Apr 7 16:20:32 2015 +0100
drm/i915: Deminish contribution of wait-boosting from clients
we removed an atomic timer based check for allowing waitboosting and
moved it below the mutex taken during RPS. However, that mutex can be
held for long periods of time on Vallyview/Cherryview as communication
with the PCU is slow. As clients may frequently wait for results (e.g.
such as tranform feedback) we introduced contention between the client
and the RPS worker. We can take advantage of the RPS worker, by
switching the wait boost decision to use spin locks and defer the
actual reclocking to the worker.
Fixes a regression of up to 45% on Baytrail and Baswell!
v2 (Daniel):
- Use max_freq_softlimit instead of the not-yet-merged boost
frequency.
- Don't inject a fake irq into the boost work, instead treat
client_boost as just another legit waker.
v3: Drop the now unused mask (Chris).
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90112
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> (v1)
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:

committed by
Daniel Vetter

parent
21631f10ea
commit
8d3afd7d0e
@@ -4143,17 +4143,25 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
|
||||
dev_priv->rps.last_adj = 0;
|
||||
I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
|
||||
}
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
|
||||
spin_lock(&dev_priv->rps.client_lock);
|
||||
while (!list_empty(&dev_priv->rps.clients))
|
||||
list_del_init(dev_priv->rps.clients.next);
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
spin_unlock(&dev_priv->rps.client_lock);
|
||||
}
|
||||
|
||||
void gen6_rps_boost(struct drm_i915_private *dev_priv,
|
||||
struct intel_rps_client *rps,
|
||||
unsigned long submitted)
|
||||
{
|
||||
u32 val;
|
||||
/* This is intentionally racy! We peek at the state here, then
|
||||
* validate inside the RPS worker.
|
||||
*/
|
||||
if (!(dev_priv->mm.busy &&
|
||||
dev_priv->rps.enabled &&
|
||||
dev_priv->rps.cur_freq < dev_priv->rps.max_freq_softlimit))
|
||||
return;
|
||||
|
||||
/* Force a RPS boost (and don't count it against the client) if
|
||||
* the GPU is severely congested.
|
||||
@@ -4161,14 +4169,14 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv,
|
||||
if (rps && time_after(jiffies, submitted + DRM_I915_THROTTLE_JIFFIES))
|
||||
rps = NULL;
|
||||
|
||||
mutex_lock(&dev_priv->rps.hw_lock);
|
||||
val = dev_priv->rps.max_freq_softlimit;
|
||||
if (dev_priv->rps.enabled &&
|
||||
dev_priv->mm.busy &&
|
||||
dev_priv->rps.cur_freq < val &&
|
||||
(rps == NULL || list_empty(&rps->link))) {
|
||||
intel_set_rps(dev_priv->dev, val);
|
||||
dev_priv->rps.last_adj = 0;
|
||||
spin_lock(&dev_priv->rps.client_lock);
|
||||
if (rps == NULL || list_empty(&rps->link)) {
|
||||
spin_lock_irq(&dev_priv->irq_lock);
|
||||
if (dev_priv->rps.interrupts_enabled) {
|
||||
dev_priv->rps.client_boost = true;
|
||||
queue_work(dev_priv->wq, &dev_priv->rps.work);
|
||||
}
|
||||
spin_unlock_irq(&dev_priv->irq_lock);
|
||||
|
||||
if (rps != NULL) {
|
||||
list_add(&rps->link, &dev_priv->rps.clients);
|
||||
@@ -4176,7 +4184,7 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv,
|
||||
} else
|
||||
dev_priv->rps.boosts++;
|
||||
}
|
||||
mutex_unlock(&dev_priv->rps.hw_lock);
|
||||
spin_unlock(&dev_priv->rps.client_lock);
|
||||
}
|
||||
|
||||
void intel_set_rps(struct drm_device *dev, u8 val)
|
||||
@@ -6913,6 +6921,7 @@ void intel_pm_setup(struct drm_device *dev)
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
mutex_init(&dev_priv->rps.hw_lock);
|
||||
spin_lock_init(&dev_priv->rps.client_lock);
|
||||
|
||||
INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
|
||||
intel_gen6_powersave_work);
|
||||
|
Reference in New Issue
Block a user