From: Ben Widawsky <ben@bwidawsk.net>
To: intel-gfx@lists.freedesktop.org
Cc: Ben Widawsky <ben@bwidawsk.net>
Subject: [PATCH 05/18] drm/i915: context switch implementation
Date: Sun, 18 Mar 2012 13:39:45 -0700 [thread overview]
Message-ID: <1332103198-25852-6-git-send-email-ben@bwidawsk.net> (raw)
In-Reply-To: <1332103198-25852-1-git-send-email-ben@bwidawsk.net>
Implement the context switch code as well as the interfaces to do the
context switch. This patch also doesn't match 1:1 with the RFC patches.
The main difference is that from Daniel's responses the last context
object is now stored instead of the last context. This aids in allows us
to free the context data structure, and context object independently.
There is room for optimization: this code will pin the context object
until the next context is active. The optimal way to do it is to
actually pin the object, move it to the active list, do the context
switch, and then unpin it. This allows the eviction code to actually
evict the context object if needed.
The context switch code is missing workarounds, they will be implemented
in future patches.
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
---
drivers/gpu/drm/i915/i915_drv.h | 5 ++
drivers/gpu/drm/i915/i915_gem_context.c | 118 ++++++++++++++++++++++++++++++-
drivers/gpu/drm/i915/intel_ringbuffer.c | 26 +++++++
drivers/gpu/drm/i915/intel_ringbuffer.h | 5 ++
4 files changed, 153 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f458a8f..c6c2ada 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1303,10 +1303,15 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level);
/* i915_gem_context.c */
+#define I915_CONTEXT_FORCED_SWITCH (1<<0)
+#define I915_CONTEXT_INITIAL_SWITCH (1<<1)
void i915_gem_context_load(struct drm_device *dev);
void i915_gem_context_unload(struct drm_device *dev);
void i915_gem_context_open(struct drm_device *dev, struct drm_file *file);
void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
+int i915_switch_context(struct intel_ring_buffer *ring,
+ struct drm_file *file,
+ int to_id, u32 seqno, u32 flags);
/* i915_gem_gtt.c */
int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 321bafd..cc508d5 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -262,7 +262,7 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
mutex_unlock(&dev->struct_mutex);
}
-static __used struct i915_hw_context *
+static struct i915_hw_context *
i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id)
{
struct i915_hw_context *ctx = NULL;
@@ -279,3 +279,119 @@ i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id)
return ctx;
}
+
+static int do_switch(struct drm_i915_gem_object *from_obj,
+ struct i915_hw_context *to,
+ u32 seqno, u32 flags)
+{
+ bool initial_switch = (flags & I915_CONTEXT_INITIAL_SWITCH) ? true : false;
+ bool force = (flags & I915_CONTEXT_FORCED_SWITCH) ? true : false;
+ struct intel_ring_buffer *ring = NULL;
+ u32 hw_flags = 0;
+ int ret;
+
+ BUG_ON(to == NULL);
+ BUG_ON(from_obj != NULL && from_obj->pin_count == 0);
+ BUG_ON((from_obj != NULL && from_obj->context_id < 0) || to->obj->context_id < 0);
+
+ ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false);
+ if (ret)
+ return ret;
+
+ if (initial_switch)
+ hw_flags |= MI_RESTORE_INHIBIT;
+ if (force)
+ hw_flags |= MI_FORCE_RESTORE;
+
+ ring = to->ring;
+ ret = intel_ring_mi_set_context(ring, to, hw_flags);
+ if (ret) {
+ i915_gem_object_unpin(to->obj);
+ return ret;
+ }
+
+ /* The backing object for the context is done after switching to the
+ * *next* context. Therefore we cannot retire the previous context until
+ * the next context has already started running. In fact, the below code
+ * is a bit suboptimal because the retiring can occur simply after the
+ * MI_SET_CONTEXT instead of when the next seqno has completed.
+ */
+ if (from_obj != NULL) {
+ i915_gem_object_move_to_active(from_obj, ring, seqno);
+ /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the
+ * whole damn pipeline, we don't need to explicitly mark the
+ * object dirty. It should be safe to evict the object at any
+ * point after MI_SET_CONTEXT has finished executing... true as
+ * of GEN7. If not from_obj->dirty=1 would make this safer.
+ */
+ BUG_ON(from_obj->ring != to->ring);
+ }
+
+ if (from_obj)
+ i915_gem_object_unpin(from_obj);
+
+ ring->last_context_obj = to->obj;
+
+ return 0;
+}
+
+/**
+ * i915_switch_context() - perform a GPU context switch.
+ * @ring: ring for which we'll execute the context switch
+ * @file_priv: file_priv associated with the context, may be NULL
+ * @id: context id number
+ * @seqno: sequence number by which the new context will be switched to
+ * @flags:
+ *
+ * This function will perform the context switch to the given context id on the
+ * specified ring. Unfortunately the context switch code doesn't have an
+ * independent way of knowing when the context switch has occurred, so the
+ * caller must notify of us a time by which the context switch has occurred.
+ */
+int i915_switch_context(struct intel_ring_buffer *ring,
+ struct drm_file *file,
+ int to_id, u32 seqno, u32 flags)
+{
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ struct drm_i915_file_private *file_priv = NULL;
+ struct i915_hw_context *to;
+ struct drm_i915_gem_object *from_obj = ring->last_context_obj;
+ int ret;
+
+ if (dev_priv->hw_contexts_disabled)
+ return 0;
+
+ if (ring != &dev_priv->ring[RCS])
+ return 0;
+
+ if (file)
+ file_priv = file->driver_priv;
+
+ if (to_id == DEFAULT_CONTEXT_ID) {
+ to = ring->default_context;
+ kref_get(&to->nref);
+ } else {
+ to = i915_gem_context_get(file_priv, to_id);
+ if (to == NULL)
+ return -EINVAL;
+ }
+ drm_gem_object_reference(&to->obj->base);
+
+ /* If the object is still on the active list, we can shortcut */
+ if (from_obj == to->obj) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = do_switch(from_obj, to, seqno, flags);
+ if (ret) {
+ drm_gem_object_unreference(&to->obj->base);
+ goto out;
+ }
+
+out:
+ if (from_obj != NULL)
+ drm_gem_object_unreference(&from_obj->base);
+ kref_put(&to->nref, destroy_hw_context);
+ return ret;
+}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index ca3972f..cd74f86 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -920,6 +920,32 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
return 0;
}
+int intel_ring_mi_set_context(struct intel_ring_buffer *ring,
+ struct i915_hw_context *new_context,
+ u32 hw_flags)
+{
+ int ret;
+
+ ret = intel_ring_begin(ring, 4);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_emit(ring, MI_SET_CONTEXT);
+ intel_ring_emit(ring, new_context->obj->gtt_offset |
+ MI_MM_SPACE_GTT |
+ MI_SAVE_EXT_STATE_EN |
+ MI_RESTORE_EXT_STATE_EN |
+ hw_flags);
+ /* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP */
+ intel_ring_emit(ring, MI_NOOP);
+
+ intel_ring_advance(ring);
+
+ return ret;
+
+}
+
static void cleanup_status_page(struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = ring->dev->dev_private;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 8c9f898..0ed98bb 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -121,6 +121,7 @@ struct intel_ring_buffer {
drm_local_map_t map;
struct i915_hw_context *default_context;
+ struct drm_i915_gem_object *last_context_obj;
void *private;
};
@@ -216,6 +217,10 @@ static inline void i915_trace_irq_get(struct intel_ring_buffer *ring, u32 seqno)
ring->trace_irq_seqno = seqno;
}
+int intel_ring_mi_set_context(struct intel_ring_buffer *ring,
+ struct i915_hw_context *new_context,
+ u32 hw_flags);
+
/* DRI warts */
int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size);
--
1.7.9.4
next prev parent reply other threads:[~2012-03-18 20:41 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-18 20:39 [PATCH 00/18] i915 HW Context Support Ben Widawsky
2012-03-18 20:39 ` [PATCH 01/18] drm/i915: CXT_SIZE register offsets added Ben Widawsky
2012-03-18 20:39 ` [PATCH 02/18] drm/i915: preliminary context support Ben Widawsky
2012-03-28 22:43 ` Daniel Vetter
2012-03-28 22:59 ` Ben Widawsky
2012-03-29 8:43 ` Daniel Vetter
2012-03-18 20:39 ` [PATCH 03/18] drm/i915: context basic create & destroy Ben Widawsky
2012-03-18 20:39 ` [PATCH 04/18] drm/i915: add context information to objects Ben Widawsky
2012-03-28 22:36 ` Daniel Vetter
2012-03-29 0:20 ` Ben Widawsky
2012-03-29 8:47 ` Daniel Vetter
2012-03-29 15:57 ` Ben Widawsky
2012-03-18 20:39 ` Ben Widawsky [this message]
2012-03-29 18:24 ` [PATCH 05/18] drm/i915: context switch implementation Daniel Vetter
2012-03-29 18:43 ` Ben Widawsky
2012-03-29 18:49 ` Daniel Vetter
2012-03-30 18:11 ` Ben Widawsky
2012-03-29 18:47 ` Daniel Vetter
2012-03-18 20:39 ` [PATCH 06/18] drm/i915: trace events for contexts Ben Widawsky
2012-03-18 20:39 ` [PATCH 07/18] drm/i915: Ivybridge MI_ARB_ON_OFF context w/a Ben Widawsky
2012-03-18 20:39 ` [PATCH 08/18] drm/i915: PIPE_CONTROL_TLB_INVALIDATE Ben Widawsky
2012-03-18 20:39 ` [PATCH 09/18] drm/i915: possibly invalidate TLB before context switch Ben Widawsky
2012-03-29 19:25 ` Daniel Vetter
2012-03-30 18:39 ` Ben Widawsky
2012-03-30 19:01 ` Daniel Vetter
2012-03-18 20:39 ` [PATCH 10/18] drm/i915: use the default context Ben Widawsky
2012-03-18 20:39 ` [PATCH 11/18] drm/i915: switch to default context on idle Ben Widawsky
2012-03-29 19:29 ` Daniel Vetter
2012-03-29 20:28 ` Chris Wilson
2012-03-30 21:17 ` Ben Widawsky
2012-03-30 21:30 ` Daniel Vetter
2012-03-18 20:39 ` [PATCH 12/18] drm/i915: try to reset the gpu before unload Ben Widawsky
2012-03-29 19:31 ` Daniel Vetter
2012-03-30 18:50 ` Ben Widawsky
2012-03-30 19:05 ` Daniel Vetter
2012-03-30 16:54 ` Jesse Barnes
2012-03-30 17:30 ` Daniel Vetter
2012-03-18 20:39 ` [PATCH 13/18] drm/i915/context: create & destroy ioctls Ben Widawsky
2012-03-29 19:35 ` Daniel Vetter
2012-03-30 18:55 ` Ben Widawsky
2012-03-30 19:16 ` Daniel Vetter
2012-03-18 20:39 ` [PATCH 14/18] drm/i915/context: switch contexts with execbuf2 Ben Widawsky
2012-03-29 19:38 ` Daniel Vetter
2012-03-30 18:58 ` Ben Widawsky
2012-03-30 19:20 ` Daniel Vetter
2012-03-18 20:39 ` [PATCH 15/18] drm/i915/context: add params Ben Widawsky
2012-03-18 20:39 ` [PATCH 16/18] drm/i915/context: anonymous context interfaces Ben Widawsky
2012-03-29 19:42 ` Daniel Vetter
2012-03-18 20:39 ` [PATCH 17/18] drm/i915: Ironlake rc6 can use " Ben Widawsky
2012-03-29 19:47 ` Daniel Vetter
2012-03-18 20:39 ` [PATCH 18/18] drm/i915: try to enable rc6 on Ironlake... again Ben Widawsky
2012-03-19 3:47 ` [PATCH 00/18] i915 HW Context Support Ben Widawsky
2012-03-19 10:14 ` Daniel Vetter
2012-03-29 19:51 ` 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=1332103198-25852-6-git-send-email-ben@bwidawsk.net \
--to=ben@bwidawsk.net \
--cc=intel-gfx@lists.freedesktop.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox