[RFC] [PATCH] drm/i915: Busy-wait for the seqno to update after an IRQ

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



One issue we face is where the chipset is not yet as coherent as it
should be, and the interrupt arrives before the seqno is written into
the CPU cache. (NB, this is usually due to a missing bit of register
setup and should be resolved in the future.) In the meantime, in order
to begin performance testing, albeit at the cost of extra power
consumption, enable the driver to spin upon the seqno after the irq
arrives.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---

An experimental patch to sketch out Keith's variation of spinning only
upon receipt of the interrupt. Please review and test.
-Chris

---
 drivers/gpu/drm/i915/i915_drv.c         |    2 +-
 drivers/gpu/drm/i915/i915_drv.h         |    1 +
 drivers/gpu/drm/i915/i915_irq.c         |    3 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c |   33 +++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_ringbuffer.h |    1 +
 5 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 36e2938..7d6f078 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -107,7 +107,7 @@ unsigned int i915_irq_notify __read_mostly = I915_IRQ_NOTIFY_INTERRUPT;
 module_param_named(irq_notify, i915_irq_notify, int, 0600);
 MODULE_PARM_DESC(irq_notify,
 		"Choose the request notification method, can be any "
-		"combination of irq (0x1) or polling (0x2). "
+		"combination of irq (0x1), polling (0x2) or spinning-on-irq (0x4). "
 		"WARNING: Selecting no method will result in busy-waits. "
 		"(default: is to use irq only)");
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 49fa8e9..96a7e00 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1009,6 +1009,7 @@ extern bool i915_enable_hangcheck __read_mostly;
 extern unsigned int i915_irq_notify __read_mostly;
 #define I915_IRQ_NOTIFY_INTERRUPT	0x1
 #define I915_IRQ_NOTIFY_POLL		0x2
+#define I915_IRQ_NOTIFY_SPIN		0x4
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b52bbf0..50f95fd 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -370,6 +370,9 @@ static void notify_ring(struct drm_device *dev,
 			  jiffies +
 			  msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 	}
+
+	if (ring->irq_notify & I915_IRQ_NOTIFY_SPIN)
+		queue_work(dev_priv->wq, &ring->irq_work);
 }
 
 static void gen6_pm_rps_work(struct work_struct *work)
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 5b8db53..b653d76 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -261,6 +261,25 @@ u32 intel_ring_get_active_head(struct intel_ring_buffer *ring)
 	return I915_READ(acthd_reg);
 }
 
+static void intel_ring_irq_work(struct work_struct *work)
+{
+	struct intel_ring_buffer *ring =
+		container_of(work, struct intel_ring_buffer, irq_work);
+	int spin = 100;
+
+	do {
+		/* XXX spot the missing memory barriers */
+		u32 seqno = ring->waiting_seqno;
+		if (seqno == 0)
+			break;
+
+		if (i915_seqno_passed(ring->get_seqno(ring), seqno)) {
+			wake_up_all(&ring->irq_queue);
+			break;
+		}
+	} while (--spin && ring->irq_notify);
+}
+
 static void intel_ring_irq_elapsed(unsigned long data)
 {
 	struct intel_ring_buffer *ring = (struct intel_ring_buffer *)data;
@@ -335,6 +354,8 @@ static int init_ring_common(struct intel_ring_buffer *ring)
 
 	setup_timer(&ring->irq_timer, intel_ring_irq_elapsed,
 		    (unsigned long) ring);
+	INIT_WORK(&ring->irq_work, intel_ring_irq_work);
+
 	return 0;
 }
 
@@ -1566,10 +1587,18 @@ void intel_ring_put_irq(struct intel_ring_buffer *ring)
 {
 	spin_lock(&ring->irq_lock);
 	if (--ring->irq_refcount == 0) {
-		if (ring->irq_notify & I915_IRQ_NOTIFY_POLL)
+		unsigned irq_notify;
+
+		irq_notify = ring->irq_notify;
+		ring->irq_notify = 0;
+
+		if (irq_notify & I915_IRQ_NOTIFY_SPIN)
+			cancel_work_sync(&ring->irq_work);
+
+		if (irq_notify & I915_IRQ_NOTIFY_POLL)
 			del_timer(&ring->irq_timer);
 
-		if (ring->irq_notify & I915_IRQ_NOTIFY_INTERRUPT)
+		if (irq_notify & I915_IRQ_NOTIFY_INTERRUPT)
 			ring->irq_put(ring);
 	}
 	spin_unlock(&ring->irq_lock);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index eb60f12..69d08c8 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -55,6 +55,7 @@ struct  intel_ring_buffer {
 	spinlock_t	irq_lock;
 	u32		irq_refcount;
 	struct timer_list irq_timer;
+	struct work_struct irq_work;
 	u32		irq_mask;
 	u32		irq_seqno;		/* last seq seem at irq time */
 	unsigned int    irq_notify;
-- 
1.7.7.3


[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux