From: Robert Beckett <robert.beckett@intel.com>
To: oscar.mateo@intel.com, intel-gfx@lists.freedesktop.org
Cc: Thomas Daniel <thomas.daniel@intel.com>
Subject: Re: [PATCH 43/49] drm/i915/bdw: Handle context switch events
Date: Sat, 26 Apr 2014 01:53:18 +0100 [thread overview]
Message-ID: <535B037E.1090109@intel.com> (raw)
In-Reply-To: <1395943218-7708-44-git-send-email-oscar.mateo@intel.com>
On 27/03/2014 18:00, oscar.mateo@intel.com wrote:
> From: Thomas Daniel <thomas.daniel@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.daniel@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.mateo@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)
> - 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 & GT_RENDER_USER_INTERRUPT)
> - notify_ring(dev, &dev_priv->ring[VECS]);
> + notify_ring(dev, ring);
> if (vecs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
> - DRM_DEBUG_DRIVER("TODO: Context switch\n");
> + gen8_handle_context_events(ring);
> I915_WRITE(GEN8_GT_IIR(3), tmp);
> } else
> DRM_ERROR("The master control interrupt lied (GT3)!\n");
> diff --git a/drivers/gpu/drm/i915/i915_lrc.c b/drivers/gpu/drm/i915/i915_lrc.c
> index 4cacabb..440da11 100644
> --- a/drivers/gpu/drm/i915/i915_lrc.c
> +++ b/drivers/gpu/drm/i915/i915_lrc.c
> @@ -46,7 +46,24 @@
> #define GEN8_LR_CONTEXT_SIZE (21 * PAGE_SIZE)
>
> #define RING_ELSP(ring) ((ring)->mmio_base+0x230)
> +#define RING_EXECLIST_STATUS(ring) ((ring)->mmio_base+0x234)
> #define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244)
> +#define RING_CONTEXT_STATUS_BUF(ring) ((ring)->mmio_base+0x370)
> +#define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0)
> +
> +#define RING_EXECLIST_QFULL (1 << 0x2)
> +#define RING_EXECLIST1_VALID (1 << 0x3)
> +#define RING_EXECLIST0_VALID (1 << 0x4)
> +#define RING_EXECLIST_ACTIVE_STATUS (3 << 0xE)
> +#define RING_EXECLIST1_ACTIVE (1 << 0x11)
> +#define RING_EXECLIST0_ACTIVE (1 << 0x12)
> +
> +#define GEN8_CTX_STATUS_IDLE_ACTIVE (1 << 0)
> +#define GEN8_CTX_STATUS_PREEMPTED (1 << 1)
> +#define GEN8_CTX_STATUS_ELEMENT_SWITCH (1 << 2)
> +#define GEN8_CTX_STATUS_ACTIVE_IDLE (1 << 3)
> +#define GEN8_CTX_STATUS_COMPLETE (1 << 4)
> +#define GEN8_CTX_STATUS_LITE_RESTORE (1 << 15)
>
> #define CTX_LRI_HEADER_0 0x01
> #define CTX_CONTEXT_CONTROL 0x02
> @@ -237,6 +254,9 @@ static void gen8_switch_context_unqueue(struct intel_engine *ring)
> {
> struct drm_i915_gem_request *req0 = NULL, *req1 = NULL;
> struct drm_i915_gem_request *cursor = NULL, *tmp = NULL;
> + struct drm_i915_private *dev_priv = ring->dev->dev_private;
> +
> + assert_spin_locked(&ring->execlist_lock);
>
> if (list_empty(&ring->execlist_queue))
> return;
> @@ -249,8 +269,7 @@ static void gen8_switch_context_unqueue(struct intel_engine *ring)
> /* Same ID: ignore first request, as second request
> * will update tail past first request's workload */
> list_del(&req0->execlist_link);
> - i915_gem_context_unreference(req0->ctx);
> - kfree(req0);
> + queue_work(dev_priv->wq, &req0->work);
> req0 = cursor;
> } else {
> req1 = cursor;
> @@ -262,6 +281,83 @@ static void gen8_switch_context_unqueue(struct intel_engine *ring)
> req1? req1->ctx : NULL, req1? req1->tail : 0));
> }
>
> +static bool check_remove_request(struct intel_engine *ring, u32 request_id)
> +{
> + struct drm_i915_private *dev_priv = ring->dev->dev_private;
> + struct drm_i915_gem_request *head_req;
> +
> + assert_spin_locked(&ring->execlist_lock);
> +
> + head_req = list_first_entry_or_null(&ring->execlist_queue,
> + struct drm_i915_gem_request, execlist_link);
> + if (head_req != NULL) {
> + if (get_submission_id(head_req->ctx) == request_id) {
> + list_del(&head_req->execlist_link);
> + queue_work(dev_priv->wq, &head_req->work);
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +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;
> +}
> +
> +static void free_request_task(struct work_struct *work)
> +{
> + struct drm_i915_gem_request *req =
> + container_of(work, struct drm_i915_gem_request, work);
> + struct drm_device *dev = req->ring->dev;
> +
> + mutex_lock(&dev->struct_mutex);
> + i915_gem_context_unreference(req->ctx);
> + mutex_unlock(&dev->struct_mutex);
> +
> + kfree(req);
> +}
> +
> int gen8_switch_context_queue(struct intel_engine *ring,
> struct i915_hw_context *to,
> u32 tail)
> @@ -276,6 +372,7 @@ int gen8_switch_context_queue(struct intel_engine *ring,
> req->ctx = to;
> i915_gem_context_reference(req->ctx);
> req->tail = tail;
> + INIT_WORK(&req->work, free_request_task);
>
> spin_lock_irqsave(&ring->execlist_lock, flags);
>
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index a92bede..ee5a220 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1464,6 +1464,7 @@ static int intel_init_ring(struct drm_device *dev,
> if (ring->status_page.page_addr == NULL)
> return -ENOMEM;
> ring->status_page.obj = obj;
> + ring->next_context_status_buffer = 0;
> } else if (I915_NEED_GFX_HWS(dev)) {
> ret = init_status_page(ring);
> if (ret)
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index 5f4fd3c..daca04e 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -173,6 +173,7 @@ struct intel_engine {
>
> struct i915_hw_context *default_context;
> struct i915_hw_context *last_context;
> + u8 next_context_status_buffer;
>
> struct intel_ring_hangcheck hangcheck;
>
>
next prev parent reply other threads:[~2014-04-26 0:53 UTC|newest]
Thread overview: 85+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-03-27 17:59 [PATCH 00/49] Execlists oscar.mateo
2014-03-27 17:59 ` [PATCH 01/49] drm/i915/bdw: Macro to distinguish LRCs (Logical Ring Contexts) oscar.mateo
2014-03-27 17:59 ` [PATCH 02/49] drm/i915: s/for_each_ring/for_each_active_ring oscar.mateo
2014-03-27 17:59 ` [PATCH 03/49] drm/i915: for_each_ring oscar.mateo
2014-03-27 17:59 ` [PATCH 04/49] drm/i915: Simplify a couple of functions thanks to for_each_ring oscar.mateo
2014-03-27 17:59 ` [PATCH 05/49] drm/i915: Extract trivial parts of ring init (early init) oscar.mateo
2014-03-27 17:59 ` [PATCH 06/49] drm/i915/bdw: New file for logical ring contexts and execlists oscar.mateo
2014-03-27 17:59 ` [PATCH 07/49] drm/i915/bdw: Rework init code for gen8 contexts oscar.mateo
2014-03-27 17:59 ` [PATCH 08/49] drm/i915: Make i915_gem_create_context outside accessible oscar.mateo
2014-03-27 17:59 ` [PATCH 09/49] drm/i915: Extract ringbuffer obj alloc & destroy oscar.mateo
2014-03-27 17:59 ` [PATCH 10/49] drm/i915: s/intel_ring_buffer/intel_engine oscar.mateo
2014-03-27 17:59 ` [PATCH 11/49] drm/i915: Split the ringbuffers and the rings oscar.mateo
2014-03-27 17:59 ` [PATCH 12/49] drm/i915: Rename functions that mention ringbuffers (meaning rings) oscar.mateo
2014-03-27 17:59 ` [PATCH 13/49] drm/i915/bdw: Execlists ring tail writing oscar.mateo
2014-03-27 17:13 ` Mateo Lozano, Oscar
2014-03-27 17:59 ` [PATCH 14/49] drm/i915/bdw: LR context ring init oscar.mateo
2014-03-27 17:59 ` [PATCH 15/49] drm/i915/bdw: GEN8 semaphoreless ring add request oscar.mateo
2014-03-27 17:59 ` [PATCH 16/49] drm/i915/bdw: GEN8 new ring flush oscar.mateo
2014-03-27 17:59 ` [PATCH 17/49] drm/i915/bdw: A bit more advanced context init/fini oscar.mateo
2014-04-01 0:38 ` Damien Lespiau
2014-04-01 13:47 ` Mateo Lozano, Oscar
2014-04-01 13:51 ` Damien Lespiau
2014-04-01 19:18 ` Ben Widawsky
2014-04-01 21:05 ` Damien Lespiau
2014-04-02 4:07 ` Ben Widawsky
2014-03-27 17:59 ` [PATCH 18/49] drm/i915/bdw: Allocate ringbuffer for LR contexts oscar.mateo
2014-03-27 17:59 ` [PATCH 19/49] drm/i915/bdw: Populate LR contexts (somewhat) oscar.mateo
2014-04-01 0:00 ` Damien Lespiau
2014-04-01 13:33 ` Mateo Lozano, Oscar
2014-04-15 16:00 ` Jeff McGee
2014-04-15 16:10 ` Jeff McGee
2014-04-15 19:51 ` Daniel Vetter
2014-04-15 20:43 ` Jeff McGee
2014-04-15 21:08 ` Daniel Vetter
2014-04-15 22:32 ` Jeff McGee
2014-04-16 6:04 ` Daniel Vetter
2014-03-27 17:59 ` [PATCH 20/49] drm/i915/bdw: Status page for LR contexts oscar.mateo
2014-03-27 17:59 ` [PATCH 21/49] drm/i915/bdw: Enable execlists in the hardware oscar.mateo
2014-03-27 17:59 ` [PATCH 22/49] drm/i915/bdw: Plumbing for user LR context switching oscar.mateo
2014-03-27 17:59 ` [PATCH 23/49] drm/i915: s/__intel_ring_advance/intel_ringbuffer_advance_and_submit oscar.mateo
2014-03-27 17:59 ` [PATCH 24/49] drm/i915/bdw: Write a new set of context-aware ringbuffer management functions oscar.mateo
2014-03-27 17:59 ` [PATCH 25/49] drm/i915: Final touches to LR contexts plumbing and refactoring oscar.mateo
2014-03-27 17:59 ` [PATCH 26/49] drm/i915/bdw: Set the request context information correctly in the LRC case oscar.mateo
2014-03-27 17:59 ` [PATCH 27/49] drm/i915/bdw: Prepare for user-created LR contexts oscar.mateo
2014-03-27 17:59 ` [PATCH 28/49] drm/i915/bdw: Start creating & destroying user " oscar.mateo
2014-03-27 17:59 ` [PATCH 29/49] drm/i915/bdw: Pin context pages at context create time oscar.mateo
2014-03-27 17:59 ` [PATCH 30/49] drm/i915/bdw: Extract LR context object populating oscar.mateo
2014-03-27 18:00 ` [PATCH 31/49] drm/i915/bdw: Introduce dependent contexts oscar.mateo
2014-03-27 17:21 ` Mateo Lozano, Oscar
2014-04-09 16:54 ` Mateo Lozano, Oscar
2014-03-27 18:00 ` [PATCH 32/49] drm/i915/bdw: Create stand-alone and " oscar.mateo
2014-03-27 18:00 ` [PATCH 33/49] drm/i915/bdw: Allow non-default, non-render user LR contexts oscar.mateo
2014-03-27 18:00 ` [PATCH 34/49] drm/i915/bdw: Fix reset stats ioctl with " oscar.mateo
2014-03-27 18:00 ` [PATCH 35/49] drm/i915: Allocate an integer ID for each new file descriptor oscar.mateo
2014-03-27 18:00 ` [PATCH 36/49] drm/i915/bdw: Prepare for a 20-bits globally unique submission ID oscar.mateo
2014-03-27 18:00 ` [PATCH 37/49] drm/i915/bdw: Implement context switching (somewhat) oscar.mateo
2014-03-27 18:00 ` [PATCH 38/49] drm/i915/bdw: Add forcewake lock around ELSP writes oscar.mateo
2014-03-27 18:00 ` [PATCH 39/49] drm/i915/bdw: Swap the PPGTT PDPs, LRC style oscar.mateo
2014-03-31 16:42 ` Damien Lespiau
2014-04-01 13:42 ` Mateo Lozano, Oscar
2014-04-02 13:47 ` Damien Lespiau
2014-04-09 7:56 ` Mateo Lozano, Oscar
2014-03-27 18:00 ` [PATCH 40/49] drm/i915/bdw: Write the tail pointer, " oscar.mateo
2014-03-27 18:00 ` [PATCH 41/49] drm/i915/bdw: LR context switch interrupts oscar.mateo
2014-04-02 11:42 ` Damien Lespiau
2014-04-02 11:49 ` Daniel Vetter
2014-04-02 12:56 ` Damien Lespiau
2014-03-27 18:00 ` [PATCH 42/49] drm/i915/bdw: Get prepared for a two-stage execlist submit process oscar.mateo
2014-04-04 11:12 ` Damien Lespiau
2014-04-04 13:24 ` Damien Lespiau
2014-04-09 7:57 ` Mateo Lozano, Oscar
2014-03-27 18:00 ` [PATCH 43/49] drm/i915/bdw: Handle context switch events oscar.mateo
2014-04-03 14:24 ` Damien Lespiau
2014-04-09 8:15 ` Mateo Lozano, Oscar
2014-04-26 0:53 ` Robert Beckett [this message]
2014-04-28 14:43 ` Mateo Lozano, Oscar
2014-03-27 18:00 ` [PATCH 44/49] drm/i915/bdw: Display execlists info in debugfs oscar.mateo
2014-04-07 19:19 ` Damien Lespiau
2014-03-27 18:00 ` [PATCH 45/49] drm/i915/bdw: Display context ringbuffer " oscar.mateo
2014-03-27 18:00 ` [PATCH 46/49] drm/i915/bdw: Start queueing contexts to be submitted oscar.mateo
2014-03-27 18:00 ` [PATCH 47/49] drm/i915/bdw: Always write seqno to default context oscar.mateo
2014-03-27 18:00 ` [PATCH 48/49] drm/i915/bdw: Enable logical ring contexts oscar.mateo
2014-03-27 18:00 ` [PATCH 49/49] drm/i915/bdw: Document execlists and " oscar.mateo
2014-04-07 18:12 ` [PATCH 00/49] Execlists Damien Lespiau
2014-04-07 21:32 ` Daniel Vetter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=535B037E.1090109@intel.com \
--to=robert.beckett@intel.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=oscar.mateo@intel.com \
--cc=thomas.daniel@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.