Re: [Intel-gfx] [PATCH 43/49] drm/i915/bdw: Handle context switch events

2014-04-28 Thread Mateo Lozano, Oscar
 tmp = I915_READ(GEN8_GT_IIR(0));
 if (tmp) {
 ret = IRQ_HANDLED;
   +
 rcs = tmp  GEN8_RCS_IRQ_SHIFT;
   - bcs = tmp  GEN8_BCS_IRQ_SHIFT;
   + ring = dev_priv-ring[RCS];
 if (rcs  GT_RENDER_USER_INTERRUPT)
   - notify_ring(dev, dev_priv-ring[RCS]);
   + notify_ring(dev, ring);
   + if (rcs  GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
   + gen8_handle_context_events(ring);
  
  Handling the context events here can generate a new execlist submission,
  which if a small enough workload, can finish and generate a new context 
  event
  interrupt before we ack this interrupt.
  
  When we ack this interrupt, we clear the new one too, loosing an interrupt.
  
  Moving the
  
  I915_WRITE(GEN8_GT_IIR(0), tmp);
  
  to just inside the if (tmp) { conditional (or anywhere before this call) 
  fixes this
  issue. There is no harm in acking the interrupt immediately as we have the
  read stored in tmp.
  
 -Original Message-
 From: Daniel, Thomas
 Sent: Monday, April 28, 2014 10:58 AM
 To: Beckett, Robert; Mateo Lozano, Oscar; Barbalho, Rafael; Ewins, Jon
 Subject: RE: Re: [Intel-gfx] [PATCH 43/49] drm/i915/bdw: Handle context switch
 events
 
 Hi Bob,
 
 Looks like a good catch, and a sensible fix.
 
 Thomas.

I agree with Thomas. Will add to the next revision of the series.

Thanks!
Oscar
___
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx


Re: [Intel-gfx] [PATCH 43/49] drm/i915/bdw: Handle context switch events

2014-04-25 Thread Robert Beckett

On 27/03/2014 18:00, oscar.ma...@intel.com wrote:

From: Thomas Daniel thomas.dan...@intel.com

Handle all context status events in the context status buffer on every
context switch interrupt. We only remove work from the execlist queue
after a context status buffer reports that it has completed and we only
attempt to schedule new contexts on interrupt when a previously submitted
context completes (unless no contexts are queued, which means the GPU is
free).

Signed-off-by: Thomas Daniel thomas.dan...@intel.com

v2: Unreferencing the context when we are freeing the request might free
the backing bo, which requires the struct_mutex to be grabbed, so defer
unreferencing and freeing to a bottom half.

Signed-off-by: Oscar Mateo oscar.ma...@intel.com
---
  drivers/gpu/drm/i915/i915_drv.h |   3 +
  drivers/gpu/drm/i915/i915_irq.c |  28 ++---
  drivers/gpu/drm/i915/i915_lrc.c | 101 +++-
  drivers/gpu/drm/i915/intel_ringbuffer.c |   1 +
  drivers/gpu/drm/i915/intel_ringbuffer.h |   1 +
  5 files changed, 123 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 2607664..4c8cf52 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1679,6 +1679,8 @@ struct drm_i915_gem_request {

/** execlist queue entry for this request */
struct list_head execlist_link;
+   /** Struct to handle this request in the bottom half of an interrupt */
+   struct work_struct work;
  };

  struct drm_i915_file_private {
@@ -2344,6 +2346,7 @@ void gen8_gem_context_free(struct i915_hw_context *ctx);
  int gen8_switch_context_queue(struct intel_engine *ring,
  struct i915_hw_context *to,
  u32 tail);
+void gen8_handle_context_events(struct intel_engine *ring);

  /* i915_gem_evict.c */
  int __must_check i915_gem_evict_something(struct drm_device *dev,
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 56657b5..6e0f456 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1334,6 +1334,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device 
*dev,
   struct drm_i915_private *dev_priv,
   u32 master_ctl)
  {
+   struct intel_engine *ring;
u32 rcs, bcs, vcs, vecs;
uint32_t tmp = 0;
irqreturn_t ret = IRQ_NONE;
@@ -1342,14 +1343,21 @@ static irqreturn_t gen8_gt_irq_handler(struct 
drm_device *dev,
tmp = I915_READ(GEN8_GT_IIR(0));
if (tmp) {
ret = IRQ_HANDLED;
+
rcs = tmp  GEN8_RCS_IRQ_SHIFT;
-   bcs = tmp  GEN8_BCS_IRQ_SHIFT;
+   ring = dev_priv-ring[RCS];
if (rcs  GT_RENDER_USER_INTERRUPT)
-   notify_ring(dev, dev_priv-ring[RCS]);
+   notify_ring(dev, ring);
+   if (rcs  GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+   gen8_handle_context_events(ring);


Handling the context events here can generate a new execlist submission, 
which if a small enough workload, can finish and generate a new context 
event interrupt before we ack this interrupt.


When we ack this interrupt, we clear the new one too, loosing an interrupt.

Moving the

I915_WRITE(GEN8_GT_IIR(0), tmp);

to just inside the if (tmp) { conditional (or anywhere before this call) 
fixes this issue. There is no harm in acking the interrupt immediately 
as we have the read stored in tmp.




+
+   bcs = tmp  GEN8_BCS_IRQ_SHIFT;
+   ring = dev_priv-ring[BCS];
if (bcs  GT_RENDER_USER_INTERRUPT)
-   notify_ring(dev, dev_priv-ring[BCS]);
-   if ((rcs | bcs)  GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
-DRM_DEBUG_DRIVER(TODO: Context switch\n);
+   notify_ring(dev, ring);
+   if (bcs  GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+   gen8_handle_context_events(ring);
+
I915_WRITE(GEN8_GT_IIR(0), tmp);
} else
DRM_ERROR(The master control interrupt lied (GT0)!\n);
@@ -1360,10 +1368,11 @@ static irqreturn_t gen8_gt_irq_handler(struct 
drm_device *dev,
if (tmp) {
ret = IRQ_HANDLED;
vcs = tmp  GEN8_VCS1_IRQ_SHIFT;
+   ring = dev_priv-ring[VCS];
if (vcs  GT_RENDER_USER_INTERRUPT)
-   notify_ring(dev, dev_priv-ring[VCS]);
+   notify_ring(dev, ring);
if (vcs  GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
-

Re: [Intel-gfx] [PATCH 43/49] drm/i915/bdw: Handle context switch events

2014-04-09 Thread Mateo Lozano, Oscar
It seems to be completely managed by SW, for SW (or, at least, it does not seem 
to have any visible effect in the HW). But you are right, it is probably worth 
updating.

-- Oscar

 -Original Message-
 From: Lespiau, Damien
 Sent: Thursday, April 03, 2014 3:25 PM
 To: Mateo Lozano, Oscar
 Cc: intel-gfx@lists.freedesktop.org; Daniel, Thomas
 Subject: Re: [Intel-gfx] [PATCH 43/49] drm/i915/bdw: Handle context switch
 events
 
 On Thu, Mar 27, 2014 at 06:00:12PM +, oscar.ma...@intel.com wrote:
  +void gen8_handle_context_events(struct intel_engine *ring) {
  +   struct drm_i915_private *dev_priv = ring-dev-dev_private;
  +   u32 status_pointer;
  +   u8 read_pointer;
  +   u8 write_pointer;
  +   u32 status;
  +   u32 status_id;
  +   u32 submit_contexts = 0;
  +
  +   status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring));
  +
  +   read_pointer = ring-next_context_status_buffer;
  +   write_pointer = status_pointer  0x07;
  +   if (read_pointer  write_pointer)
  +   write_pointer += 6;
  +
  +   spin_lock(ring-execlist_lock);
  +
  +   while (read_pointer  write_pointer) {
  +   read_pointer++;
  +   status = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
  +   (read_pointer % 6) * 8);
  +   status_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
  +   (read_pointer % 6) * 8 + 4);
  +
  +   if (status  GEN8_CTX_STATUS_ELEMENT_SWITCH) {
  +   if (check_remove_request(ring, status_id))
  +   submit_contexts++;
  +   } else if (status  GEN8_CTX_STATUS_COMPLETE) {
  +   if (check_remove_request(ring, status_id))
  +   submit_contexts++;
  +   }
  +   }
  +
  +   if (submit_contexts != 0)
  +   gen8_switch_context_unqueue(ring);
  +
  +   spin_unlock(ring-execlist_lock);
  +
  +   WARN(submit_contexts  2, More than two context complete
 events?\n);
  +   ring-next_context_status_buffer = write_pointer % 6; }
 
 I'm a bit suprised that we never update the read pointer in the
 CONTEXT_STATUS_PTR when we consume entries from
 CONTEXT_STATUS_BUF.
 
 Are we sure this field isn't used by hw at all to figure out if the circular 
 buffer
 has some free space?
 
 --
 Damien
___
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx


Re: [Intel-gfx] [PATCH 43/49] drm/i915/bdw: Handle context switch events

2014-04-03 Thread Damien Lespiau
On Thu, Mar 27, 2014 at 06:00:12PM +, oscar.ma...@intel.com wrote:
 +void gen8_handle_context_events(struct intel_engine *ring)
 +{
 + struct drm_i915_private *dev_priv = ring-dev-dev_private;
 + u32 status_pointer;
 + u8 read_pointer;
 + u8 write_pointer;
 + u32 status;
 + u32 status_id;
 + u32 submit_contexts = 0;
 +
 + status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring));
 +
 + read_pointer = ring-next_context_status_buffer;
 + write_pointer = status_pointer  0x07;
 + if (read_pointer  write_pointer)
 + write_pointer += 6;
 +
 + spin_lock(ring-execlist_lock);
 +
 + while (read_pointer  write_pointer) {
 + read_pointer++;
 + status = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
 + (read_pointer % 6) * 8);
 + status_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
 + (read_pointer % 6) * 8 + 4);
 +
 + if (status  GEN8_CTX_STATUS_ELEMENT_SWITCH) {
 + if (check_remove_request(ring, status_id))
 + submit_contexts++;
 + } else if (status  GEN8_CTX_STATUS_COMPLETE) {
 + if (check_remove_request(ring, status_id))
 + submit_contexts++;
 + }
 + }
 +
 + if (submit_contexts != 0)
 + gen8_switch_context_unqueue(ring);
 +
 + spin_unlock(ring-execlist_lock);
 +
 + WARN(submit_contexts  2, More than two context complete events?\n);
 + ring-next_context_status_buffer = write_pointer % 6;
 +}

I'm a bit suprised that we never update the read pointer in the
CONTEXT_STATUS_PTR when we consume entries from CONTEXT_STATUS_BUF.

Are we sure this field isn't used by hw at all to figure out if the
circular buffer has some free space?

-- 
Damien
___
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx


[Intel-gfx] [PATCH 43/49] drm/i915/bdw: Handle context switch events

2014-03-27 Thread oscar . mateo
From: Thomas Daniel thomas.dan...@intel.com

Handle all context status events in the context status buffer on every
context switch interrupt. We only remove work from the execlist queue
after a context status buffer reports that it has completed and we only
attempt to schedule new contexts on interrupt when a previously submitted
context completes (unless no contexts are queued, which means the GPU is
free).

Signed-off-by: Thomas Daniel thomas.dan...@intel.com

v2: Unreferencing the context when we are freeing the request might free
the backing bo, which requires the struct_mutex to be grabbed, so defer
unreferencing and freeing to a bottom half.

Signed-off-by: Oscar Mateo oscar.ma...@intel.com
---
 drivers/gpu/drm/i915/i915_drv.h |   3 +
 drivers/gpu/drm/i915/i915_irq.c |  28 ++---
 drivers/gpu/drm/i915/i915_lrc.c | 101 +++-
 drivers/gpu/drm/i915/intel_ringbuffer.c |   1 +
 drivers/gpu/drm/i915/intel_ringbuffer.h |   1 +
 5 files changed, 123 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 2607664..4c8cf52 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1679,6 +1679,8 @@ struct drm_i915_gem_request {
 
/** execlist queue entry for this request */
struct list_head execlist_link;
+   /** Struct to handle this request in the bottom half of an interrupt */
+   struct work_struct work;
 };
 
 struct drm_i915_file_private {
@@ -2344,6 +2346,7 @@ void gen8_gem_context_free(struct i915_hw_context *ctx);
 int gen8_switch_context_queue(struct intel_engine *ring,
  struct i915_hw_context *to,
  u32 tail);
+void gen8_handle_context_events(struct intel_engine *ring);
 
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct drm_device *dev,
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 56657b5..6e0f456 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1334,6 +1334,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device 
*dev,
   struct drm_i915_private *dev_priv,
   u32 master_ctl)
 {
+   struct intel_engine *ring;
u32 rcs, bcs, vcs, vecs;
uint32_t tmp = 0;
irqreturn_t ret = IRQ_NONE;
@@ -1342,14 +1343,21 @@ static irqreturn_t gen8_gt_irq_handler(struct 
drm_device *dev,
tmp = I915_READ(GEN8_GT_IIR(0));
if (tmp) {
ret = IRQ_HANDLED;
+
rcs = tmp  GEN8_RCS_IRQ_SHIFT;
-   bcs = tmp  GEN8_BCS_IRQ_SHIFT;
+   ring = dev_priv-ring[RCS];
if (rcs  GT_RENDER_USER_INTERRUPT)
-   notify_ring(dev, dev_priv-ring[RCS]);
+   notify_ring(dev, ring);
+   if (rcs  GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+   gen8_handle_context_events(ring);
+
+   bcs = tmp  GEN8_BCS_IRQ_SHIFT;
+   ring = dev_priv-ring[BCS];
if (bcs  GT_RENDER_USER_INTERRUPT)
-   notify_ring(dev, dev_priv-ring[BCS]);
-   if ((rcs | bcs)  GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
-DRM_DEBUG_DRIVER(TODO: Context switch\n);
+   notify_ring(dev, ring);
+   if (bcs  GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+   gen8_handle_context_events(ring);
+
I915_WRITE(GEN8_GT_IIR(0), tmp);
} else
DRM_ERROR(The master control interrupt lied (GT0)!\n);
@@ -1360,10 +1368,11 @@ static irqreturn_t gen8_gt_irq_handler(struct 
drm_device *dev,
if (tmp) {
ret = IRQ_HANDLED;
vcs = tmp  GEN8_VCS1_IRQ_SHIFT;
+   ring = dev_priv-ring[VCS];
if (vcs  GT_RENDER_USER_INTERRUPT)
-   notify_ring(dev, dev_priv-ring[VCS]);
+   notify_ring(dev, ring);
if (vcs  GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
-DRM_DEBUG_DRIVER(TODO: Context switch\n);
+   gen8_handle_context_events(ring);
I915_WRITE(GEN8_GT_IIR(1), tmp);
} else
DRM_ERROR(The master control interrupt lied (GT1)!\n);
@@ -1374,10 +1383,11 @@ static irqreturn_t gen8_gt_irq_handler(struct 
drm_device *dev,
if (tmp) {
ret = IRQ_HANDLED;
vecs = tmp  GEN8_VECS_IRQ_SHIFT;
+   ring = dev_priv-ring[VECS];
if (vecs