[Intel-gfx] [PATCH 01/25] drm/i915: Add ring_notify mechanism

ville.syrjala at linux.intel.com ville.syrjala at linux.intel.com
Wed Jun 18 19:58:34 CEST 2014


From: Ville Syrjälä <ville.syrjala at linux.intel.com>

Proveide a ring notify mechanism where you can ask for a callback when a
specific seqno has been passed.

Can be used for FBC and mmio flips at least.

Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
 drivers/gpu/drm/i915/i915_gem.c         | 10 ++++
 drivers/gpu/drm/i915/i915_irq.c         |  4 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c | 89 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h | 17 +++++++
 4 files changed, 120 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index d857f58..a5e62cb 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2521,6 +2521,8 @@ static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
 static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
 					struct intel_engine_cs *ring)
 {
+	struct intel_ring_notify *notify, *next;
+
 	while (!list_empty(&ring->active_list)) {
 		struct drm_i915_gem_object *obj;
 
@@ -2552,6 +2554,14 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
 	kfree(ring->preallocated_lazy_request);
 	ring->preallocated_lazy_request = NULL;
 	ring->outstanding_lazy_seqno = 0;
+
+	spin_lock_irq(&ring->lock);
+	list_for_each_entry_safe(notify, next, &ring->notify_list, list) {
+		intel_ring_notify_complete(notify);
+		/* FIXME should we notify at reset? */
+		notify->notify(notify);
+	}
+	spin_unlock_irq(&ring->lock);
 }
 
 void i915_gem_restore_fences(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 1c1ec22..218f011 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1221,6 +1221,10 @@ static void notify_ring(struct drm_device *dev,
 	if (drm_core_check_feature(dev, DRIVER_MODESET))
 		intel_notify_mmio_flip(ring);
 
+	spin_lock(&ring->lock);
+	intel_ring_notify_check(ring);
+	spin_unlock(&ring->lock);
+
 	wake_up_all(&ring->irq_queue);
 	i915_queue_hangcheck(dev);
 }
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index b96edaf..31321ae 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1447,6 +1447,9 @@ static int intel_init_ring_buffer(struct drm_device *dev,
 
 	init_waitqueue_head(&ring->irq_queue);
 
+	INIT_LIST_HEAD(&ring->notify_list);
+	spin_lock_init(&ring->lock);
+
 	if (I915_NEED_GFX_HWS(dev)) {
 		ret = init_status_page(ring);
 		if (ret)
@@ -2407,3 +2410,89 @@ intel_stop_ring_buffer(struct intel_engine_cs *ring)
 
 	stop_ring(ring);
 }
+
+void intel_ring_notify_complete(struct intel_ring_notify *notify)
+{
+	struct intel_engine_cs *ring = notify->ring;
+
+	ring->irq_put(ring);
+	list_del(&notify->list);
+	notify->ring = NULL;
+}
+
+void intel_ring_notify_check(struct intel_engine_cs *ring)
+{
+	struct intel_ring_notify *notify, *next;
+	u32 seqno;
+
+	assert_spin_locked(&ring->lock);
+
+	if (list_empty(&ring->notify_list))
+		return;
+
+	seqno = ring->get_seqno(ring, false);
+
+	list_for_each_entry_safe(notify, next, &ring->notify_list, list) {
+		if (i915_seqno_passed(seqno, notify->seqno)) {
+			intel_ring_notify_complete(notify);
+			notify->notify(notify);
+		}
+	}
+}
+
+int intel_ring_notify_add(struct intel_engine_cs *ring,
+			  struct intel_ring_notify *notify)
+{
+	unsigned long irqflags;
+	int ret;
+
+	lockdep_assert_held(&ring->dev->struct_mutex);
+
+	if (WARN_ON(notify->ring != NULL || notify->seqno == 0))
+		return -EINVAL;
+
+	if (i915_seqno_passed(ring->get_seqno(ring, true), notify->seqno))
+		goto notify_immediately;
+
+	ret = i915_gem_check_olr(ring, notify->seqno);
+	if (ret)
+		return ret;
+
+	if (WARN_ON(!ring->irq_get(ring)))
+		goto notify_immediately;
+
+	spin_lock_irqsave(&ring->lock, irqflags);
+	notify->ring = ring;
+	list_add_tail(&notify->list, &ring->notify_list);
+	/* check again in case we just missed it */
+	intel_ring_notify_check(ring);
+	spin_unlock_irqrestore(&ring->lock, irqflags);
+
+	return 0;
+
+ notify_immediately:
+	spin_lock_irqsave(&ring->lock, irqflags);
+	notify->notify(notify);
+	spin_unlock_irqrestore(&ring->lock, irqflags);
+
+	return 0;
+}
+
+bool intel_ring_notify_pending(struct intel_ring_notify *notify)
+{
+	return notify->ring != NULL;
+}
+
+void intel_ring_notify_cancel(struct intel_ring_notify *notify)
+{
+	struct intel_engine_cs *ring = ACCESS_ONCE(notify->ring);
+	unsigned long irqflags;
+
+	if (!ring)
+		return;
+
+	spin_lock_irqsave(&ring->lock, irqflags);
+	if (notify->ring)
+		intel_ring_notify_complete(notify);
+	spin_unlock_irqrestore(&ring->lock, irqflags);
+}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index e72017b..273abf3 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -79,6 +79,13 @@ struct intel_ringbuffer {
 	u32 last_retired_head;
 };
 
+struct intel_ring_notify {
+	void (*notify)(struct intel_ring_notify *notify);
+	struct intel_engine_cs *ring;
+	struct list_head list;
+	u32 seqno;
+};
+
 struct  intel_engine_cs {
 	const char	*name;
 	enum intel_ring_id {
@@ -217,6 +224,9 @@ struct  intel_engine_cs {
 	 * to encode the command length in the header).
 	 */
 	u32 (*get_cmd_length_mask)(u32 cmd_header);
+
+	struct list_head notify_list;
+	spinlock_t lock;
 };
 
 static inline bool
@@ -335,6 +345,13 @@ static inline void i915_trace_irq_get(struct intel_engine_cs *ring, u32 seqno)
 		ring->trace_irq_seqno = seqno;
 }
 
+void intel_ring_notify_complete(struct intel_ring_notify *notify);
+void intel_ring_notify_check(struct intel_engine_cs *ring);
+int __must_check intel_ring_notify_add(struct intel_engine_cs *ring,
+				       struct intel_ring_notify *notify);
+bool intel_ring_notify_pending(struct intel_ring_notify *notify);
+void intel_ring_notify_cancel(struct intel_ring_notify *notify);
+
 /* DRI warts */
 int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size);
 
-- 
1.8.5.5




More information about the Intel-gfx mailing list