[PATCH 2/4] drm/i915: Introduce a cancellable wrapper for delayed resume tasks

Chris Wilson chris at chris-wilson.co.uk
Mon May 16 11:26:41 UTC 2016


Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_dma.c |  7 ++++
 drivers/gpu/drm/i915/i915_drv.c | 89 +++++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_drv.h | 16 ++++++++
 3 files changed, 112 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 65a593ac8148..00a0eb40e79b 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1094,6 +1094,12 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
 	if (ret < 0)
 		return ret;
 
+	ret = intel_async_resume_init(&dev_priv->async_resume);
+	if (ret < 0) {
+		i915_workqueues_cleanup(dev_priv);
+		return ret;
+	}
+
 	/* This must be called before any calls to HAS_PCH_* */
 	intel_detect_pch(dev);
 
@@ -1128,6 +1134,7 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
 static void i915_driver_cleanup_early(struct drm_i915_private *dev_priv)
 {
 	i915_gem_load_cleanup(dev_priv->dev);
+	intel_async_resume_cleanup(&dev_priv->async_resume);
 	i915_workqueues_cleanup(dev_priv);
 }
 
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index dba03c026151..a4253e0426ba 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -580,6 +580,93 @@ static bool suspend_to_idle(struct drm_i915_private *dev_priv)
 	return false;
 }
 
+struct intel_async_resume_cb {
+	struct delayed_work work;
+	struct list_head link;
+
+	struct drm_i915_private *i915;
+	void (*func)(struct drm_i915_private *);
+};
+
+int intel_async_resume_init(struct intel_async_resume *ar)
+{
+	ar->wq = alloc_workqueue("i915-resume", WQ_UNBOUND, 0);
+	if (ar->wq == NULL)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&ar->list);
+	spin_lock_init(&ar->lock);
+	return 0;
+}
+
+static void intel_async_resume_cb(struct work_struct *dwork)
+{
+	struct intel_async_resume_cb *cb =
+		container_of(dwork, typeof(*cb), work.work);
+	bool cancelled;
+
+	spin_lock(&cb->i915->async_resume.lock);
+	cancelled = list_empty(&cb->link);
+	if (!cancelled)
+		list_del_init(&cb->link);
+	spin_unlock(&cb->i915->async_resume.lock);
+	if (cancelled)
+		return;
+
+	cb->func(cb->i915);
+	kfree(cb);
+}
+
+void intel_async_resume(struct intel_async_resume *ar,
+		       void (*func)(struct drm_i915_private *),
+		       int delay_ms)
+{
+	struct drm_i915_private *dev_priv =
+		container_of(ar, struct drm_i915_private, async_resume);
+	struct intel_async_resume_cb *cb;
+
+	cb = kmalloc(sizeof(*cb), GFP_ATOMIC);
+	if (!cb)
+		return func(dev_priv);
+
+	cb->i915 = dev_priv;
+	cb->func = func;
+
+	INIT_DELAYED_WORK(&cb->work, intel_async_resume_cb);
+
+	spin_lock(&ar->lock);
+	list_add(&cb->link, &ar->list);
+	spin_unlock(&ar->lock);
+
+	queue_delayed_work(ar->wq, &cb->work, msecs_to_jiffies(delay_ms));
+}
+
+static void intel_cancel_async_resume(struct drm_i915_private *dev_priv)
+{
+	struct intel_async_resume *ar = &dev_priv->async_resume;
+
+	spin_lock(&ar->lock);
+	while (!list_empty(&ar->list)) {
+		struct intel_async_resume_cb *cb =
+			list_first_entry(&ar->list, typeof(*cb), link);
+
+		list_del_init(&cb->link);
+		spin_unlock(&ar->lock);
+
+		if (cancel_delayed_work_sync(&cb->work))
+			kfree(cb);
+
+		spin_lock(&ar->lock);
+	}
+	spin_unlock(&ar->lock);
+}
+
+void intel_async_resume_cleanup(struct intel_async_resume *ar)
+{
+	WARN_ON(!list_empty(&ar->list));
+	destroy_workqueue(ar->wq);
+}
+
 static int i915_drm_suspend(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -593,6 +680,8 @@ static int i915_drm_suspend(struct drm_device *dev)
 
 	disable_rpm_wakeref_asserts(dev_priv);
 
+	intel_cancel_async_resume(dev_priv);
+
 	/* We do a lot of poking in a lot of registers, make sure they work
 	 * properly. */
 	intel_display_set_init_power(dev_priv, true);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 72f0b02a8372..e16f1f99d695 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1924,6 +1924,12 @@ struct drm_i915_private {
 	struct work_struct fbdev_suspend_work;
 #endif
 
+	struct intel_async_resume {
+		struct spinlock lock;
+		struct list_head list;
+		struct workqueue_struct *wq;
+	} async_resume;
+
 	struct drm_property *broadcast_rgb_property;
 	struct drm_property *force_audio_property;
 
@@ -3499,6 +3505,16 @@ int i915_parse_cmds(struct intel_engine_cs *engine,
 		    u32 batch_len,
 		    bool is_master);
 
+int intel_async_resume_init(struct intel_async_resume *ar);
+void intel_async_resume(struct intel_async_resume *ar,
+			void (*func)(struct drm_i915_private *),
+			int delay_ms);
+static inline void intel_async_resume_flush(struct intel_async_resume *ar)
+{
+	flush_workqueue(ar->wq);
+}
+void intel_async_resume_cleanup(struct intel_async_resume *ar);
+
 /* i915_suspend.c */
 extern int i915_save_state(struct drm_device *dev);
 extern int i915_restore_state(struct drm_device *dev);
-- 
2.8.1



More information about the Intel-gfx-trybot mailing list