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