[PATCH] drm/i915: Keep user GGTT alive for a minimum of 250ms

Chris Wilson chris at chris-wilson.co.uk
Thu May 23 19:41:27 UTC 2019


Do not allow runtime pm autosuspend to remove userspace GGTT mmaps too
quickly. For example, igt sets the autosuspend delay to 0, and so we
immediately attempt to perform runtime suspend upon releasing the
wakeref. Unfortunately, that involves tearing down GGTT mmaps as they
require an active device.

Override the autosuspend for GGTT mmaps, by keeping the wakeref around
for 250ms after populating the PTE for a fresh mmap.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala at linux.intel.com>
---
 drivers/gpu/drm/i915/Kconfig.profile |  4 +++
 drivers/gpu/drm/i915/i915_drv.h      |  3 ++
 drivers/gpu/drm/i915/i915_gem.c      |  6 ++++
 drivers/gpu/drm/i915/intel_wakeref.c | 47 ++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_wakeref.h | 14 +++++++++
 5 files changed, 74 insertions(+)

diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile
index 0e5db98da8f3..0f997e221868 100644
--- a/drivers/gpu/drm/i915/Kconfig.profile
+++ b/drivers/gpu/drm/i915/Kconfig.profile
@@ -1,3 +1,7 @@
+config DRM_I915_USERFAULT_AUTOSUSPEND
+	int
+	default 250 # milliseconds
+
 config DRM_I915_SPIN_REQUEST
 	int
 	default 5 # microseconds
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 311e19154672..41dad8889eaa 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -874,6 +874,9 @@ struct i915_gem_mm {
 	 */
 	struct list_head userfault_list;
 
+	/* Manual runtime pm autosuspend delay for user GGTT mmaps */
+	struct intel_wakeref_auto userfault_wakeref;
+
 	/**
 	 * List of objects which are pending destruction.
 	 */
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index d3b7dac527dc..7207678110eb 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1834,6 +1834,8 @@ vm_fault_t i915_gem_fault(struct vm_fault *vmf)
 	assert_rpm_wakelock_held(dev_priv);
 	if (!i915_vma_set_userfault(vma) && !obj->userfault_count++)
 		list_add(&obj->userfault_link, &dev_priv->mm.userfault_list);
+	intel_wakeref_auto(&dev_priv->mm.userfault_wakeref,
+			   msecs_to_jiffies_timeout(CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND));
 	GEM_BUG_ON(!obj->userfault_count);
 
 	i915_vma_set_ggtt_write(vma);
@@ -4671,6 +4673,8 @@ void i915_gem_fini(struct drm_i915_private *dev_priv)
 {
 	GEM_BUG_ON(dev_priv->gt.awake);
 
+	intel_wakeref_auto_fini(&dev_priv->mm.userfault_wakeref);
+
 	i915_gem_suspend_late(dev_priv);
 	intel_disable_gt_powersave(dev_priv);
 
@@ -4748,6 +4752,8 @@ static void i915_gem_init__mm(struct drm_i915_private *i915)
 	INIT_LIST_HEAD(&i915->mm.fence_list);
 	INIT_LIST_HEAD(&i915->mm.userfault_list);
 
+	intel_wakeref_auto_init(&i915->mm.userfault_wakeref, i915);
+
 	INIT_WORK(&i915->mm.free_work, __i915_gem_free_work);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c
index 91196d9612bb..49764bf82f96 100644
--- a/drivers/gpu/drm/i915/intel_wakeref.c
+++ b/drivers/gpu/drm/i915/intel_wakeref.c
@@ -73,3 +73,50 @@ void __intel_wakeref_init(struct intel_wakeref *wf, struct lock_class_key *key)
 	atomic_set(&wf->count, 0);
 	wf->wakeref = 0;
 }
+
+static void wakeref_auto_timeout(struct timer_list *t)
+{
+	struct intel_wakeref_auto *wf = from_timer(wf, t, timer);
+	intel_wakeref_t wakeref = 0;
+
+	if (atomic_dec_and_lock(&wf->count, &wf->lock)) {
+		wakeref = fetch_and_zero(&wf->wakeref);
+		spin_unlock(&wf->lock);
+	}
+
+	if (wakeref)
+		intel_runtime_pm_put(wf->i915, wakeref);
+}
+
+void intel_wakeref_auto_init(struct intel_wakeref_auto *wf,
+			     struct drm_i915_private *i915)
+{
+	spin_lock_init(&wf->lock);
+	timer_setup(&wf->timer, wakeref_auto_timeout, 0);
+	atomic_set(&wf->count, 0);
+	wf->wakeref = 0;
+	wf->i915 = i915;
+}
+
+void intel_wakeref_auto(struct intel_wakeref_auto *wf, long timeout)
+{
+	assert_rpm_wakelock_held(wf->i915);
+
+	spin_lock(&wf->lock);
+	if (!atomic_fetch_inc(&wf->count)) {
+		GEM_BUG_ON(wf->wakeref);
+		wf->wakeref = intel_runtime_pm_get_if_in_use(wf->i915);
+	}
+	spin_unlock(&wf->lock);
+
+	if (mod_timer(&wf->timer, jiffies + timeout))
+		wakeref_auto_timeout(&wf->timer);
+}
+
+void intel_wakeref_auto_fini(struct intel_wakeref_auto *wf)
+{
+	if (del_timer_sync(&wf->timer))
+		wakeref_auto_timeout(&wf->timer);
+
+	GEM_BUG_ON(wf->wakeref);
+}
diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/intel_wakeref.h
index db742291211c..52e1d7939d2a 100644
--- a/drivers/gpu/drm/i915/intel_wakeref.h
+++ b/drivers/gpu/drm/i915/intel_wakeref.h
@@ -10,6 +10,7 @@
 #include <linux/atomic.h>
 #include <linux/mutex.h>
 #include <linux/stackdepot.h>
+#include <linux/timer.h>
 
 struct drm_i915_private;
 
@@ -130,4 +131,17 @@ intel_wakeref_active(struct intel_wakeref *wf)
 	return READ_ONCE(wf->wakeref);
 }
 
+struct intel_wakeref_auto {
+	struct drm_i915_private *i915;
+	struct timer_list timer;
+	intel_wakeref_t wakeref;
+	spinlock_t lock;
+	atomic_t count;
+};
+
+void intel_wakeref_auto_init(struct intel_wakeref_auto *wf,
+			     struct drm_i915_private *i915);
+void intel_wakeref_auto(struct intel_wakeref_auto *wf, long timeout);
+void intel_wakeref_auto_fini(struct intel_wakeref_auto *wf);
+
 #endif /* INTEL_WAKEREF_H */
-- 
2.20.1



More information about the Intel-gfx-trybot mailing list