Skip to contentSkip to conversation

Execlists v5

PATCH Applied Thomas Daniel 9 participants 137 messages Jul 24, 2014 – Aug 28, 2014 Page 1 of 2

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover Execlists v5

From: Thomas Daniel <[email protected]>

For a description of this patchset, please check the previous cover letters: [1], [2], [3] and [4].

I have taken ownership of this patchset from Oscar, and this version represents his last work on the execlists patchset. The narrative below is from him.

I have been given some grace period to fix the remaining issues in Execlists before I move to a different project, and this is the result. There are very little differences between this v5 and the v4 I sent out last week, so I was unsure whether to drop a new patchbomb or simply reply to the patches that have changed, but I decided for the former to make the review easier.

The changes are:

- New prep-work patch to prevent a potential problem with the legacy ringbuffer submission extraction that was done earlier.
- Do the remaining intel_runtime_put while purging the execlists queue during reset.
- Check arguments before doing stuff in intel_execlists_submission. Also, get rel_constants parsing right.
- Do gen8_emit_flush = gen6_ring_flush + gen6_bsd_ring_flush.
- New patches for pinning context and ringbuffer backing objects on-demand (before I was pinning on interrupt time, which was a no-no). These fix the reamining eviction issues I was seeing.

The previous comment about the WAs still applies. I reproduce it here for completeness:

"One other caveat I have noticed is that many WAs in gen8_init_clock_gating (those that affect registers that now exist per-context) can get lost in the render default context. The reason is, in Execlists, a context is saved as soon as head = tail (with MI_SET_CONTEXT, however, the context wouldn't be saved until you tried to restore a different context). As we are sending the golden state batchbuffer to the render ring as soon as the rings are initialized, we are effectively saving the default context before gen8_init_clock_gating has an opportunity to set the WAs. I haven't noticed any ill-effect from this (yet) but it would be a good idea to move the WAs somewhere else (ring init looks like a good place). I believe there is already work in progress to create a new WA architecture, so this can be tackled there."

The previous IGT test [4] still applies.

There are three pending issues:

- The test gem_close_race warns about "scheduling while atomic" when the shrinker gets called. Without Execlists, the shrinker does not get called at all (which kind of makes sense) but the tests timeouts before finishing.
- The test gem_concurrent_blit fails in the gtt-* subtests: some pixels (14, to be exact) do not get copied correctly from one bo to another. Funnily enough, the tests pass if I do a i915 module reload first (./tests/drv_module_reload). Yesterday I dumped all the registers in the chip before and after a module reload (attached), but I havenŽt found any meaningful difference yet.
- When I try to run a whole IGT suite using Piglit, sometimes I hit the BUG_ON(!i915_gem_obj_is_pinned(ctx_obj0)) in execlists_submit_context(). I havenŽt managed to reproduce the problem at will, but there is obviously something wrong with the last two Execlists patches.

Keep the r-b tags coming, please!!

-- Oscar

[1]
http://lists.freedesktop.org/archives/intel-gfx/2014-March/042563.html
[2]
http://lists.freedesktop.org/archives/intel-gfx/2014-May/044847.html
[3]
http://lists.freedesktop.org/archives/intel-gfx/2014-June/047138.html
[4]
http://lists.freedesktop.org/archives/intel-gfx/2014-July/048944.html
[5]
http://lists.freedesktop.org/archives/intel-gfx/2014-May/044846.html

Ben Widawsky (2):
drm/i915/bdw: Implement context switching (somewhat) drm/i915/bdw: Print context state in debugfs

Michel Thierry (1):
drm/i915/bdw: Two-stage execlist submit process

Oscar Mateo (39):
drm/i915: Reorder the actual workload submission so that args checking
is done earlier
drm/i915/bdw: New source and header file for LRs, LRCs and Execlists drm/i915/bdw: Macro for LRCs and module option for Execlists drm/i915/bdw: Initialization for Logical Ring Contexts drm/i915/bdw: Introduce one context backing object per engine drm/i915/bdw: A bit more advanced LR context alloc/free drm/i915/bdw: Allocate ringbuffers for Logical Ring Contexts drm/i915/bdw: Add a context and an engine pointers to the ringbuffer drm/i915/bdw: Populate LR contexts (somewhat) drm/i915/bdw: Deferred creation of user-created LRCs drm/i915/bdw: Render moot context reset and switch with Execlists drm/i915/bdw: Don't write PDP in the legacy way when using LRCs drm/i915: Abstract the legacy workload submission mechanism away drm/i915/bdw: Skeleton for the new logical rings submission path drm/i915/bdw: Generic logical ring init and cleanup drm/i915/bdw: GEN-specific logical ring init
drm/i915/bdw: GEN-specific logical ring set/get seqno drm/i915/bdw: New logical ring submission mechanism drm/i915/bdw: GEN-specific logical ring emit request drm/i915/bdw: GEN-specific logical ring emit flush drm/i915/bdw: Emission of requests with logical rings drm/i915/bdw: Ring idle and stop with logical rings drm/i915/bdw: Interrupts with logical rings
drm/i915/bdw: GEN-specific logical ring emit batchbuffer start drm/i915/bdw: Workload submission mechanism for Execlists drm/i915/bdw: Always use MMIO flips with Execlists drm/i915/bdw: Render state init for Execlists drm/i915/bdw: Write the tail pointer, LRC style drm/i915/bdw: Avoid non-lite-restore preemptions drm/i915/bdw: Help out the ctx switch interrupt handler drm/i915/bdw: Make sure gpu reset still works with Execlists drm/i915/bdw: Make sure error capture keeps working with Execlists drm/i915/bdw: Disable semaphores for Execlists drm/i915/bdw: Display execlists info in debugfs drm/i915/bdw: Display context backing obj & ringbuffer info in debugfs drm/i915/bdw: Document Logical Rings, LR contexts and Execlists drm/i915/bdw: Enable Logical Ring Contexts (hence, Execlists) drm/i915/bdw: Pin the context backing objects to GGTT on-demand drm/i915/bdw: Pin the ringbuffer backing object to GGTT on-demand

Thomas Daniel (1):
drm/i915/bdw: Handle context switch events

 Documentation/DocBook/drm.tmpl               |    5 +
 drivers/gpu/drm/i915/Makefile                |    1 +
 drivers/gpu/drm/i915/i915_debugfs.c          |  157 ++-
 drivers/gpu/drm/i915/i915_drv.c              |    4 +
 drivers/gpu/drm/i915/i915_drv.h              |   47 +-
 drivers/gpu/drm/i915/i915_gem.c              |  132 +-
 drivers/gpu/drm/i915/i915_gem_context.c      |   56 +-
 drivers/gpu/drm/i915/i915_gem_execbuffer.c   |  118 +-
 drivers/gpu/drm/i915/i915_gem_gtt.c          |    5 +
 drivers/gpu/drm/i915/i915_gem_render_state.c |   40 +-
 drivers/gpu/drm/i915/i915_gem_render_state.h |   47 +
 drivers/gpu/drm/i915/i915_gpu_error.c        |   22 +-
 drivers/gpu/drm/i915/i915_irq.c              |   44 +-
 drivers/gpu/drm/i915/i915_params.c           |    6 +
 drivers/gpu/drm/i915/i915_reg.h              |    5 +
 drivers/gpu/drm/i915/intel_display.c         |    2 +
 drivers/gpu/drm/i915/intel_lrc.c             | 1802 ++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.h             |  115 ++
 drivers/gpu/drm/i915/intel_renderstate.h     |    8 +-
 drivers/gpu/drm/i915/intel_ringbuffer.c      |  166 ++-
 drivers/gpu/drm/i915/intel_ringbuffer.h      |   41 +-
 21 files changed, 2622 insertions(+), 201 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/i915_gem_render_state.h
 create mode 100644 drivers/gpu/drm/i915/intel_lrc.c
 create mode 100644 drivers/gpu/drm/i915/intel_lrc.h
Signature · 5 lines
1.9.0
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#1 lore raw

PATCH 1/43 drm/i915: Reorder the actual workload submission so that args checking is done earlier

From: Oscar Mateo <[email protected]>

In this patch:

commit 78382593e921c88371abd019aca8978db3248a8f

Author: Oscar Mateo <[email protected]>
Date:   Thu Jul 3 16:28:05 2014 +0100

drm/i915: Extract the actual workload submission mechanism from execbuffer

So that we isolate the legacy ringbuffer submission mechanism, which becomes a good candidate to be abstracted away. This is prep-work for Execlists (which will its own workload submission mechanism).

No functional changes.

I changed the order in which the args checking is done. I don't know why I did (brain fade?) but itś not right. I haven't seen any ill effect from this, but the Execlists version of this function will have problems if the order is not correct.

---
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |   86 ++++++++++++++--------------
 1 file changed, 43 insertions(+), 43 deletions(-)
drivers/gpu/drm/i915/i915_gem_execbuffer.c +43 -43
index 60998fc..c5115957 100644
@@ -1042,6 +1042,43 @@ legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
 	u32 instp_mask;
 	int i, ret = 0;
 
+	instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
+	instp_mask = I915_EXEC_CONSTANTS_MASK;
+	switch (instp_mode) {
+	case I915_EXEC_CONSTANTS_REL_GENERAL:
+	case I915_EXEC_CONSTANTS_ABSOLUTE:
+	case I915_EXEC_CONSTANTS_REL_SURFACE:
+		if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) {
+			DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
+			ret = -EINVAL;
+			goto error;
+		}
+
+		if (instp_mode != dev_priv->relative_constants_mode) {
+			if (INTEL_INFO(dev)->gen < 4) {
+				DRM_DEBUG("no rel constants on pre-gen4\n");
+				ret = -EINVAL;
+				goto error;
+			}
+
+			if (INTEL_INFO(dev)->gen > 5 &&
+			    instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
+				DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
+				ret = -EINVAL;
+				goto error;
+			}
+
+			/* The HW changed the meaning on this bit on gen6 */
+			if (INTEL_INFO(dev)->gen >= 6)
+				instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE;
+		}
+		break;
+	default:
+		DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode);
+		ret = -EINVAL;
+		goto error;
+	}
+
 	if (args->num_cliprects != 0) {
 		if (ring != &dev_priv->ring[RCS]) {
 			DRM_DEBUG("clip rectangles are only valid with the render ring\n");
@@ -1085,6 +1122,12 @@ legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
 		}
 	}
 
+	if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
+		ret = i915_reset_gen7_sol_offsets(dev, ring);
+		if (ret)
+			goto error;
+	}
+
 	ret = i915_gem_execbuffer_move_to_gpu(ring, vmas);
 	if (ret)
 		goto error;
@@ -1093,43 +1136,6 @@ legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
 	if (ret)
 		goto error;
 
-	instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
-	instp_mask = I915_EXEC_CONSTANTS_MASK;
-	switch (instp_mode) {
-	case I915_EXEC_CONSTANTS_REL_GENERAL:
-	case I915_EXEC_CONSTANTS_ABSOLUTE:
-	case I915_EXEC_CONSTANTS_REL_SURFACE:
-		if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) {
-			DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
-			ret = -EINVAL;
-			goto error;
-		}
-
-		if (instp_mode != dev_priv->relative_constants_mode) {
-			if (INTEL_INFO(dev)->gen < 4) {
-				DRM_DEBUG("no rel constants on pre-gen4\n");
-				ret = -EINVAL;
-				goto error;
-			}
-
-			if (INTEL_INFO(dev)->gen > 5 &&
-			    instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
-				DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
-				ret = -EINVAL;
-				goto error;
-			}
-
-			/* The HW changed the meaning on this bit on gen6 */
-			if (INTEL_INFO(dev)->gen >= 6)
-				instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE;
-		}
-		break;
-	default:
-		DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode);
-		ret = -EINVAL;
-		goto error;
-	}
-
 	if (ring == &dev_priv->ring[RCS] &&
 			instp_mode != dev_priv->relative_constants_mode) {
 		ret = intel_ring_begin(ring, 4);
@@ -1145,12 +1151,6 @@ legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
 		dev_priv->relative_constants_mode = instp_mode;
 	}
 
-	if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
-		ret = i915_reset_gen7_sol_offsets(dev, ring);
-		if (ret)
-			goto error;
-	}
-
 	exec_len = args->batch_len;
 	if (cliprects) {
 		for (i = 0; i < args->num_cliprects; i++) {
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#2 lore raw

Re: [PATCH 01/43] drm/i915: Reorder the actual workload submission so that args checking is done earlier

Quoted 14 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

In this patch:

commit 78382593e921c88371abd019aca8978db3248a8f

Author: Oscar Mateo <[email protected]>
Date:   Thu Jul 3 16:28:05 2014 +0100

drm/i915: Extract the actual workload submission mechanism from execbuffer

So that we isolate the legacy ringbuffer submission mechanism, which becomes a good candidate to be abstracted away. This is prep-work for Execlists (which will its own workload submission mechanism).

Quoted 7 lines

No functional changes.

I changed the order in which the args checking is done. I don't know why I did (brain fade?) but itś not right. I haven't seen any ill effect from this, but the Execlists version of this function will have problems if the order is not correct.

I don't think this matters - the point of no return for legacy execbuf is the call to ring->dispatch. After that nothing may fail any more. But as long as we track state correctly (e.g. if we've switched the context already) we'll be fine.

So presuming I'm not blind I dont' think this is needed. But maybe Chris spots something.
-Daniel

Quoted 129 lines
---
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |   86 ++++++++++++++--------------
 1 file changed, 43 insertions(+), 43 deletions(-)
drivers/gpu/drm/i915/i915_gem_execbuffer.c +43 -43
index 60998fc..c5115957 100644
@@ -1042,6 +1042,43 @@ legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
 	u32 instp_mask;
 	int i, ret = 0;
 
+	instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
+	instp_mask = I915_EXEC_CONSTANTS_MASK;
+	switch (instp_mode) {
+	case I915_EXEC_CONSTANTS_REL_GENERAL:
+	case I915_EXEC_CONSTANTS_ABSOLUTE:
+	case I915_EXEC_CONSTANTS_REL_SURFACE:
+		if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) {
+			DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
+			ret = -EINVAL;
+			goto error;
+		}
+
+		if (instp_mode != dev_priv->relative_constants_mode) {
+			if (INTEL_INFO(dev)->gen < 4) {
+				DRM_DEBUG("no rel constants on pre-gen4\n");
+				ret = -EINVAL;
+				goto error;
+			}
+
+			if (INTEL_INFO(dev)->gen > 5 &&
+			    instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
+				DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
+				ret = -EINVAL;
+				goto error;
+			}
+
+			/* The HW changed the meaning on this bit on gen6 */
+			if (INTEL_INFO(dev)->gen >= 6)
+				instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE;
+		}
+		break;
+	default:
+		DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode);
+		ret = -EINVAL;
+		goto error;
+	}
+
 	if (args->num_cliprects != 0) {
 		if (ring != &dev_priv->ring[RCS]) {
 			DRM_DEBUG("clip rectangles are only valid with the render ring\n");
@@ -1085,6 +1122,12 @@ legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
 		}
 	}
 
+	if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
+		ret = i915_reset_gen7_sol_offsets(dev, ring);
+		if (ret)
+			goto error;
+	}
+
 	ret = i915_gem_execbuffer_move_to_gpu(ring, vmas);
 	if (ret)
 		goto error;
@@ -1093,43 +1136,6 @@ legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
 	if (ret)
 		goto error;
 
-	instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
-	instp_mask = I915_EXEC_CONSTANTS_MASK;
-	switch (instp_mode) {
-	case I915_EXEC_CONSTANTS_REL_GENERAL:
-	case I915_EXEC_CONSTANTS_ABSOLUTE:
-	case I915_EXEC_CONSTANTS_REL_SURFACE:
-		if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) {
-			DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
-			ret = -EINVAL;
-			goto error;
-		}
-
-		if (instp_mode != dev_priv->relative_constants_mode) {
-			if (INTEL_INFO(dev)->gen < 4) {
-				DRM_DEBUG("no rel constants on pre-gen4\n");
-				ret = -EINVAL;
-				goto error;
-			}
-
-			if (INTEL_INFO(dev)->gen > 5 &&
-			    instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
-				DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
-				ret = -EINVAL;
-				goto error;
-			}
-
-			/* The HW changed the meaning on this bit on gen6 */
-			if (INTEL_INFO(dev)->gen >= 6)
-				instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE;
-		}
-		break;
-	default:
-		DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode);
-		ret = -EINVAL;
-		goto error;
-	}
-
 	if (ring == &dev_priv->ring[RCS] &&
 			instp_mode != dev_priv->relative_constants_mode) {
 		ret = intel_ring_begin(ring, 4);
@@ -1145,12 +1151,6 @@ legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
 		dev_priv->relative_constants_mode = instp_mode;
 	}
 
-	if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
-		ret = i915_reset_gen7_sol_offsets(dev, ring);
-		if (ret)
-			goto error;
-	}
-
 	exec_len = args->batch_len;
 	if (cliprects) {
 		for (i = 0; i < args->num_cliprects; i++) {
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#3 lore raw

Re: [PATCH 01/43] drm/i915: Reorder the actual workload submission so that args checking is done earlier

Quoted 21 lines · Daniel Vetter
Quoted 20 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

In this patch:

commit 78382593e921c88371abd019aca8978db3248a8f

Author: Oscar Mateo <[email protected]>
Date:   Thu Jul 3 16:28:05 2014 +0100

drm/i915: Extract the actual workload submission mechanism from execbuffer

So that we isolate the legacy ringbuffer submission mechanism, which becomes a good candidate to be abstracted away. This is prep-work for Execlists (which will its own workload submission mechanism).

No functional changes.

I changed the order in which the args checking is done. I don't know why I did (brain fade?) but itś not right. I haven't seen any ill effect from this, but the Execlists version of this function will have problems if the order is not correct.

Quoted 6 lines
Quoted 1 line

I don't think this matters - the point of no return for legacy execbuf is the call to ring->dispatch. After that nothing may fail any more. But as long as we track state correctly (e.g. if we've switched the context already) we'll be fine.

Right. Except that I think our tracking is buggy - or at least insufficient to address the needs of future dispatch mechanisms. I think that we confuse some bookkeeping that should be at the request level and place it on the ring. At the moment, we have one request per-ring and so it doesn't matter, but transitioning to one request per-logical-ring we start to have issues as that state is being tracked on the wrong struct.

Anyway, that's part of the motivation to fixing up requests and making them central to accessing the rings/dispatch (whereas at the moment they are behind the scenes).
-Chris

Signature · 5 lines
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#4 lore raw

PATCH 2/43 drm/i915/bdw: New source and header file for LRs, LRCs and Execlists

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Some legacy HW context code assumptions don't make sense for this new submission method, so we will place this stuff in a separate file.

Note for reviewers: I've carefully considered the best name for this file and this was my best option (other possibilities were intel_lr_context.c or intel_execlist.c). I am open to a certain bikeshedding on this matter, anyway.

And some point in time, it would be a good idea to split intel_lrc.c/.h even further, but for the moment just shove everything together.

v2: Change to intel_lrc.c

v3: Squash together with the header file addition

---
 drivers/gpu/drm/i915/Makefile    |    1 +
 drivers/gpu/drm/i915/i915_drv.h  |    1 +
 drivers/gpu/drm/i915/intel_lrc.c |   42 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.h |   27 ++++++++++++++++++++++++
 4 files changed, 71 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/intel_lrc.c
 create mode 100644 drivers/gpu/drm/i915/intel_lrc.h
drivers/gpu/drm/i915/Makefile +1 -0
index cad1683..9fee2a0 100644
@@ -31,6 +31,7 @@ i915-y += i915_cmd_parser.o \
 	  i915_gpu_error.o \
 	  i915_irq.o \
 	  i915_trace_points.o \
+	  intel_lrc.o \
 	  intel_ringbuffer.o \
 	  intel_uncore.o
 
drivers/gpu/drm/i915/i915_drv.h +1 -0
index 44a63f3..54c2bd9 100644
@@ -35,6 +35,7 @@
 #include "i915_reg.h"
 #include "intel_bios.h"
 #include "intel_ringbuffer.h"
+#include "intel_lrc.h"
 #include "i915_gem_gtt.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
drivers/gpu/drm/i915/intel_lrc.c new file +42 -0

42 lines not on this page · raw message

drivers/gpu/drm/i915/intel_lrc.h new file +27 -0
new file mode 100644
index 0000000..f6830a4
@@ -0,0 +1,27 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _INTEL_LRC_H_
+#define _INTEL_LRC_H_
+
+#endif /* _INTEL_LRC_H_ */
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#5 lore raw

PATCH 3/43 drm/i915/bdw: Macro for LRCs and module option for Execlists

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

GEN8 brings an expansion of the HW contexts: "Logical Ring Contexts". These expanded contexts enable a number of new abilities, especially "Execlists".

The macro is defined to off until we have things in place to hope to work.

v2: Rename "advanced contexts" to the more correct "logical ring contexts".

v3: Add a module parameter to enable execlists. Execlist are relatively new, and so it'd be wise to be able to switch back to ring submission to debug subtle problems that will inevitably arise.

v4: Add an intel_enable_execlists function.

v5: Sanitize early, as suggested by Daniel. Remove lrc_enabled.

---
 drivers/gpu/drm/i915/i915_drv.h    |    2 ++
 drivers/gpu/drm/i915/i915_gem.c    |    3 +++
 drivers/gpu/drm/i915/i915_params.c |    6 ++++++
 drivers/gpu/drm/i915/intel_lrc.c   |   11 +++++++++++
 drivers/gpu/drm/i915/intel_lrc.h   |    3 +++
 5 files changed, 25 insertions(+)
drivers/gpu/drm/i915/i915_drv.h +2 -0
index 54c2bd9..a793d6d 100644
@@ -2037,6 +2037,7 @@ struct drm_i915_cmd_table {
 #define I915_NEED_GFX_HWS(dev)	(INTEL_INFO(dev)->need_gfx_hws)
 
 #define HAS_HW_CONTEXTS(dev)	(INTEL_INFO(dev)->gen >= 6)
+#define HAS_LOGICAL_RING_CONTEXTS(dev)	0
 #define HAS_ALIASING_PPGTT(dev)	(INTEL_INFO(dev)->gen >= 6)
 #define HAS_PPGTT(dev)		(INTEL_INFO(dev)->gen >= 7 && !IS_GEN8(dev))
 #define USES_PPGTT(dev)		intel_enable_ppgtt(dev, false)
@@ -2122,6 +2123,7 @@ struct i915_params {
 	int enable_rc6;
 	int enable_fbc;
 	int enable_ppgtt;
+	int enable_execlists;
 	int enable_psr;
 	unsigned int preliminary_hw_support;
 	int disable_power_well;
drivers/gpu/drm/i915/i915_gem.c +3 -0
index e5d4d73..d8bf4fa 100644
@@ -4746,6 +4746,9 @@ int i915_gem_init(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
+	i915.enable_execlists = intel_sanitize_enable_execlists(dev,
+			i915.enable_execlists);
+
 	mutex_lock(&dev->struct_mutex);
 
 	if (IS_VALLEYVIEW(dev)) {
drivers/gpu/drm/i915/i915_params.c +6 -0
index bbdee21..7f0fb72 100644
@@ -35,6 +35,7 @@ struct i915_params i915 __read_mostly = {
 	.vbt_sdvo_panel_type = -1,
 	.enable_rc6 = -1,
 	.enable_fbc = -1,
+	.enable_execlists = -1,
 	.enable_hangcheck = true,
 	.enable_ppgtt = -1,
 	.enable_psr = 1,
@@ -117,6 +118,11 @@ MODULE_PARM_DESC(enable_ppgtt,
 	"Override PPGTT usage. "
 	"(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
 
+module_param_named(enable_execlists, i915.enable_execlists, int, 0400);
+MODULE_PARM_DESC(enable_execlists,
+	"Override execlists usage. "
+	"(-1=auto [default], 0=disabled, 1=enabled)");
+
 module_param_named(enable_psr, i915.enable_psr, int, 0600);
 MODULE_PARM_DESC(enable_psr, "Enable PSR (default: true)");
 
drivers/gpu/drm/i915/intel_lrc.c +11 -0
index 49bb6fc..21f7f1c 100644
@@ -40,3 +40,14 @@
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
+
+int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists)
+{
+	if (enable_execlists == 0)
+		return 0;
+
+	if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev))
+		return 1;
+
+	return 0;
+}
drivers/gpu/drm/i915/intel_lrc.h +3 -0
index f6830a4..75ee9c3 100644
@@ -24,4 +24,7 @@
 #ifndef _INTEL_LRC_H_
 #define _INTEL_LRC_H_
 
+/* Execlists */
+int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);
+
 #endif /* _INTEL_LRC_H_ */
Signature · 1 line
1.7.9.5
#6 lore raw

Re: [PATCH 03/43] drm/i915/bdw: Macro for LRCs and module option for Execlists

Quoted 56 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

GEN8 brings an expansion of the HW contexts: "Logical Ring Contexts". These expanded contexts enable a number of new abilities, especially "Execlists".

The macro is defined to off until we have things in place to hope to work.

v2: Rename "advanced contexts" to the more correct "logical ring contexts".

v3: Add a module parameter to enable execlists. Execlist are relatively new, and so it'd be wise to be able to switch back to ring submission to debug subtle problems that will inevitably arise.

v4: Add an intel_enable_execlists function.

v5: Sanitize early, as suggested by Daniel. Remove lrc_enabled.

---
 drivers/gpu/drm/i915/i915_drv.h    |    2 ++
 drivers/gpu/drm/i915/i915_gem.c    |    3 +++
 drivers/gpu/drm/i915/i915_params.c |    6 ++++++
 drivers/gpu/drm/i915/intel_lrc.c   |   11 +++++++++++
 drivers/gpu/drm/i915/intel_lrc.h   |    3 +++
 5 files changed, 25 insertions(+)
drivers/gpu/drm/i915/i915_drv.h +2 -0
index 54c2bd9..a793d6d 100644
@@ -2037,6 +2037,7 @@ struct drm_i915_cmd_table {
 #define I915_NEED_GFX_HWS(dev)	(INTEL_INFO(dev)->need_gfx_hws)
 
 #define HAS_HW_CONTEXTS(dev)	(INTEL_INFO(dev)->gen >= 6)
+#define HAS_LOGICAL_RING_CONTEXTS(dev)	0
 #define HAS_ALIASING_PPGTT(dev)	(INTEL_INFO(dev)->gen >= 6)
 #define HAS_PPGTT(dev)		(INTEL_INFO(dev)->gen >= 7 && !IS_GEN8(dev))
 #define USES_PPGTT(dev)		intel_enable_ppgtt(dev, false)
@@ -2122,6 +2123,7 @@ struct i915_params {
 	int enable_rc6;
 	int enable_fbc;
 	int enable_ppgtt;
+	int enable_execlists;
 	int enable_psr;
 	unsigned int preliminary_hw_support;
 	int disable_power_well;
drivers/gpu/drm/i915/i915_gem.c +0 -0
index e5d4d73..d8bf4fa 100644

drivers/gpu/drm/i915/i915_gem.c int i915_gem_init(struct drm_device *dev) · line 4750

Quoted 5 lines
drivers/gpu/drm/i915/i915_gem.c +2 -0
@@ -4746,6 +4746,9 @@ int i915_gem_init(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
+	i915.enable_execlists = intel_sanitize_enable_execlists(dev,
+			i915.enable_execlists);

The ordering constraint on i915.enabel_ppgtt sanitization is imo super-fragile. You'll all get a big price (and grumpy maintainer) if this blows up. I'll add a patch on top to WARN about this.
-Daniel

Quoted 66 lines
drivers/gpu/drm/i915/i915_gem.c +1 -0
+
 	mutex_lock(&dev->struct_mutex);
 
 	if (IS_VALLEYVIEW(dev)) {
drivers/gpu/drm/i915/i915_params.c +6 -0
index bbdee21..7f0fb72 100644
@@ -35,6 +35,7 @@ struct i915_params i915 __read_mostly = {
 	.vbt_sdvo_panel_type = -1,
 	.enable_rc6 = -1,
 	.enable_fbc = -1,
+	.enable_execlists = -1,
 	.enable_hangcheck = true,
 	.enable_ppgtt = -1,
 	.enable_psr = 1,
@@ -117,6 +118,11 @@ MODULE_PARM_DESC(enable_ppgtt,
 	"Override PPGTT usage. "
 	"(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
 
+module_param_named(enable_execlists, i915.enable_execlists, int, 0400);
+MODULE_PARM_DESC(enable_execlists,
+	"Override execlists usage. "
+	"(-1=auto [default], 0=disabled, 1=enabled)");
+
 module_param_named(enable_psr, i915.enable_psr, int, 0600);
 MODULE_PARM_DESC(enable_psr, "Enable PSR (default: true)");
 
drivers/gpu/drm/i915/intel_lrc.c +11 -0
index 49bb6fc..21f7f1c 100644
@@ -40,3 +40,14 @@
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
+
+int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists)
+{
+	if (enable_execlists == 0)
+		return 0;
+
+	if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev))
+		return 1;
+
+	return 0;
+}
drivers/gpu/drm/i915/intel_lrc.h +3 -0
index f6830a4..75ee9c3 100644
@@ -24,4 +24,7 @@
 #ifndef _INTEL_LRC_H_
 #define _INTEL_LRC_H_
 
+/* Execlists */
+int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);
+
 #endif /* _INTEL_LRC_H_ */
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#7 lore raw

PATCH 4/43 drm/i915/bdw: Initialization for Logical Ring Contexts

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

For the moment this is just a placeholder, but it shows one of the main differences between the good ol' HW contexts and the shiny new Logical Ring Contexts: LR contexts allocate and free their own backing objects. Another difference is that the allocation is deferred (as the create function name suggests), but that does not happen in this patch yet, because for the moment we are only dealing with the default context.

Early in the series we had our own gen8_gem_context_init/fini functions, but the truth is they now look almost the same as the legacy hw context init/fini functions. We can always split them later if this ceases to be the case.

Also, we do not fall back to legacy ringbuffers when logical ring context initialization fails (not very likely to happen and, even if it does, hw contexts would probably fail as well).

v2: Daniel says "explain, do not showcase".

---
 drivers/gpu/drm/i915/i915_gem_context.c |   29 +++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_lrc.c        |   15 +++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.h        |    5 +++++
 3 files changed, 43 insertions(+), 6 deletions(-)
drivers/gpu/drm/i915/i915_gem_context.c +23 -6
index de72a28..718150e 100644
@@ -182,7 +182,10 @@ void i915_gem_context_free(struct kref *ctx_ref)
 						   typeof(*ctx), ref);
 	struct i915_hw_ppgtt *ppgtt = NULL;
 
-	if (ctx->legacy_hw_ctx.rcs_state) {
+	if (i915.enable_execlists) {
+		ppgtt = ctx_to_ppgtt(ctx);
+		intel_lr_context_free(ctx);
+	} else if (ctx->legacy_hw_ctx.rcs_state) {
 		/* We refcount even the aliasing PPGTT to keep the code symmetric */
 		if (USES_PPGTT(ctx->legacy_hw_ctx.rcs_state->base.dev))
 			ppgtt = ctx_to_ppgtt(ctx);
@@ -419,7 +422,11 @@ int i915_gem_context_init(struct drm_device *dev)
 	if (WARN_ON(dev_priv->ring[RCS].default_context))
 		return 0;
 
-	if (HAS_HW_CONTEXTS(dev)) {
+	if (i915.enable_execlists) {
+		/* NB: intentionally left blank. We will allocate our own
+		 * backing objects as we need them, thank you very much */
+		dev_priv->hw_context_size = 0;
+	} else if (HAS_HW_CONTEXTS(dev)) {
 		dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
 		if (dev_priv->hw_context_size > (1<<20)) {
 			DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n",
@@ -435,11 +442,20 @@ int i915_gem_context_init(struct drm_device *dev)
 		return PTR_ERR(ctx);
 	}
 
-	/* NB: RCS will hold a ref for all rings */
-	for (i = 0; i < I915_NUM_RINGS; i++)
-		dev_priv->ring[i].default_context = ctx;
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		struct intel_engine_cs *ring = &dev_priv->ring[i];
+
+		/* NB: RCS will hold a ref for all rings */
+		ring->default_context = ctx;
+
+		/* FIXME: we really only want to do this for initialized rings */
+		if (i915.enable_execlists)
+			intel_lr_context_deferred_create(ctx, ring);
+	}
 
-	DRM_DEBUG_DRIVER("%s context support initialized\n", dev_priv->hw_context_size ? "HW" : "fake");
+	DRM_DEBUG_DRIVER("%s context support initialized\n",
+			i915.enable_execlists ? "LR" :
+			dev_priv->hw_context_size ? "HW" : "fake");
 	return 0;
 }
 
@@ -781,6 +797,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 	struct intel_context *ctx;
 	int ret;
 
+	/* FIXME: allow user-created LR contexts as well */
 	if (!hw_context_enabled(dev))
 		return -ENODEV;
 
drivers/gpu/drm/i915/intel_lrc.c +15 -0
index 21f7f1c..8cc6b55 100644
@@ -51,3 +51,18 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
 
 	return 0;
 }
+
+void intel_lr_context_free(struct intel_context *ctx)
+{
+	/* TODO */
+}
+
+int intel_lr_context_deferred_create(struct intel_context *ctx,
+				     struct intel_engine_cs *ring)
+{
+	BUG_ON(ctx->legacy_hw_ctx.rcs_state != NULL);
+
+	/* TODO */
+
+	return 0;
+}
drivers/gpu/drm/i915/intel_lrc.h +5 -0
index 75ee9c3..3b93572 100644
@@ -24,6 +24,11 @@
 #ifndef _INTEL_LRC_H_
 #define _INTEL_LRC_H_
 
+/* Logical Ring Contexts */
+void intel_lr_context_free(struct intel_context *ctx);
+int intel_lr_context_deferred_create(struct intel_context *ctx,
+				     struct intel_engine_cs *ring);
+
 /* Execlists */
 int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);
 
Signature · 1 line
1.7.9.5
#8 lore raw

Re: [PATCH 04/43] drm/i915/bdw: Initialization for Logical Ring Contexts

Quoted 98 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

For the moment this is just a placeholder, but it shows one of the main differences between the good ol' HW contexts and the shiny new Logical Ring Contexts: LR contexts allocate and free their own backing objects. Another difference is that the allocation is deferred (as the create function name suggests), but that does not happen in this patch yet, because for the moment we are only dealing with the default context.

Early in the series we had our own gen8_gem_context_init/fini functions, but the truth is they now look almost the same as the legacy hw context init/fini functions. We can always split them later if this ceases to be the case.

Also, we do not fall back to legacy ringbuffers when logical ring context initialization fails (not very likely to happen and, even if it does, hw contexts would probably fail as well).

v2: Daniel says "explain, do not showcase".

---
 drivers/gpu/drm/i915/i915_gem_context.c |   29 +++++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_lrc.c        |   15 +++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.h        |    5 +++++
 3 files changed, 43 insertions(+), 6 deletions(-)
drivers/gpu/drm/i915/i915_gem_context.c +23 -6
index de72a28..718150e 100644
@@ -182,7 +182,10 @@ void i915_gem_context_free(struct kref *ctx_ref)
 						   typeof(*ctx), ref);
 	struct i915_hw_ppgtt *ppgtt = NULL;
 
-	if (ctx->legacy_hw_ctx.rcs_state) {
+	if (i915.enable_execlists) {
+		ppgtt = ctx_to_ppgtt(ctx);
+		intel_lr_context_free(ctx);
+	} else if (ctx->legacy_hw_ctx.rcs_state) {
 		/* We refcount even the aliasing PPGTT to keep the code symmetric */
 		if (USES_PPGTT(ctx->legacy_hw_ctx.rcs_state->base.dev))
 			ppgtt = ctx_to_ppgtt(ctx);
@@ -419,7 +422,11 @@ int i915_gem_context_init(struct drm_device *dev)
 	if (WARN_ON(dev_priv->ring[RCS].default_context))
 		return 0;
 
-	if (HAS_HW_CONTEXTS(dev)) {
+	if (i915.enable_execlists) {
+		/* NB: intentionally left blank. We will allocate our own
+		 * backing objects as we need them, thank you very much */
+		dev_priv->hw_context_size = 0;
+	} else if (HAS_HW_CONTEXTS(dev)) {
 		dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
 		if (dev_priv->hw_context_size > (1<<20)) {
 			DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n",
@@ -435,11 +442,20 @@ int i915_gem_context_init(struct drm_device *dev)
 		return PTR_ERR(ctx);
 	}
 
-	/* NB: RCS will hold a ref for all rings */
-	for (i = 0; i < I915_NUM_RINGS; i++)
-		dev_priv->ring[i].default_context = ctx;
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		struct intel_engine_cs *ring = &dev_priv->ring[i];
+
+		/* NB: RCS will hold a ref for all rings */
+		ring->default_context = ctx;
+
+		/* FIXME: we really only want to do this for initialized rings */
+		if (i915.enable_execlists)
+			intel_lr_context_deferred_create(ctx, ring);
+	}
 
-	DRM_DEBUG_DRIVER("%s context support initialized\n", dev_priv->hw_context_size ? "HW" : "fake");
+	DRM_DEBUG_DRIVER("%s context support initialized\n",
+			i915.enable_execlists ? "LR" :
+			dev_priv->hw_context_size ? "HW" : "fake");
 	return 0;
 }
 
@@ -781,6 +797,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 	struct intel_context *ctx;
 	int ret;
 
+	/* FIXME: allow user-created LR contexts as well */
 	if (!hw_context_enabled(dev))
 		return -ENODEV;
 
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index 21f7f1c..8cc6b55 100644
@@ -51,3 +51,18 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
 
 	return 0;
 }

drivers/gpu/drm/i915/intel_lrc.c int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists · line 63

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +10 -0
+
+void intel_lr_context_free(struct intel_context *ctx)
+{
+	/* TODO */
+}
+
+int intel_lr_context_deferred_create(struct intel_context *ctx,
+				     struct intel_engine_cs *ring)
+{
+	BUG_ON(ctx->legacy_hw_ctx.rcs_state != NULL);

I command thy:

Thou shalt not use BUG_ON except in especially dire circumstances!

Fixed while applying.
-Daniel

Quoted 28 lines
drivers/gpu/drm/i915/intel_lrc.c +5 -0
+
+	/* TODO */
+
+	return 0;
+}
drivers/gpu/drm/i915/intel_lrc.h +5 -0
index 75ee9c3..3b93572 100644
@@ -24,6 +24,11 @@
 #ifndef _INTEL_LRC_H_
 #define _INTEL_LRC_H_
 
+/* Logical Ring Contexts */
+void intel_lr_context_free(struct intel_context *ctx);
+int intel_lr_context_deferred_create(struct intel_context *ctx,
+				     struct intel_engine_cs *ring);
+
 /* Execlists */
 int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);
 
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#9 lore raw

PATCH 5/43 drm/i915/bdw: Introduce one context backing object per engine

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

A context backing object only makes sense for a given engine (because it holds state data specific to that engine).

In legacy ringbuffer sumission mode, the only MI_SET_CONTEXT we really perform is for the render engine, so one backing object is all we nee.

With Execlists, however, we need backing objects for every engine, as contexts become the only way to submit workloads to the GPU. To tackle this problem, we multiplex the context struct to contain <no-of-engines> objects.

Originally, I colored this code by instantiating one new context for every engine I wanted to use, but this change suggested by Brad Volkin makes it more elegant.

v2: Leave the old backing object pointer behind. Daniel Vetter suggested using a union, but it makes more sense to keep rcs_state as a NULL pointer behind, to make sure no one uses it incorrectly when Execlists are enabled, similar to what he suggested for ring->buffer (Rusty's API level 5).

v3: Use the name "state" instead of the too-generic "obj", so that it mirrors the name choice for the legacy rcs_state.

---
 drivers/gpu/drm/i915/i915_drv.h |    6 ++++++
 1 file changed, 6 insertions(+)
drivers/gpu/drm/i915/i915_drv.h +6 -0
index a793d6d..b2b0c80 100644
@@ -616,11 +616,17 @@ struct intel_context {
 	struct i915_ctx_hang_stats hang_stats;
 	struct i915_address_space *vm;
 
+	/* Legacy ring buffer submission */
 	struct {
 		struct drm_i915_gem_object *rcs_state;
 		bool initialized;
 	} legacy_hw_ctx;
 
+	/* Execlists */
+	struct {
+		struct drm_i915_gem_object *state;
+	} engine[I915_NUM_RINGS];
+
 	struct list_head link;
 };
 
Signature · 1 line
1.7.9.5
#10 lore raw

PATCH 1/1 drm/i915: WARN if module opt sanitization goes out of order

Depending upon one module option to be sanitized (through USES_PPGTT) for the other is a bit too fragile for my taste. At least WARN about this.

Cc Ben Widawsky <[email protected]>
Cc Damien Lespiau <[email protected]>
Cc Oscar Mateo <[email protected]>
---
 drivers/gpu/drm/i915/intel_lrc.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +2 -0
index 21f7f1cce86e..44721292eb77 100644
@@ -43,6 +43,8 @@
 
 int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists)
 {
+	WARN_ON(i915.enable_ppgtt == -1);
+
 	if (enable_execlists == 0)
 		return 0;
 
Signature · 1 line
2.0.1
Reviewed-by on v1 1/1
#11 lore raw

Re: [PATCH] drm/i915: WARN if module opt sanitization goes out of order

Quoted 8 lines · Daniel Vetter

Depending upon one module option to be sanitized (through USES_PPGTT) for the other is a bit too fragile for my taste. At least WARN about this.

Cc Ben Widawsky <[email protected]>
Cc Damien Lespiau <[email protected]>
Cc Oscar Mateo <[email protected]>

Sounds like a safety measure we'd want. Until we try to fix these kind of dependencies in a more adequate manner that is.

Signature · 1 line
Damien
Quoted 20 lines
---
 drivers/gpu/drm/i915/intel_lrc.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +2 -0
index 21f7f1cce86e..44721292eb77 100644
@@ -43,6 +43,8 @@
 
 int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists)
 {
+	WARN_ON(i915.enable_ppgtt == -1);
+
 	if (enable_execlists == 0)
 		return 0;
 
Signature · 1 line
2.0.1
#12 lore raw

PATCH 6/43 drm/i915/bdw: A bit more advanced LR context alloc/free

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Now that we have the ability to allocate our own context backing objects and we have multiplexed one of them per engine inside the context structs, we can finally allocate and free them correctly.

Regarding the context size, reading the register to calculate the sizes can work, I think, however the docs are very clear about the actual context sizes on GEN8, so just hardcode that and use it.

v2: Rebased on top of the Full PPGTT series. It is important to notice that at this point we have one global default context per engine, all of them using the aliasing PPGTT (as opposed to the single global default context we have with legacy HW contexts).

v3:
- Go back to one single global default context, this time with multiple backing objects inside.
- Use different context sizes for non-render engines, as suggested by Damien (still hardcoded, since the information about the context size registers in the BSpec is, well, *lacking*).
- Render ctx size is 20 (or 19) pages, but not 21 (caught by Damien).
- Move default context backing object creation to intel_init_ring (so that we don't waste memory in rings that might not get initialized).

v4:
- Reuse the HW legacy context init/fini.
- Create a separate free function.
- Rename the functions with an intel_ preffix.

v5: Several rebases to account for the changes in the previous patches.

---
 drivers/gpu/drm/i915/i915_drv.h         |    2 ++
 drivers/gpu/drm/i915/i915_gem_context.c |    2 +-
 drivers/gpu/drm/i915/intel_lrc.c        |   59 +++++++++++++++++++++++++++++--
 3 files changed, 60 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/i915_drv.h +2 -0
index b2b0c80..f2a6598 100644
@@ -2500,6 +2500,8 @@ int i915_switch_context(struct intel_engine_cs *ring,
 struct intel_context *
 i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
 void i915_gem_context_free(struct kref *ctx_ref);
+struct drm_i915_gem_object *
+i915_gem_alloc_context_obj(struct drm_device *dev, size_t size);
 static inline void i915_gem_context_reference(struct intel_context *ctx)
 {
 	kref_get(&ctx->ref);
drivers/gpu/drm/i915/i915_gem_context.c +1 -1
index 718150e..48d7476 100644
@@ -201,7 +201,7 @@ void i915_gem_context_free(struct kref *ctx_ref)
 	kfree(ctx);
 }
 
-static struct drm_i915_gem_object *
+struct drm_i915_gem_object *
 i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
 {
 	struct drm_i915_gem_object *obj;
drivers/gpu/drm/i915/intel_lrc.c +57 -2

78 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#13 lore raw

PATCH 7/43 drm/i915/bdw: Allocate ringbuffers for Logical Ring Contexts

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

As we have said a couple of times by now, logical ring contexts have their own ringbuffers: not only the backing pages, but the whole management struct.

In a previous version of the series, this was achieved with two separate patches:
drm/i915/bdw: Allocate ringbuffer backing objects for default global LRC drm/i915/bdw: Allocate ringbuffer for user-created LRCs

---
 drivers/gpu/drm/i915/i915_drv.h         |    1 +
 drivers/gpu/drm/i915/intel_lrc.c        |   38 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.c |    6 ++---
 drivers/gpu/drm/i915/intel_ringbuffer.h |    4 ++++
 4 files changed, 46 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/i915_drv.h +1 -0
index f2a6598..ff2c373 100644
@@ -625,6 +625,7 @@ struct intel_context {
 	/* Execlists */
 	struct {
 		struct drm_i915_gem_object *state;
+		struct intel_ringbuffer *ringbuf;
 	} engine[I915_NUM_RINGS];
 
 	struct list_head link;
drivers/gpu/drm/i915/intel_lrc.c +38 -0
index a3fc6fc..0a12b8c 100644
@@ -63,7 +63,11 @@ void intel_lr_context_free(struct intel_context *ctx)
 
 	for (i = 0; i < I915_NUM_RINGS; i++) {
 		struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state;
+		struct intel_ringbuffer *ringbuf = ctx->engine[i].ringbuf;
+
 		if (ctx_obj) {
+			intel_destroy_ringbuffer_obj(ringbuf);
+			kfree(ringbuf);
 			i915_gem_object_ggtt_unpin(ctx_obj);
 			drm_gem_object_unreference(&ctx_obj->base);
 		}
@@ -97,6 +101,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 	struct drm_device *dev = ring->dev;
 	struct drm_i915_gem_object *ctx_obj;
 	uint32_t context_size;
+	struct intel_ringbuffer *ringbuf;
 	int ret;
 
 	BUG_ON(ctx->legacy_hw_ctx.rcs_state != NULL);
@@ -117,6 +122,39 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 		return ret;
 	}
 
+	ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
+	if (!ringbuf) {
+		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
+				ring->name);
+		i915_gem_object_ggtt_unpin(ctx_obj);
+		drm_gem_object_unreference(&ctx_obj->base);
+		ret = -ENOMEM;
+		return ret;
+	}
+
+	ringbuf->size = 32 * PAGE_SIZE;
+	ringbuf->effective_size = ringbuf->size;
+	ringbuf->head = 0;
+	ringbuf->tail = 0;
+	ringbuf->space = ringbuf->size;
+	ringbuf->last_retired_head = -1;
+
+	/* TODO: For now we put this in the mappable region so that we can reuse
+	 * the existing ringbuffer code which ioremaps it. When we start
+	 * creating many contexts, this will no longer work and we must switch
+	 * to a kmapish interface.
+	 */
+	ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer obj %s: %d\n",
+				ring->name, ret);
+		kfree(ringbuf);
+		i915_gem_object_ggtt_unpin(ctx_obj);
+		drm_gem_object_unreference(&ctx_obj->base);
+		return ret;
+	}
+
+	ctx->engine[ring->id].ringbuf = ringbuf;
 	ctx->engine[ring->id].state = ctx_obj;
 
 	return 0;
drivers/gpu/drm/i915/intel_ringbuffer.c +3 -3
index 599709e..01e9840 100644
@@ -1495,7 +1495,7 @@ static int init_phys_status_page(struct intel_engine_cs *ring)
 	return 0;
 }
 
-static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
+void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
 {
 	if (!ringbuf->obj)
 		return;
@@ -1506,8 +1506,8 @@ static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
 	ringbuf->obj = NULL;
 }
 
-static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
-				      struct intel_ringbuffer *ringbuf)
+int intel_alloc_ringbuffer_obj(struct drm_device *dev,
+			       struct intel_ringbuffer *ringbuf)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct drm_i915_gem_object *obj;
drivers/gpu/drm/i915/intel_ringbuffer.h +4 -0
index ed59410..053d004 100644
@@ -353,6 +353,10 @@ intel_write_status_page(struct intel_engine_cs *ring,
 #define I915_GEM_HWS_SCRATCH_INDEX	0x30
 #define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
 
+void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf);
+int intel_alloc_ringbuffer_obj(struct drm_device *dev,
+			       struct intel_ringbuffer *ringbuf);
+
 void intel_stop_ring_buffer(struct intel_engine_cs *ring);
 void intel_cleanup_ring_buffer(struct intel_engine_cs *ring);
 
Signature · 1 line
1.7.9.5
#14 lore raw

PATCH 8/43 drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Any given ringbuffer is unequivocally tied to one context and one engine. By setting the appropriate pointers to them, the ringbuffer struct holds all the infromation you might need to submit a workload for processing, Execlists style.

---
 drivers/gpu/drm/i915/intel_lrc.c        |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 +++
 3 files changed, 7 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +2 -0
index 0a12b8c..2eb7db6 100644
@@ -132,6 +132,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 		return ret;
 	}
 
+	ringbuf->ring = ring;
+	ringbuf->ctx = ctx;
 	ringbuf->size = 32 * PAGE_SIZE;
 	ringbuf->effective_size = ringbuf->size;
 	ringbuf->head = 0;
drivers/gpu/drm/i915/intel_ringbuffer.c +2 -0
index 01e9840..279dda4 100644
@@ -1570,6 +1570,8 @@ static int intel_init_ring_buffer(struct drm_device *dev,
 	INIT_LIST_HEAD(&ring->active_list);
 	INIT_LIST_HEAD(&ring->request_list);
 	ringbuf->size = 32 * PAGE_SIZE;
+	ringbuf->ring = ring;
+	ringbuf->ctx = ring->default_context;
 	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
 
 	init_waitqueue_head(&ring->irq_queue);
drivers/gpu/drm/i915/intel_ringbuffer.h +3 -0
index 053d004..be40788 100644
@@ -88,6 +88,9 @@ struct intel_ringbuffer {
 	struct drm_i915_gem_object *obj;
 	void __iomem *virtual_start;
 
+	struct intel_engine_cs *ring;
+	struct intel_context *ctx;
+
 	u32 head;
 	u32 tail;
 	int space;
Signature · 1 line
1.7.9.5
#15 lore raw

Re: [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 32 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Any given ringbuffer is unequivocally tied to one context and one engine. By setting the appropriate pointers to them, the ringbuffer struct holds all the infromation you might need to submit a workload for processing, Execlists style.

---
 drivers/gpu/drm/i915/intel_lrc.c        |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 +++
 3 files changed, 7 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +2 -0
index 0a12b8c..2eb7db6 100644
@@ -132,6 +132,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 		return ret;
 	}
 
+	ringbuf->ring = ring;
+	ringbuf->ctx = ctx;
 	ringbuf->size = 32 * PAGE_SIZE;
 	ringbuf->effective_size = ringbuf->size;
 	ringbuf->head = 0;
drivers/gpu/drm/i915/intel_ringbuffer.c +0 -0
index 01e9840..279dda4 100644

drivers/gpu/drm/i915/intel_ringbuffer.c static int intel_init_ring_buffer(struct drm_device *dev, · line 1574

Quoted 5 lines
drivers/gpu/drm/i915/intel_ringbuffer.c +2 -0
@@ -1570,6 +1570,8 @@ static int intel_init_ring_buffer(struct drm_device *dev,
 	INIT_LIST_HEAD(&ring->active_list);
 	INIT_LIST_HEAD(&ring->request_list);
 	ringbuf->size = 32 * PAGE_SIZE;
+	ringbuf->ring = ring;
+	ringbuf->ctx = ring->default_context;

That doesn't make a terribly lot of sense tbh. I fear it's one of these slight confusions which will take tons of patches to clean up. Why exactly do we need the ring->ctx pointer?

If we only need this for lrc I want to name it accordingly, to make sure legacy code doesn't grow stupid ideas. And also we should only initialize this in the lrc ctx init then.

All patches up to this one merged.
-Daniel

Quoted 24 lines
drivers/gpu/drm/i915/intel_ringbuffer.c +0 -0
 	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
 
 	init_waitqueue_head(&ring->irq_queue);
drivers/gpu/drm/i915/intel_ringbuffer.h +3 -0
index 053d004..be40788 100644
@@ -88,6 +88,9 @@ struct intel_ringbuffer {
 	struct drm_i915_gem_object *obj;
 	void __iomem *virtual_start;
 
+	struct intel_engine_cs *ring;
+	struct intel_context *ctx;
+
 	u32 head;
 	u32 tail;
 	int space;
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#16 lore raw

Re: [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 43 lines · Daniel Vetter
Quoted 32 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Any given ringbuffer is unequivocally tied to one context and one engine. By setting the appropriate pointers to them, the ringbuffer struct holds all the infromation you might need to submit a workload for processing, Execlists style.

---
 drivers/gpu/drm/i915/intel_lrc.c        |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 +++
 3 files changed, 7 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +2 -0
index 0a12b8c..2eb7db6 100644
@@ -132,6 +132,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 		return ret;
 	}
 
+	ringbuf->ring = ring;
+	ringbuf->ctx = ctx;
 	ringbuf->size = 32 * PAGE_SIZE;
 	ringbuf->effective_size = ringbuf->size;
 	ringbuf->head = 0;
drivers/gpu/drm/i915/intel_ringbuffer.c +0 -0
index 01e9840..279dda4 100644

drivers/gpu/drm/i915/intel_ringbuffer.c static int intel_init_ring_buffer(struct drm_device *dev, · line 1574

Quoted 5 lines
drivers/gpu/drm/i915/intel_ringbuffer.c +2 -0
@@ -1570,6 +1570,8 @@ static int intel_init_ring_buffer(struct drm_device *dev,
 	INIT_LIST_HEAD(&ring->active_list);
 	INIT_LIST_HEAD(&ring->request_list);
 	ringbuf->size = 32 * PAGE_SIZE;
+	ringbuf->ring = ring;
+	ringbuf->ctx = ring->default_context;

That doesn't make a terribly lot of sense tbh. I fear it's one of these slight confusions which will take tons of patches to clean up. Why exactly do we need the ring->ctx pointer?

Quoted 5 lines

If we only need this for lrc I want to name it accordingly, to make sure legacy code doesn't grow stupid ideas. And also we should only initialize this in the lrc ctx init then.

All patches up to this one merged.

Ok, I've discussed this quickly with Damien on irc. We decided to cut away the ring->ctx part of this patch for now to be able to move on. -Daniel

Quoted 31 lines

-Daniel

Quoted 24 lines
drivers/gpu/drm/i915/intel_ringbuffer.c +0 -0
 	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
 
 	init_waitqueue_head(&ring->irq_queue);
drivers/gpu/drm/i915/intel_ringbuffer.h +3 -0
index 053d004..be40788 100644
@@ -88,6 +88,9 @@ struct intel_ringbuffer {
 	struct drm_i915_gem_object *obj;
 	void __iomem *virtual_start;
 
+	struct intel_engine_cs *ring;
+	struct intel_context *ctx;
+
 	u32 head;
 	u32 tail;
 	int space;
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#17 lore raw

Re: [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 63 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 3:21 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 15 lines · Daniel Vetter
Quoted 14 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Any given ringbuffer is unequivocally tied to one context and one engine. By setting the appropriate pointers to them, the ringbuffer struct holds all the infromation you might need to submit a workload for processing, Execlists style.

---
 drivers/gpu/drm/i915/intel_lrc.c        |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 +++
 3 files changed, 7 insertions(+)
Quoted 6 lines

drivers/gpu/drm/i915/intel_lrc.c int intel_lr_context_deferred_create(struct

Quoted 6 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index 0a12b8c..2eb7db6 100644
@@ -132,6 +132,8 @@ int intel_lr_context_deferred_create(struct

intel_context *ctx,

Quoted 14 lines

drivers/gpu/drm/i915/intel_ringbuffer.c static int intel_init_ring_buffer(struct

Quoted 14 lines
drivers/gpu/drm/i915/intel_lrc.c +2 -0
 		return ret;
 	}
 
+	ringbuf->ring = ring;
+	ringbuf->ctx = ctx;
 	ringbuf->size = 32 * PAGE_SIZE;
 	ringbuf->effective_size = ringbuf->size;
 	ringbuf->head = 0;
drivers/gpu/drm/i915/intel_ringbuffer.c +0 -0
index 01e9840..279dda4 100644
@@ -1570,6 +1570,8 @@ static int intel_init_ring_buffer(struct

drm_device *dev,

Quoted 14 lines

drivers/gpu/drm/i915/intel_ringbuffer.c static int intel_init_ring_buffer(struct drm_device *dev, · line 1574

Quoted 5 lines
drivers/gpu/drm/i915/intel_ringbuffer.c +2 -0
 	INIT_LIST_HEAD(&ring->active_list);
 	INIT_LIST_HEAD(&ring->request_list);
 	ringbuf->size = 32 * PAGE_SIZE;
+	ringbuf->ring = ring;
+	ringbuf->ctx = ring->default_context;

That doesn't make a terribly lot of sense tbh. I fear it's one of these slight confusions which will take tons of patches to clean up. Why exactly do we need the ring->ctx pointer?

If we only need this for lrc I want to name it accordingly, to make sure legacy code doesn't grow stupid ideas. And also we should only initialize this in the lrc ctx init then.

Quoted 5 lines
Quoted 1 line

All patches up to this one merged.

Ok, I've discussed this quickly with Damien on irc. We decided to cut away the ring->ctx part of this patch for now to be able to move on. -Daniel

As you've seen, removing ringbuffer->ctx causes serious problems with the plumbing later on. This can be renamed (perhaps to lrc) and removed from legacy init.

Each ring buffer belongs to a specific context - it makes sense to me to keep this information within the ringbuffer structure so that we don't have to pass the context pointer around everywhere.

Thomas.

Quoted 39 lines
Quoted 25 lines

-Daniel

Quoted 22 lines
drivers/gpu/drm/i915/intel_ringbuffer.c +0 -0
 	memset(ring->semaphore.sync_seqno, 0,
 sizeof(ring->semaphore.sync_seqno));
 
drivers/gpu/drm/i915/intel_ringbuffer.c +0 -0
 	init_waitqueue_head(&ring->irq_queue);
drivers/gpu/drm/i915/intel_ringbuffer.h +3 -1
index 053d004..be40788 100644
@@ -88,6 +88,9 @@ struct intel_ringbuffer {
 	struct drm_i915_gem_object *obj;
 	void __iomem *virtual_start;
 
+	struct intel_engine_cs *ring;
+	struct intel_context *ctx;
+
 	u32 head;
 	u32 tail;
 	int space;
--

1.7.9.5

Quoted 9 lines
Quoted 4 lines

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#18 lore raw

Re: [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 68 lines · Thomas
Quoted 63 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 3:21 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 15 lines · Daniel Vetter
Quoted 14 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Any given ringbuffer is unequivocally tied to one context and one engine. By setting the appropriate pointers to them, the ringbuffer struct holds all the infromation you might need to submit a workload for processing, Execlists style.

---
 drivers/gpu/drm/i915/intel_lrc.c        |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 +++
 3 files changed, 7 insertions(+)
Quoted 6 lines

drivers/gpu/drm/i915/intel_lrc.c int intel_lr_context_deferred_create(struct

Quoted 6 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index 0a12b8c..2eb7db6 100644
@@ -132,6 +132,8 @@ int intel_lr_context_deferred_create(struct

intel_context *ctx,

Quoted 14 lines

drivers/gpu/drm/i915/intel_ringbuffer.c static int intel_init_ring_buffer(struct

Quoted 14 lines
drivers/gpu/drm/i915/intel_lrc.c +2 -0
 		return ret;
 	}
 
+	ringbuf->ring = ring;
+	ringbuf->ctx = ctx;
 	ringbuf->size = 32 * PAGE_SIZE;
 	ringbuf->effective_size = ringbuf->size;
 	ringbuf->head = 0;
drivers/gpu/drm/i915/intel_ringbuffer.c +0 -0
index 01e9840..279dda4 100644
@@ -1570,6 +1570,8 @@ static int intel_init_ring_buffer(struct

drm_device *dev,

Quoted 14 lines

drivers/gpu/drm/i915/intel_ringbuffer.c static int intel_init_ring_buffer(struct drm_device *dev, · line 1574

Quoted 5 lines
drivers/gpu/drm/i915/intel_ringbuffer.c +2 -0
 	INIT_LIST_HEAD(&ring->active_list);
 	INIT_LIST_HEAD(&ring->request_list);
 	ringbuf->size = 32 * PAGE_SIZE;
+	ringbuf->ring = ring;
+	ringbuf->ctx = ring->default_context;

That doesn't make a terribly lot of sense tbh. I fear it's one of these slight confusions which will take tons of patches to clean up. Why exactly do we need the ring->ctx pointer?

If we only need this for lrc I want to name it accordingly, to make sure legacy code doesn't grow stupid ideas. And also we should only initialize this in the lrc ctx init then.

Quoted 5 lines
Quoted 1 line

All patches up to this one merged.

Ok, I've discussed this quickly with Damien on irc. We decided to cut away the ring->ctx part of this patch for now to be able to move on. -Daniel

Quoted 7 lines

As you've seen, removing ringbuffer->ctx causes serious problems with the plumbing later on. This can be renamed (perhaps to lrc) and removed from legacy init.

Each ring buffer belongs to a specific context - it makes sense to me to keep this information within the ringbuffer structure so that we don't have to pass the context pointer around everywhere.

I agree that it causes trouble with the follow-up patches, but I'm not sold on this being a terrible good idea. After all for ELSP we don't want to submit a ring, we want to submit the full context. So if the code that's supposed to do the execlist ctx submission only has the pointer to the ring object, the layer looks a bit wrong.

Same was iirc about the add_request part.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#19 lore raw

Re: [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 89 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Wednesday, August 13, 2014 4:16 PM
To: Daniel, Thomas
Cc: Daniel Vetter; [email protected]
Subject: Re: [Intel-gfx] [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 11 lines · Thomas
Quoted 11 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 3:21 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 5 lines
Quoted 5 lines · Daniel Vetter
Quoted 4 lines · Thomas Daniel
Quoted 3 lines

From: Oscar Mateo <[email protected]>

Any given ringbuffer is unequivocally tied to one context and one

engine.

Quoted 52 lines
Quoted 47 lines
Quoted 11 lines
Quoted 11 lines

By setting the appropriate pointers to them, the ringbuffer struct holds all the infromation you might need to submit a workload for processing, Execlists style.

---
 drivers/gpu/drm/i915/intel_lrc.c        |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c |    2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 +++
 3 files changed, 7 insertions(+)
Quoted 6 lines

drivers/gpu/drm/i915/intel_lrc.c int intel_lr_context_deferred_create(struct

Quoted 6 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index 0a12b8c..2eb7db6 100644
@@ -132,6 +132,8 @@ int intel_lr_context_deferred_create(struct

intel_context *ctx,

Quoted 14 lines

drivers/gpu/drm/i915/intel_ringbuffer.c static int intel_init_ring_buffer(struct

Quoted 14 lines
drivers/gpu/drm/i915/intel_lrc.c +2 -0
 		return ret;
 	}
 
+	ringbuf->ring = ring;
+	ringbuf->ctx = ctx;
 	ringbuf->size = 32 * PAGE_SIZE;
 	ringbuf->effective_size = ringbuf->size;
 	ringbuf->head = 0;
drivers/gpu/drm/i915/intel_ringbuffer.c +0 -0
index 01e9840..279dda4 100644
@@ -1570,6 +1570,8 @@ static int intel_init_ring_buffer(struct

drm_device *dev,

Quoted 14 lines

drivers/gpu/drm/i915/intel_ringbuffer.c static int intel_init_ring_buffer(struct drm_device *dev, · line 1574

Quoted 5 lines
drivers/gpu/drm/i915/intel_ringbuffer.c +2 -0
 	INIT_LIST_HEAD(&ring->active_list);
 	INIT_LIST_HEAD(&ring->request_list);
 	ringbuf->size = 32 * PAGE_SIZE;
+	ringbuf->ring = ring;
+	ringbuf->ctx = ring->default_context;

That doesn't make a terribly lot of sense tbh. I fear it's one of these slight confusions which will take tons of patches to clean up. Why exactly do we need the ring->ctx pointer?

If we only need this for lrc I want to name it accordingly, to make sure legacy code doesn't grow stupid ideas. And also we should only initialize this in the lrc ctx init then.

Quoted 5 lines
Quoted 1 line

All patches up to this one merged.

Ok, I've discussed this quickly with Damien on irc. We decided to cut away the ring->ctx part of this patch for now to be able to move on. -Daniel

Quoted 7 lines

As you've seen, removing ringbuffer->ctx causes serious problems with the plumbing later on. This can be renamed (perhaps to lrc) and removed from legacy init.

Each ring buffer belongs to a specific context - it makes sense to me to keep this information within the ringbuffer structure so that we don't have to pass the context pointer around everywhere.

Quoted 5 lines

I agree that it causes trouble with the follow-up patches, but I'm not sold on this being a terrible good idea. After all for ELSP we don't want to submit a ring, we want to submit the full context. So if the code that's supposed to do the execlist ctx submission only has the pointer to the ring object, the layer looks a bit wrong.

When it comes to the execlist submission (actually as early as the execlist request queueing), the engine and context are indeed used and required. intel_logical_ring_advance_and_submit() is the lrc function analogous to __intel_ring_advance() and I believe the initial creation of intel_lrc.c was actually done by copying intel_ringbuffer.c. This explains why some of the lrc code is perhaps not as it would have been if this had been designed from scratch, and there is room for future improvement. advance_and_submit therefore only gets the ringbuffer struct and uses the context pointer in that struct to get the logical ring context itself. At that point the engine, context and new tail pointer are handed over to the execlist queue backend.

Thomas.

Quoted 7 lines

Same was iirc about the add_request part.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#20 lore raw

Re: [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 11 lines · Thomas

When it comes to the execlist submission (actually as early as the execlist request queueing), the engine and context are indeed used and required. intel_logical_ring_advance_and_submit() is the lrc function analogous to __intel_ring_advance() and I believe the initial creation of intel_lrc.c was actually done by copying intel_ringbuffer.c. This explains why some of the lrc code is perhaps not as it would have been if this had been designed from scratch, and there is room for future improvement. advance_and_submit therefore only gets the ringbuffer struct and uses the context pointer in that struct to get the logical ring context itself. At that point the engine, context and new tail pointer are handed over to the execlist queue backend.

I guess I need to clarify: Does it make sense to move the ELSP respectively the submission to the execlist scheduler queue out of there up a few levels into the execlist cmd submission function? Is it possible or is there some technical reason that I'm overlooking?

I want to know what exactly I'm dealing with here before I sign up for it by merging the patches as-is and asking for a cleanup. I doesn't look bad really, but there's always a good chance that I've overlooked a bigger dragon.

Since you have the patches and worked with them I'm asking you such explorative questions. Ofc I can do this checking myself, but that takes time ... This doesn't mean that you have to implement the changes, just be reasonable confident that it will work out as a cleanup on top. -Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#21 lore raw

Re: [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 23 lines · Daniel Vetter
Quoted 11 lines · Thomas

When it comes to the execlist submission (actually as early as the execlist request queueing), the engine and context are indeed used and required. intel_logical_ring_advance_and_submit() is the lrc function analogous to __intel_ring_advance() and I believe the initial creation of intel_lrc.c was actually done by copying intel_ringbuffer.c. This explains why some of the lrc code is perhaps not as it would have been if this had been designed from scratch, and there is room for future improvement. advance_and_submit therefore only gets the ringbuffer struct and uses the context pointer in that struct to get the logical ring context itself. At that point the engine, context and new tail pointer are handed over to the execlist queue backend.

I guess I need to clarify: Does it make sense to move the ELSP respectively the submission to the execlist scheduler queue out of there up a few levels into the execlist cmd submission function? Is it possible or is there some technical reason that I'm overlooking?

I want to know what exactly I'm dealing with here before I sign up for it by merging the patches as-is and asking for a cleanup. I doesn't look bad really, but there's always a good chance that I've overlooked a bigger dragon.

Quoted 4 lines

Since you have the patches and worked with them I'm asking you such explorative questions. Ofc I can do this checking myself, but that takes time ... This doesn't mean that you have to implement the changes, just be reasonable confident that it will work out as a cleanup on top.

To clarify more the context: Currently you're replies sound like "This is what it looks like and I don't really know why nor whether we can change that". That's not confidence instilling and that makes maintainers reluctant to merge patches for fear of needing to fix things themselves ;-)
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#22 lore raw

Re: [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 15 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Thursday, August 14, 2014 4:37 PM
To: Daniel, Thomas
Cc: Daniel Vetter; [email protected]
Subject: Re: [Intel-gfx] [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 3 lines · Daniel Vetter
Quoted 2 lines · Thomas

When it comes to the execlist submission (actually as early as the execlist request queueing), the engine and context are indeed used and

Quoted 17 lines

required.

Quoted 6 lines
Quoted 6 lines

intel_logical_ring_advance_and_submit() is the lrc function analogous to
__intel_ring_advance() and I believe the initial creation of intel_lrc.c was actually done by copying intel_ringbuffer.c. This explains why some of the lrc code is perhaps not as it would have been if this had been designed from scratch, and there is room for future

improvement.

Quoted 9 lines
Quoted 4 lines

advance_and_submit therefore only gets the ringbuffer struct and uses the context pointer in that struct to get the logical ring context itself. At that point the engine, context and new tail pointer are handed over to the execlist queue backend.

I guess I need to clarify: Does it make sense to move the ELSP respectively the submission to the execlist scheduler queue out of there up a few levels into the execlist cmd submission function? Is it possible or is there some technical reason that I'm overlooking?

Yes this would make sense, and we already have a separate emit_request vfunc which is only used in lrc mode so we can for example change the signature to accept a drm_i915_gem_request* directly and take the ctx and engine from there.

Quoted 11 lines
Quoted 10 lines

I want to know what exactly I'm dealing with here before I sign up for it by merging the patches as-is and asking for a cleanup. I doesn't look bad really, but there's always a good chance that I've overlooked a bigger dragon.

Since you have the patches and worked with them I'm asking you such explorative questions. Ofc I can do this checking myself, but that takes time ... This doesn't mean that you have to implement the changes, just be reasonable confident that it will work out as a cleanup on

top.

Understood.

Quoted 3 lines

To clarify more the context: Currently you're replies sound like "This is what it looks like and I don't really know why nor whether we can change that".

You're right, I don't know why it was done this way. But I can see that there is no problem to change it later - it's only a piece of code after all...

Quoted 3 lines

That's not confidence instilling and that makes maintainers reluctant to merge patches for fear of needing to fix things themselves ;-)

If it helps, I can tell you that several guys in our team are working with this code and we have a vested interest in making sure the quality is as high as possible.

Cheers,
Thomas.

Quoted 5 lines

-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#23 lore raw

Re: [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 28 lines · Thomas
Quoted 28 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Thursday, August 14, 2014 4:37 PM
To: Daniel, Thomas
Cc: Daniel Vetter; [email protected]
Subject: Re: [Intel-gfx] [PATCH 08/43] drm/i915/bdw: Add a context and an engine pointers to the ringbuffer

Quoted 3 lines · Daniel Vetter
Quoted 2 lines · Thomas

When it comes to the execlist submission (actually as early as the execlist request queueing), the engine and context are indeed used and

required.

Quoted 6 lines
Quoted 6 lines

intel_logical_ring_advance_and_submit() is the lrc function analogous to
__intel_ring_advance() and I believe the initial creation of intel_lrc.c was actually done by copying intel_ringbuffer.c. This explains why some of the lrc code is perhaps not as it would have been if this had been designed from scratch, and there is room for future

improvement.

Quoted 5 lines
Quoted 4 lines

advance_and_submit therefore only gets the ringbuffer struct and uses the context pointer in that struct to get the logical ring context itself. At that point the engine, context and new tail pointer are handed over to the execlist queue backend.

Quoted 8 lines
Quoted 4 lines
Quoted 4 lines

I guess I need to clarify: Does it make sense to move the ELSP respectively the submission to the execlist scheduler queue out of there up a few levels into the execlist cmd submission function? Is it possible or is there some technical reason that I'm overlooking?

Yes this would make sense, and we already have a separate emit_request vfunc which is only used in lrc mode so we can for example change the signature to accept a drm_i915_gem_request* directly and take the ctx and engine from there.

Hm, I didn't spot the emit_request vfunc yet. Probably another one that I'll ask you to fold in ;-)

Quoted 18 lines
Quoted 10 lines
Quoted 9 lines

I want to know what exactly I'm dealing with here before I sign up for it by merging the patches as-is and asking for a cleanup. I doesn't look bad really, but there's always a good chance that I've overlooked a bigger dragon.

Since you have the patches and worked with them I'm asking you such explorative questions. Ofc I can do this checking myself, but that takes time ... This doesn't mean that you have to implement the changes, just be reasonable confident that it will work out as a cleanup on

top.

Understood.

Quoted 3 lines

To clarify more the context: Currently you're replies sound like "This is what it looks like and I don't really know why nor whether we can change that".

You're right, I don't know why it was done this way. But I can see that there is no problem to change it later - it's only a piece of code after all...

Quoted 6 lines
Quoted 3 lines

That's not confidence instilling and that makes maintainers reluctant to merge patches for fear of needing to fix things themselves ;-)

If it helps, I can tell you that several guys in our team are working with this code and we have a vested interest in making sure the quality is as high as possible.

Ok, I think you get the hang of how this "guide your maintainer into accepting stuff" game works ;-) I'll take your word for it that there's no dragon hiding and that you'll bravely fight it anyway and will merge in a few more patches. And I'll do a JIRA to jot down the restructuring we need to do.

Merging might be a bit slower since I'm heading to Chicago on Saturday already, so I might ask you to resend the remaining patches.

Cheers, Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#24 lore raw

PATCH 1/1 drm/i915: Add temporary ring->ctx backpointer

From: Oscar Mateo <[email protected]>

The execlist patches have a bit a convoluted and long history and due to that have the actual submission still misplaced deeply burried in the low-level ringbuffer handling code. This design goes back to the legacy ringbuffer code with its tricky lazy request and simple work submissiion using ring tail writes. For that reason they need a ring->ctx backpointer.

The goal is to unburry that code and move it up into a level where the full execlist context is available so that we can ditch this backpointer. Until that's done make it really obvious that there's work still to be done.

Cc Oscar Mateo <[email protected]>
Cc Thomas Daniel <[email protected]>

--

Thomas, please ack this patch and the general plan we've discussed. Then I'll start pulling in more patches and I'll do the s/ctx/FIXME_lrc_ctx/ on the fly.
-Daniel

---
 drivers/gpu/drm/i915/intel_lrc.c        | 2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.h | 7 +++++++
 2 files changed, 9 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +2 -0
index 6b5f416b5c0d..c2352d1b23fa 100644
@@ -1086,6 +1086,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 	}
 
 	ringbuf->ring = ring;
+	ringbuf->FIXME_lrc_ctx = ctx;
+
 	ringbuf->size = 32 * PAGE_SIZE;
 	ringbuf->effective_size = ringbuf->size;
 	ringbuf->head = 0;
drivers/gpu/drm/i915/intel_ringbuffer.h +7 -0
index 24437da91f77..26785ca72530 100644
@@ -99,6 +99,13 @@ struct intel_ringbuffer {
 
 	struct intel_engine_cs *ring;
 
+	/*
+	 * FIXME: This backpointer is an artifact of the history of how the
+	 * execlist patches came into being. It will get removed once the basic
+	 * code has landed.
+	 */
+	struct intel_context *FIXME_lrc_ctx;
+
 	u32 head;
 	u32 tail;
 	int space;
Signature · 1 line
2.0.1
author Acked-by on v1 1/1
#25 lore raw

Re: [PATCH] drm/i915: Add temporary ring->ctx backpointer

Quoted 22 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]]
Sent: Thursday, August 14, 2014 5:28 PM
To: Intel Graphics Development
Cc: Mateo Lozano, Oscar; Daniel, Thomas; Daniel Vetter
Subject: [PATCH] drm/i915: Add temporary ring->ctx backpointer

From: Oscar Mateo <[email protected]>

The execlist patches have a bit a convoluted and long history and due to that have the actual submission still misplaced deeply burried in the low-level ringbuffer handling code. This design goes back to the legacy ringbuffer code with its tricky lazy request and simple work submissiion using ring tail writes. For that reason they need a
ring->ctx backpointer.

The goal is to unburry that code and move it up into a level where the full execlist context is available so that we can ditch this backpointer. Until that's done make it really obvious that there's work still to be done.

Quoted 7 lines
Cc Oscar Mateo <[email protected]>
Cc Thomas Daniel <[email protected]>

--

Thomas, please ack this patch and the general plan we've discussed.

Quoted 44 lines

Then I'll start pulling in more patches and I'll do the s/ctx/FIXME_lrc_ctx/ on the fly.

(quoted diff) +0 -2
-Daniel
---
 drivers/gpu/drm/i915/intel_lrc.c        | 2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.h | 7 +++++++
 2 files changed, 9 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +2 -0
index 6b5f416b5c0d..c2352d1b23fa 100644
@@ -1086,6 +1086,8 @@ int intel_lr_context_deferred_create(struct
 intel_context *ctx,
 	}
 
 	ringbuf->ring = ring;
+	ringbuf->FIXME_lrc_ctx = ctx;
+
 	ringbuf->size = 32 * PAGE_SIZE;
 	ringbuf->effective_size = ringbuf->size;
drivers/gpu/drm/i915/intel_lrc.c +0 -0
 	ringbuf->head = 0;
drivers/gpu/drm/i915/intel_ringbuffer.h +7 -1
index 24437da91f77..26785ca72530 100644
@@ -99,6 +99,13 @@ struct intel_ringbuffer {
 
 	struct intel_engine_cs *ring;
 
+	/*
+	 * FIXME: This backpointer is an artifact of the history of how the
+	 * execlist patches came into being. It will get removed once the basic
+	 * code has landed.
+	 */
+	struct intel_context *FIXME_lrc_ctx;
+
 	u32 head;
 	u32 tail;
 	int space;
--

2.0.1

#26 lore raw

PATCH 9/43 drm/i915/bdw: Populate LR contexts (somewhat)

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

For the most part, logical ring context objects are similar to hardware contexts in that the backing object is meant to be opaque. There are some exceptions where we need to poke certain offsets of the object for initialization, updating the tail pointer or updating the PDPs.

For our basic execlist implementation we'll only need our PPGTT PDs, and ringbuffer addresses in order to set up the context. With previous patches, we have both, so start prepping the context to be load.

Before running a context for the first time you must populate some fields in the context object. These fields begin 1 PAGE + LRCA, ie. the first page (in 0 based counting) of the context image. These same fields will be read and written to as contexts are saved and restored once the system is up and running.

Many of these fields are completely reused from previous global
registers: ringbuffer head/tail/control, context control matches some previous MI_SET_CONTEXT flags, and page directories. There are other fields which we don't touch which we may want in the future.

v2: CTX_LRI_HEADER_0 is MI_LOAD_REGISTER_IMM(14) for render and (11) for other engines.

v3: Several rebases and general changes to the code.

v4: Squash with "Extract LR context object populating"
Also, Damien's review comments:
- Set the Force Posted bit on the LRI header, as the BSpec suggest we do.
- Prevent warning when compiling a 32-bits kernel without HIGHMEM64.
- Add a clarifying comment to the context population code.

v5: Damien's review comments:
- The third MI_LOAD_REGISTER_IMM in the context does not set Force Posted.
- Remove dead code.

v6: Add a note about the (presumed) differences between BDW and CHV state contexts. Also, Brad's review comments:
- Use the _MASKED_BIT_ENABLE, upper_32_bits and lower_32_bits macros.
- Be less magical about how we set the ring size in the context.

---
 drivers/gpu/drm/i915/i915_reg.h  |    1 +
 drivers/gpu/drm/i915/intel_lrc.c |  159 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 156 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/i915_reg.h +1 -0
index ce70aa4..043a6ea 100644
@@ -282,6 +282,7 @@
  *   address/value pairs. Don't overdue it, though, x <= 2^4 must hold!
  */
 #define MI_LOAD_REGISTER_IMM(x)	MI_INSTR(0x22, 2*(x)-1)
+#define   MI_LRI_FORCE_POSTED		(1<<12)
 #define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*(x)-1)
 #define MI_STORE_REGISTER_MEM_GEN8(x) MI_INSTR(0x24, 3*(x)-1)
 #define   MI_SRM_LRM_GLOBAL_GTT		(1<<22)
drivers/gpu/drm/i915/intel_lrc.c +155 -4

181 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#27 lore raw

PATCH 10/43 drm/i915/bdw: Deferred creation of user-created LRCs

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

The backing objects and ringbuffers for contexts created via open fd are actually empty until the user starts sending execbuffers to them. At that point, we allocate & populate them. We do this because, at create time, we really don't know which engine is going to be used with the context later on (and we don't want to waste memory on objects that we might never use).

v2: As contexts created via ioctl can only be used with the render ring, we have enough information to allocate & populate them right away.

v3: Defer the creation always, even with ioctl-created contexts, as requested by Daniel Vetter.

---
 drivers/gpu/drm/i915/i915_gem_context.c    |    7 +++----
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |    8 ++++++++
 2 files changed, 11 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/i915_gem_context.c +3 -4
index 48d7476..fbe7278 100644
@@ -784,9 +784,9 @@ int i915_switch_context(struct intel_engine_cs *ring,
 	return do_switch(ring, to);
 }
 
-static bool hw_context_enabled(struct drm_device *dev)
+static bool contexts_enabled(struct drm_device *dev)
 {
-	return to_i915(dev)->hw_context_size;
+	return i915.enable_execlists || to_i915(dev)->hw_context_size;
 }
 
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
@@ -797,8 +797,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 	struct intel_context *ctx;
 	int ret;
 
-	/* FIXME: allow user-created LR contexts as well */
-	if (!hw_context_enabled(dev))
+	if (!contexts_enabled(dev))
 		return -ENODEV;
 
 	ret = i915_mutex_lock_interruptible(dev);
drivers/gpu/drm/i915/i915_gem_execbuffer.c +8 -0
index c5115957..4e9b387 100644
@@ -951,6 +951,14 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
 		return ERR_PTR(-EIO);
 	}
 
+	if (i915.enable_execlists && !ctx->engine[ring->id].state) {
+		int ret = intel_lr_context_deferred_create(ctx, ring);
+		if (ret) {
+			DRM_DEBUG("Could not create LRC %u: %d\n", ctx_id, ret);
+			return ERR_PTR(ret);
+		}
+	}
+
 	return ctx;
 }
 
Signature · 1 line
1.7.9.5
#28 lore raw

Re: [PATCH 10/43] drm/i915/bdw: Deferred creation of user-created LRCs

Quoted 9 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

The backing objects and ringbuffers for contexts created via open fd are actually empty until the user starts sending execbuffers to them. At that point, we allocate & populate them. We do this because, at create time, we really don't know which engine is going to be used with the context later on (and we don't want to waste memory on objects that we might never use).

Quoted 8 lines

v2: As contexts created via ioctl can only be used with the render ring, we have enough information to allocate & populate them right away.

v3: Defer the creation always, even with ioctl-created contexts, as requested by Daniel Vetter.

This patch seems to miss the hunk to remove

		/* FIXME: we really only want to do this for initialized rings */
		if (i915.enable_execlists)
			intel_lr_context_deferred_create(ctx, ring);

Also I just realized that that code completely lacks error handling.

If it's not already there please quickly submit a fixup patch. -Daniel

Quoted 57 lines
---
 drivers/gpu/drm/i915/i915_gem_context.c    |    7 +++----
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |    8 ++++++++
 2 files changed, 11 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/i915_gem_context.c +3 -4
index 48d7476..fbe7278 100644
@@ -784,9 +784,9 @@ int i915_switch_context(struct intel_engine_cs *ring,
 	return do_switch(ring, to);
 }
 
-static bool hw_context_enabled(struct drm_device *dev)
+static bool contexts_enabled(struct drm_device *dev)
 {
-	return to_i915(dev)->hw_context_size;
+	return i915.enable_execlists || to_i915(dev)->hw_context_size;
 }
 
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
@@ -797,8 +797,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 	struct intel_context *ctx;
 	int ret;
 
-	/* FIXME: allow user-created LR contexts as well */
-	if (!hw_context_enabled(dev))
+	if (!contexts_enabled(dev))
 		return -ENODEV;
 
 	ret = i915_mutex_lock_interruptible(dev);
drivers/gpu/drm/i915/i915_gem_execbuffer.c +8 -0
index c5115957..4e9b387 100644
@@ -951,6 +951,14 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
 		return ERR_PTR(-EIO);
 	}
 
+	if (i915.enable_execlists && !ctx->engine[ring->id].state) {
+		int ret = intel_lr_context_deferred_create(ctx, ring);
+		if (ret) {
+			DRM_DEBUG("Could not create LRC %u: %d\n", ctx_id, ret);
+			return ERR_PTR(ret);
+		}
+	}
+
 	return ctx;
 }
 
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#29 lore raw

PATCH 11/43 drm/i915/bdw: Render moot context reset and switch with Execlists

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enbale_execlists instead.

---
 drivers/gpu/drm/i915/i915_gem_context.c |    9 +++++++++
 1 file changed, 9 insertions(+)
drivers/gpu/drm/i915/i915_gem_context.c +9 -0
index fbe7278..288f5de 100644
@@ -380,6 +380,9 @@ void i915_gem_context_reset(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int i;
 
+	if (i915.enable_execlists)
+		return;
+
 	/* Prevent the hardware from restoring the last context (which hung) on
 	 * the next switch */
 	for (i = 0; i < I915_NUM_RINGS; i++) {
@@ -514,6 +517,9 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
 		ppgtt->enable(ppgtt);
 	}
 
+	if (i915.enable_execlists)
+		return 0;
+
 	/* FIXME: We should make this work, even in reset */
 	if (i915_reset_in_progress(&dev_priv->gpu_error))
 		return 0;
@@ -769,6 +775,9 @@ int i915_switch_context(struct intel_engine_cs *ring,
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 
+	if (i915.enable_execlists)
+		return 0;
+
 	WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 
 	if (to->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */
Signature · 1 line
1.7.9.5
#30 lore raw

Re: [PATCH 11/43] drm/i915/bdw: Render moot context reset and switch with Execlists

Quoted 18 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enbale_execlists instead.

---
 drivers/gpu/drm/i915/i915_gem_context.c |    9 +++++++++
 1 file changed, 9 insertions(+)
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
index fbe7278..288f5de 100644

drivers/gpu/drm/i915/i915_gem_context.c void i915_gem_context_reset(struct drm_device *dev) · line 384

Quoted 5 lines
drivers/gpu/drm/i915/i915_gem_context.c +2 -0
@@ -380,6 +380,9 @@ void i915_gem_context_reset(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int i;
 
+	if (i915.enable_execlists)
+		return;

This will conflict badly with Alistair's patch at a functional level. I'm pretty sure that we want _some_ form of reset for the context state, since the hw didn't just magically load the previously running context. So NACK on this hunk.

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv) · line 521

Quoted 10 lines
drivers/gpu/drm/i915/i915_gem_context.c +3 -0
+
 	/* Prevent the hardware from restoring the last context (which hung) on
 	 * the next switch */
 	for (i = 0; i < I915_NUM_RINGS; i++) {
@@ -514,6 +517,9 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
 		ppgtt->enable(ppgtt);
 	}
 
+	if (i915.enable_execlists)
+		return 0;

Again this conflicts with Alistair's patch. Furthermore it looks redudant since you no-op out i915_switch_context separately.

drivers/gpu/drm/i915/i915_gem_context.c int i915_switch_context(struct intel_engine_cs *ring, · line 779

Quoted 10 lines
drivers/gpu/drm/i915/i915_gem_context.c +3 -0
+
 	/* FIXME: We should make this work, even in reset */
 	if (i915_reset_in_progress(&dev_priv->gpu_error))
 		return 0;
@@ -769,6 +775,9 @@ int i915_switch_context(struct intel_engine_cs *ring,
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 
+	if (i915.enable_execlists)
+		return 0;

I've hoped we don't need this with the legacy ringbuffer cmdsubmission fuly split out. If there are other paths (resume, gpu reset) where this comes into play then I guess we need to look at where the best place is to make this call. So until this comes with a bit a better justification I'll punt on this for now.
-Daniel

Quoted 11 lines
drivers/gpu/drm/i915/i915_gem_context.c +1 -0
+
 	WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 
 	if (to->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#31 lore raw

Re: [PATCH 11/43] drm/i915/bdw: Render moot context reset and switch with Execlists

Quoted 35 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 3:30 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 11/43] drm/i915/bdw: Render moot context reset and switch with Execlists

drivers/gpu/drm/i915/i915_gem_context.c void i915_gem_context_reset(struct drm_device

Quoted 19 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enbale_execlists instead.

---
 drivers/gpu/drm/i915/i915_gem_context.c |    9 +++++++++
 1 file changed, 9 insertions(+)
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
index fbe7278..288f5de 100644
@@ -380,6 +380,9 @@ void i915_gem_context_reset(struct drm_device

*dev)

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int i;
 
Quoted 6 lines

drivers/gpu/drm/i915/i915_gem_context.c void i915_gem_context_reset(struct drm_device *dev) · line 384

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_context.c +2 -0
+	if (i915.enable_execlists)
+		return;

This will conflict badly with Alistair's patch at a functional level. I'm pretty sure that we want _some_ form of reset for the context state, since the hw didn't just magically load the previously running context. So NACK on this hunk.

OK I'll wait to see the final version of Alistair's patch and decide what to do about this hunk.

Quoted 10 lines

drivers/gpu/drm/i915/i915_gem_context.c void i915_gem_context_reset(struct drm_device · line 386

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +1 -0
+
 	/* Prevent the hardware from restoring the last context (which

hung) on

Quoted 6 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 	 * the next switch */
 	for (i = 0; i < I915_NUM_RINGS; i++) { @@ -514,6 +517,9 @@ int

i915_gem_context_enable(struct drm_i915_private *dev_priv)

drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 		ppgtt->enable(ppgtt);
 	}
Quoted 5 lines

drivers/gpu/drm/i915/i915_gem_context.c

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_context.c +2 -0
+	if (i915.enable_execlists)
+		return 0;

Again this conflicts with Alistair's patch. Furthermore it looks redudant since you no-op out i915_switch_context separately.

I don't think this is a conflict. Doesn't Alistair's change here just involve writing PDPs for full PPGTT? We don't want to do that in lrc mode.

Quoted 9 lines
Quoted 9 lines
drivers/gpu/drm/i915/i915_gem_context.c +1 -0
+
 	/* FIXME: We should make this work, even in reset */
 	if (i915_reset_in_progress(&dev_priv->gpu_error))
 		return 0;
@@ -769,6 +775,9 @@ int i915_switch_context(struct intel_engine_cs
 *ring,  {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 
Quoted 8 lines

drivers/gpu/drm/i915/i915_gem_context.c int i915_switch_context(struct intel_engine_cs · line 779

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_context.c +2 -0
+	if (i915.enable_execlists)
+		return 0;

I've hoped we don't need this with the legacy ringbuffer cmdsubmission fuly split out. If there are other paths (resume, gpu reset) where this comes into play then I guess we need to look at where the best place is to make this call. So until this comes with a bit a better justification I'll punt on this for now. -Daniel

Yes, the command submission lrc path doesn't call this but other codepaths do. If we keep the check in context_enable() the only remaining call I see is in i915_gpu_idle(). I don't mind if the check is done there but perhaps a WARN_ON should then be added into switch_context() because we don't want to be putting illegal MI_SET_CONTEXT commands into the ring.

Thomas.

Quoted 18 lines
Quoted 9 lines
drivers/gpu/drm/i915/i915_gem_context.c +1 -0
+
 	WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 
 	if (to->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake

context */
--
1.7.9.5

Quoted 4 lines

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#32 lore raw

Re: [PATCH 11/43] drm/i915/bdw: Render moot context reset and switch with Execlists

Quoted 54 lines · Thomas
Quoted 35 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 3:30 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 11/43] drm/i915/bdw: Render moot context reset and switch with Execlists

drivers/gpu/drm/i915/i915_gem_context.c void i915_gem_context_reset(struct drm_device

Quoted 19 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enbale_execlists instead.

---
 drivers/gpu/drm/i915/i915_gem_context.c |    9 +++++++++
 1 file changed, 9 insertions(+)
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
index fbe7278..288f5de 100644
@@ -380,6 +380,9 @@ void i915_gem_context_reset(struct drm_device

*dev)

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int i;
 
Quoted 6 lines

drivers/gpu/drm/i915/i915_gem_context.c void i915_gem_context_reset(struct drm_device *dev) · line 384

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_context.c +2 -0
+	if (i915.enable_execlists)
+		return;

This will conflict badly with Alistair's patch at a functional level. I'm pretty sure that we want _some_ form of reset for the context state, since the hw didn't just magically load the previously running context. So NACK on this hunk.

OK I'll wait to see the final version of Alistair's patch and decide what to do about this hunk.

Quoted 10 lines

drivers/gpu/drm/i915/i915_gem_context.c void i915_gem_context_reset(struct drm_device · line 386

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +1 -0
+
 	/* Prevent the hardware from restoring the last context (which

hung) on

Quoted 6 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 	 * the next switch */
 	for (i = 0; i < I915_NUM_RINGS; i++) { @@ -514,6 +517,9 @@ int

i915_gem_context_enable(struct drm_i915_private *dev_priv)

drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 		ppgtt->enable(ppgtt);
 	}
Quoted 7 lines
Quoted 5 lines

drivers/gpu/drm/i915/i915_gem_context.c

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_context.c +2 -0
+	if (i915.enable_execlists)
+		return 0;

Again this conflicts with Alistair's patch. Furthermore it looks redudant since you no-op out i915_switch_context separately.

I don't think this is a conflict. Doesn't Alistair's change here just involve writing PDPs for full PPGTT? We don't want to do that in lrc mode.

Oh, just context conflict since Alistair's patch removes the next line ;-) Also I shuffled some of the ppgtt code right above this around.

Quoted 16 lines
Quoted 8 lines
Quoted 8 lines
drivers/gpu/drm/i915/i915_gem_context.c +1 -0
+
 	/* FIXME: We should make this work, even in reset */
 	if (i915_reset_in_progress(&dev_priv->gpu_error))
 		return 0;
@@ -769,6 +775,9 @@ int i915_switch_context(struct intel_engine_cs
 *ring,  {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 
Quoted 8 lines

drivers/gpu/drm/i915/i915_gem_context.c int i915_switch_context(struct intel_engine_cs · line 779

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_context.c +2 -0
+	if (i915.enable_execlists)
+		return 0;

I've hoped we don't need this with the legacy ringbuffer cmdsubmission fuly split out. If there are other paths (resume, gpu reset) where this comes into play then I guess we need to look at where the best place is to make this call. So until this comes with a bit a better justification I'll punt on this for now. -Daniel

Quoted 5 lines

Yes, the command submission lrc path doesn't call this but other codepaths do. If we keep the check in context_enable() the only remaining call I see is in i915_gpu_idle(). I don't mind if the check is done there but perhaps a WARN_ON should then be added into switch_context() because we don't want to be putting illegal MI_SET_CONTEXT commands into the ring.

Yeah, that sounds like a plan. There's still a bit of confusion around the ctx reset in Alistairs patch but unrelated to the code bits we've discussed here. So when you resend this revised patch can you please merge Alistair's patch into your baseline to avoid conflicts.

Thanks, Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#33 lore raw

PATCH 1/1 drm/i915/bdw: Render moot context reset and switch with Execlists

In reply to Thomas Daniel

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enable_execlists instead.

v3: Rebased. Corrected a typo in comment for i915_switch_context and added a comment that it should not be called in execlist mode. Added WARN_ON if i915_switch_context is called in execlist mode. Moved check for execlist mode out of i915_switch_context and into callers. Added comment in context_reset explaining why nothing is done in execlist mode.

---
 drivers/gpu/drm/i915/i915_gem.c         |    8 +++++---
 drivers/gpu/drm/i915/i915_gem_context.c |   16 +++++++++++++++-
 2 files changed, 20 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/i915_gem.c +5 -3
index cb9310b..954a5f9 100644
@@ -2981,9 +2981,11 @@ int i915_gpu_idle(struct drm_device *dev)
 
 	/* Flush everything onto the inactive list. */
 	for_each_ring(ring, dev_priv, i) {
-		ret = i915_switch_context(ring, ring->default_context);
-		if (ret)
-			return ret;
+		if (!i915.enable_execlists) {
+			ret = i915_switch_context(ring, ring->default_context);
+			if (ret)
+				return ret;
+		}
 
 		ret = intel_ring_idle(ring);
 		if (ret)
drivers/gpu/drm/i915/i915_gem_context.c +15 -1
index 0fdb357..3face51 100644
@@ -289,6 +289,12 @@ void i915_gem_context_reset(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int i;
 
+	/* In execlists mode we will unreference the context when the execlist
+	 * queue is cleared and the requests destroyed.
+	 */
+	if (i915.enable_execlists)
+		return;
+
 	for (i = 0; i < I915_NUM_RINGS; i++) {
 		struct intel_engine_cs *ring = &dev_priv->ring[i];
 		struct intel_context *lctx = ring->last_context;
@@ -397,6 +403,9 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
 
 	BUG_ON(!dev_priv->ring[RCS].default_context);
 
+	if (i915.enable_execlists)
+		return 0;
+
 	for_each_ring(ring, dev_priv, i) {
 		ret = i915_switch_context(ring, ring->default_context);
 		if (ret)
@@ -637,14 +646,19 @@ unpin_out:
  *
  * The context life cycle is simple. The context refcount is incremented and
  * decremented by 1 and create and destroy. If the context is in use by the GPU,
- * it will have a refoucnt > 1. This allows us to destroy the context abstract
+ * it will have a refcount > 1. This allows us to destroy the context abstract
  * object while letting the normal object tracking destroy the backing BO.
+ *
+ * This function should not be used in execlists mode.  Instead the context is
+ * switched by writing to the ELSP and requests keep a reference to their
+ * context.
  */
 int i915_switch_context(struct intel_engine_cs *ring,
 			struct intel_context *to)
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 
+	WARN_ON(i915.enable_execlists);
 	WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 
 	if (to->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */
Signature · 1 line
1.7.9.5
#34 lore raw

Re: [PATCH] drm/i915/bdw: Render moot context reset and switch with Execlists

Quoted 6 lines · Thomas Daniel

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enable_execlists instead.

Quoted 8 lines

v3: Rebased. Corrected a typo in comment for i915_switch_context and added a comment that it should not be called in execlist mode. Added WARN_ON if i915_switch_context is called in execlist mode. Moved check for execlist mode out of i915_switch_context and into callers. Added comment in context_reset explaining why nothing is done in execlist mode.

No, this is not the way. The requirement is to reduce the number of special cases not increase them. These should be evaluated to be no-ops when execlists is used.
-Chris

Signature · 1 line
Chris Wilson, Intel Open Source Technology Centre
#35 lore raw

Re: [PATCH] drm/i915/bdw: Render moot context reset and switch with Execlists

Quoted 16 lines · Chris Wilson
Quoted 6 lines · Thomas Daniel

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enable_execlists instead.

Quoted 8 lines

v3: Rebased. Corrected a typo in comment for i915_switch_context and added a comment that it should not be called in execlist mode. Added WARN_ON if i915_switch_context is called in execlist mode. Moved check for execlist mode out of i915_switch_context and into callers. Added comment in context_reset explaining why nothing is done in execlist mode.

Quoted 3 lines

No, this is not the way. The requirement is to reduce the number of special cases not increase them. These should be evaluated to be no-ops when execlists is used.

I think it's ok-ish for now. Maybe we need to reconsider when we wire up lrc reclaim - which is the real user of the switch_context in gpu_idle. The problem I have though is that I can't parse the subject of the patch, someone please translate that to simplified English for me. I can do the replacement while applying.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#36 lore raw

Re: [PATCH] drm/i915/bdw: Render moot context reset and switch with Execlists

Quoted 21 lines · Daniel Vetter
Quoted 16 lines · Chris Wilson
Quoted 6 lines · Thomas Daniel

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enable_execlists instead.

Quoted 8 lines

v3: Rebased. Corrected a typo in comment for i915_switch_context and added a comment that it should not be called in execlist mode. Added WARN_ON if i915_switch_context is called in execlist mode. Moved check for execlist mode out of i915_switch_context and into callers. Added comment in context_reset explaining why nothing is done in execlist mode.

Quoted 3 lines

No, this is not the way. The requirement is to reduce the number of special cases not increase them. These should be evaluated to be no-ops when execlists is used.

Quoted 6 lines

I think it's ok-ish for now. Maybe we need to reconsider when we wire up lrc reclaim - which is the real user of the switch_context in gpu_idle. The problem I have though is that I can't parse the subject of the patch, someone please translate that to simplified English for me. I can do the replacement while applying.
-Daniel

"Render moot" usually means something like "make obsolete", not sure about the rest.

#37 lore raw

Re: [PATCH] drm/i915/bdw: Render moot context reset and switch with Execlists

In reply to Daniel Vetter
Quoted 21 lines · Daniel Vetter
Quoted 16 lines · Chris Wilson
Quoted 6 lines · Thomas Daniel

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enable_execlists instead.

Quoted 8 lines

v3: Rebased. Corrected a typo in comment for i915_switch_context and added a comment that it should not be called in execlist mode. Added WARN_ON if i915_switch_context is called in execlist mode. Moved check for execlist mode out of i915_switch_context and into callers. Added comment in context_reset explaining why nothing is done in execlist mode.

Quoted 3 lines

No, this is not the way. The requirement is to reduce the number of special cases not increase them. These should be evaluated to be no-ops when execlists is used.

Quoted 5 lines

I think it's ok-ish for now. Maybe we need to reconsider when we wire up lrc reclaim - which is the real user of the switch_context in gpu_idle. The problem I have though is that I can't parse the subject of the patch, someone please translate that to simplified English for me. I can do the replacement while applying.

No, it is not. execlists is badly designed and this is a further symptom of that.
-Chris

Signature · 1 line
Chris Wilson, Intel Open Source Technology Centre
#38 lore raw

Re: [PATCH] drm/i915/bdw: Render moot context reset and switch with Execlists

Quoted 28 lines · Chris Wilson
Quoted 21 lines · Daniel Vetter
Quoted 16 lines · Chris Wilson
Quoted 6 lines · Thomas Daniel

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enable_execlists instead.

Quoted 8 lines

v3: Rebased. Corrected a typo in comment for i915_switch_context and added a comment that it should not be called in execlist mode. Added WARN_ON if i915_switch_context is called in execlist mode. Moved check for execlist mode out of i915_switch_context and into callers. Added comment in context_reset explaining why nothing is done in execlist mode.

Quoted 3 lines

No, this is not the way. The requirement is to reduce the number of special cases not increase them. These should be evaluated to be no-ops when execlists is used.

Quoted 5 lines

I think it's ok-ish for now. Maybe we need to reconsider when we wire up lrc reclaim - which is the real user of the switch_context in gpu_idle. The problem I have though is that I can't parse the subject of the patch, someone please translate that to simplified English for me. I can do the replacement while applying.

Quoted 4 lines

No, it is not. execlists is badly designed and this is a further symptom of that.
-Chris

Thomas is not available and I am replying on his behalf. Is the following subject is good for this patch?

"Don't execute context reset and switch when using Execlists"

regards
Arun

#39 lore raw

Re: [PATCH] drm/i915/bdw: Render moot context reset and switch with Execlists

Quoted 29 lines · Arun
Quoted 28 lines · Chris Wilson
Quoted 26 lines · Daniel Vetter
Quoted 16 lines · Chris Wilson
Quoted 6 lines · Thomas Daniel

These two functions make no sense in an Logical Ring Context & Execlists world.

v2: We got rid of lrc_enabled and centralized everything in the sanitized i915.enable_execlists instead.

Quoted 8 lines

v3: Rebased. Corrected a typo in comment for i915_switch_context and added a comment that it should not be called in execlist mode. Added WARN_ON if i915_switch_context is called in execlist mode. Moved check for execlist mode out of i915_switch_context and into callers. Added comment in context_reset explaining why nothing is done in execlist mode.

Quoted 3 lines

No, this is not the way. The requirement is to reduce the number of special cases not increase them. These should be evaluated to be no-ops when execlists is used.

I think it's ok-ish for now. Maybe we need to reconsider when we wire up lrc reclaim - which is the real user of the switch_context in gpu_idle. The problem I have though is that I can't parse the subject of the patch, someone please translate that to simplified English for me. I can do the replacement while applying.

Quoted 8 lines
Quoted 4 lines

No, it is not. execlists is badly designed and this is a further symptom of that.
-Chris

Thomas is not available and I am replying on his behalf. Is the following subject is good for this patch?

"Don't execute context reset and switch when using Execlists"

Yeah, I think that's more parseable by mere mortals^W^W non-native speakers. Pulled in.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#40 lore raw

PATCH 12/43 drm/i915/bdw: Don't write PDP in the legacy way when using LRCs

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

This is mostly for correctness so that we know we are running the LR context correctly (this is, the PDPs are contained inside the context object).

v2: Move the check to inside the enable PPGTT function. The switch happens in two places: the legacy context switch (that we won't hit when Execlists are enabled) and the PPGTT enable, which unfortunately we need. This would look much nicer if the ppgtt->enable was part of the ring init, where it logically belongs.

---
 drivers/gpu/drm/i915/i915_gem_gtt.c |    5 +++++
 1 file changed, 5 insertions(+)
drivers/gpu/drm/i915/i915_gem_gtt.c +5 -0
index 5188936..ccd70f5 100644
@@ -852,6 +852,11 @@ static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
 		if (USES_FULL_PPGTT(dev))
 			continue;
 
+		/* In the case of Execlists, we don't want to write the PDPs
+		 * in the legacy way (they live inside the context now) */
+		if (i915.enable_execlists)
+			return 0;
+
 		ret = ppgtt->switch_mm(ppgtt, ring, true);
 		if (ret)
 			goto err_out;
Signature · 1 line
1.7.9.5
#41 lore raw

Re: [PATCH 12/43] drm/i915/bdw: Don't write PDP in the legacy way when using LRCs

Quoted 22 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

This is mostly for correctness so that we know we are running the LR context correctly (this is, the PDPs are contained inside the context object).

v2: Move the check to inside the enable PPGTT function. The switch happens in two places: the legacy context switch (that we won't hit when Execlists are enabled) and the PPGTT enable, which unfortunately we need. This would look much nicer if the ppgtt->enable was part of the ring init, where it logically belongs.

---
 drivers/gpu/drm/i915/i915_gem_gtt.c |    5 +++++
 1 file changed, 5 insertions(+)
drivers/gpu/drm/i915/i915_gem_gtt.c +0 -0
index 5188936..ccd70f5 100644

drivers/gpu/drm/i915/i915_gem_gtt.c static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) · line 858

Quoted 7 lines
drivers/gpu/drm/i915/i915_gem_gtt.c +4 -0
@@ -852,6 +852,11 @@ static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
 		if (USES_FULL_PPGTT(dev))
 			continue;
 
+		/* In the case of Execlists, we don't want to write the PDPs
+		 * in the legacy way (they live inside the context now) */
+		if (i915.enable_execlists)
+			return 0;

This looks like it should be a continue to enable PPGTT on more rings then the render ring?

Signature · 1 line
Damien
#42 lore raw

PATCH 12/43 drm/i915/bdw: Don't write PDP in the legacy way when using LRCs

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

This is mostly for correctness so that we know we are running the LR context correctly (this is, the PDPs are contained inside the context object).

v2: Move the check to inside the enable PPGTT function. The switch happens in two places: the legacy context switch (that we won't hit when Execlists are enabled) and the PPGTT enable, which unfortunately we need. This would look much nicer if the ppgtt->enable was part of the ring init, where it logically belongs.

v3: Move the check to the start of the enable PPGTT function. None of the legacy PPGTT enabling is required when using LRCs as the PPGTT is enabled in the context descriptor and the PDPs are written in the LRC.

---
 drivers/gpu/drm/i915/i915_gem_gtt.c |    5 +++++
 1 file changed, 5 insertions(+)
drivers/gpu/drm/i915/i915_gem_gtt.c +5 -0
index 5188936..cfbf272 100644
@@ -843,6 +843,11 @@ static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
 	struct intel_engine_cs *ring;
 	int j, ret;
 
+	/* In the case of Execlists, we don't want to write the PDPs
+	 * in the legacy way (they live inside the context now) */
+	if (i915.enable_execlists)
+		return 0;
+
 	for_each_ring(ring, dev_priv, j) {
 		I915_WRITE(RING_MODE_GEN7(ring),
 			   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
Signature · 1 line
1.7.9.5
Reviewed-by on v1 12/43
#43 lore raw

Re: [PATCH 12/43] drm/i915/bdw: Don't write PDP in the legacy way when using LRCs

Quoted 12 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

This is mostly for correctness so that we know we are running the LR context correctly (this is, the PDPs are contained inside the context object).

v2: Move the check to inside the enable PPGTT function. The switch happens in two places: the legacy context switch (that we won't hit when Execlists are enabled) and the PPGTT enable, which unfortunately we need. This would look much nicer if the ppgtt->enable was part of the ring init, where it logically belongs.

Quoted 7 lines

v3: Move the check to the start of the enable PPGTT function. None of the legacy PPGTT enabling is required when using LRCs as the PPGTT is enabled in the context descriptor and the PDPs are written in the LRC.

Signature · 1 line
Damien
Quoted 27 lines
---
 drivers/gpu/drm/i915/i915_gem_gtt.c |    5 +++++
 1 file changed, 5 insertions(+)
drivers/gpu/drm/i915/i915_gem_gtt.c +5 -0
index 5188936..cfbf272 100644
@@ -843,6 +843,11 @@ static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
 	struct intel_engine_cs *ring;
 	int j, ret;
 
+	/* In the case of Execlists, we don't want to write the PDPs
+	 * in the legacy way (they live inside the context now) */
+	if (i915.enable_execlists)
+		return 0;
+
 	for_each_ring(ring, dev_priv, j) {
 		I915_WRITE(RING_MODE_GEN7(ring),
 			   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#44 lore raw

Re: [PATCH 12/43] drm/i915/bdw: Don't write PDP in the legacy way when using LRCs

In reply to Thomas Daniel
Quoted 28 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

This is mostly for correctness so that we know we are running the LR context correctly (this is, the PDPs are contained inside the context object).

v2: Move the check to inside the enable PPGTT function. The switch happens in two places: the legacy context switch (that we won't hit when Execlists are enabled) and the PPGTT enable, which unfortunately we need. This would look much nicer if the ppgtt->enable was part of the ring init, where it logically belongs.

v3: Move the check to the start of the enable PPGTT function. None of the legacy PPGTT enabling is required when using LRCs as the PPGTT is enabled in the context descriptor and the PDPs are written in the LRC.

---
 drivers/gpu/drm/i915/i915_gem_gtt.c |    5 +++++
 1 file changed, 5 insertions(+)
drivers/gpu/drm/i915/i915_gem_gtt.c +0 -0
index 5188936..cfbf272 100644

drivers/gpu/drm/i915/i915_gem_gtt.c static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt) · line 846

Quoted 4 lines
drivers/gpu/drm/i915/i915_gem_gtt.c +1 -0
@@ -843,6 +843,11 @@ static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
 	struct intel_engine_cs *ring;
 	int j, ret;
 
+	/* In the case of Execlists, we don't want to write the PDPs

This comment is misleading since you now also disable the ppgtt enable bit setting. Not that the code disabled in v2 of this patch is for aliasing ppgtt mode only anyway, so irrelevant for execlist mode. Aside: A few patches from myself will clear this up a bit better.

As-is this just looks confusing, so I'll punt for now. -Daniel

Quoted 14 lines
drivers/gpu/drm/i915/i915_gem_gtt.c +4 -0
+	 * in the legacy way (they live inside the context now) */
+	if (i915.enable_execlists)
+		return 0;
+
 	for_each_ring(ring, dev_priv, j) {
 		I915_WRITE(RING_MODE_GEN7(ring),
 			   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#45 lore raw

PATCH 1/1 drm/i915/bdw: Don't write PDP in the legacy way when using LRCs

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

This is mostly for correctness so that we know we are running the LR context correctly (this is, the PDPs are contained inside the context object).

v2: Move the check to inside the enable PPGTT function. The switch happens in two places: the legacy context switch (that we won't hit when Execlists are enabled) and the PPGTT enable, which unfortunately we need. This would look much nicer if the ppgtt->enable was part of the ring init, where it logically belongs.

v3: Move the check to the start of the enable PPGTT function. None of the legacy PPGTT enabling is required when using LRCs as the PPGTT is enabled in the context descriptor and the PDPs are written in the LRC.

v4: Clarify comment based on review feedback.

---
 drivers/gpu/drm/i915/i915_gem_gtt.c |    6 ++++++
 1 file changed, 6 insertions(+)
drivers/gpu/drm/i915/i915_gem_gtt.c +6 -0
index 5188936..2966b53 100644
@@ -843,6 +843,12 @@ static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
 	struct intel_engine_cs *ring;
 	int j, ret;
 
+	/* In the case of execlists, PPGTT is enabled by the context descriptor
+	 * and the PDPs are contained within the context itself.  We don't
+	 * need to do anything here. */
+	if (i915.enable_execlists)
+		return 0;
+
 	for_each_ring(ring, dev_priv, j) {
 		I915_WRITE(RING_MODE_GEN7(ring),
 			   _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
Signature · 1 line
1.7.9.5
#46 lore raw

PATCH 13/43 drm/i915: Abstract the legacy workload submission mechanism away

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

As suggested by Daniel Vetter. The idea, in subsequent patches, is to provide an alternative to these vfuncs for the Execlists submission mechanism.

v2: Splitted into two and reordered to illustrate our intentions, instead of showing it off. Also, remove the add_request vfunc and added the stop_ring one.

---
 drivers/gpu/drm/i915/i915_drv.h            |   24 ++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_gem.c            |   15 +++++++++++----
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |   20 ++++++++++----------
 3 files changed, 45 insertions(+), 14 deletions(-)
drivers/gpu/drm/i915/i915_drv.h +24 -0
index ff2c373..1caed52 100644
@@ -1617,6 +1617,21 @@ struct drm_i915_private {
 	/* Old ums support infrastructure, same warning applies. */
 	struct i915_ums_state ums;
 
+	/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
+	struct {
+		int (*do_execbuf) (struct drm_device *dev, struct drm_file *file,
+				   struct intel_engine_cs *ring,
+				   struct intel_context *ctx,
+				   struct drm_i915_gem_execbuffer2 *args,
+				   struct list_head *vmas,
+				   struct drm_i915_gem_object *batch_obj,
+				   u64 exec_start, u32 flags);
+		int (*init_rings) (struct drm_device *dev);
+		void (*cleanup_ring) (struct intel_engine_cs *ring);
+		void (*stop_ring) (struct intel_engine_cs *ring);
+		bool (*is_ring_initialized) (struct intel_engine_cs *ring);
+	} gt;
+
 	/*
 	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
 	 * will be rejected. Instead look for a better place.
@@ -2224,6 +2239,14 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 			      struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *file_priv);
+int i915_gem_ringbuffer_submission(struct drm_device *dev,
+				   struct drm_file *file,
+				   struct intel_engine_cs *ring,
+				   struct intel_context *ctx,
+				   struct drm_i915_gem_execbuffer2 *args,
+				   struct list_head *vmas,
+				   struct drm_i915_gem_object *batch_obj,
+				   u64 exec_start, u32 flags);
 int i915_gem_execbuffer(struct drm_device *dev, void *data,
 			struct drm_file *file_priv);
 int i915_gem_execbuffer2(struct drm_device *dev, void *data,
@@ -2376,6 +2399,7 @@ void i915_gem_reset(struct drm_device *dev);
 bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_init(struct drm_device *dev);
+int i915_gem_init_rings(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
 int i915_gem_l3_remap(struct intel_engine_cs *ring, int slice);
 void i915_gem_init_swizzling(struct drm_device *dev);
drivers/gpu/drm/i915/i915_gem.c +11 -4
index d8bf4fa..6544286 100644
@@ -4518,7 +4518,7 @@ i915_gem_stop_ringbuffers(struct drm_device *dev)
 	int i;
 
 	for_each_ring(ring, dev_priv, i)
-		intel_stop_ring_buffer(ring);
+		dev_priv->gt.stop_ring(ring);
 }
 
 int
@@ -4635,7 +4635,7 @@ intel_enable_blt(struct drm_device *dev)
 	return true;
 }
 
-static int i915_gem_init_rings(struct drm_device *dev)
+int i915_gem_init_rings(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
@@ -4718,7 +4718,7 @@ i915_gem_init_hw(struct drm_device *dev)
 
 	i915_gem_init_swizzling(dev);
 
-	ret = i915_gem_init_rings(dev);
+	ret = dev_priv->gt.init_rings(dev);
 	if (ret)
 		return ret;
 
@@ -4759,6 +4759,13 @@ int i915_gem_init(struct drm_device *dev)
 			DRM_DEBUG_DRIVER("allow wake ack timed out\n");
 	}
 
+	if (!i915.enable_execlists) {
+		dev_priv->gt.do_execbuf = i915_gem_ringbuffer_submission;
+		dev_priv->gt.init_rings = i915_gem_init_rings;
+		dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer;
+		dev_priv->gt.stop_ring = intel_stop_ring_buffer;
+	}
+
 	i915_gem_init_userptr(dev);
 	i915_gem_init_global_gtt(dev);
 
@@ -4794,7 +4801,7 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
 	int i;
 
 	for_each_ring(ring, dev_priv, i)
-		intel_cleanup_ring_buffer(ring);
+		dev_priv->gt.cleanup_ring(ring);
 }
 
 int
drivers/gpu/drm/i915/i915_gem_execbuffer.c +10 -10
index 4e9b387..8c63d79 100644
@@ -1034,14 +1034,14 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
 	return 0;
 }
 
-static int
-legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
-			     struct intel_engine_cs *ring,
-			     struct intel_context *ctx,
-			     struct drm_i915_gem_execbuffer2 *args,
-			     struct list_head *vmas,
-			     struct drm_i915_gem_object *batch_obj,
-			     u64 exec_start, u32 flags)
+int
+i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
+			       struct intel_engine_cs *ring,
+			       struct intel_context *ctx,
+			       struct drm_i915_gem_execbuffer2 *args,
+			       struct list_head *vmas,
+			       struct drm_i915_gem_object *batch_obj,
+			       u64 exec_start, u32 flags)
 {
 	struct drm_clip_rect *cliprects = NULL;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1408,8 +1408,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 	else
 		exec_start += i915_gem_obj_offset(batch_obj, vm);
 
-	ret = legacy_ringbuffer_submission(dev, file, ring, ctx,
-			args, &eb->vmas, batch_obj, exec_start, flags);
+	ret = dev_priv->gt.do_execbuf(dev, file, ring, ctx, args,
+			&eb->vmas, batch_obj, exec_start, flags);
 	if (ret)
 		goto err;
 
Signature · 1 line
1.7.9.5
#47 lore raw

Re: [PATCH 13/43] drm/i915: Abstract the legacy workload submission mechanism away

Quoted 27 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

As suggested by Daniel Vetter. The idea, in subsequent patches, is to provide an alternative to these vfuncs for the Execlists submission mechanism.

v2: Splitted into two and reordered to illustrate our intentions, instead of showing it off. Also, remove the add_request vfunc and added the stop_ring one.

---
 drivers/gpu/drm/i915/i915_drv.h            |   24 ++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_gem.c            |   15 +++++++++++----
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |   20 ++++++++++----------
 3 files changed, 45 insertions(+), 14 deletions(-)
drivers/gpu/drm/i915/i915_drv.h +2 -0
index ff2c373..1caed52 100644
@@ -1617,6 +1617,21 @@ struct drm_i915_private {
 	/* Old ums support infrastructure, same warning applies. */
 	struct i915_ums_state ums;
 
+	/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
+	struct {

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1631

Quoted 10 lines
drivers/gpu/drm/i915/i915_drv.h +10 -0
+		int (*do_execbuf) (struct drm_device *dev, struct drm_file *file,
+				   struct intel_engine_cs *ring,
+				   struct intel_context *ctx,
+				   struct drm_i915_gem_execbuffer2 *args,
+				   struct list_head *vmas,
+				   struct drm_i915_gem_object *batch_obj,
+				   u64 exec_start, u32 flags);
+		int (*init_rings) (struct drm_device *dev);
+		void (*cleanup_ring) (struct intel_engine_cs *ring);
+		void (*stop_ring) (struct intel_engine_cs *ring);

My rule of thumb is that with just one caller it's probably better to not have a vtable - just makes it harder to follow the code flow.

Usually (with non-borked code design at least) init/teardown functions have only one caller, so there's a good chance I'll ask you to remove them again.

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1632

Quoted 1 line
drivers/gpu/drm/i915/i915_drv.h +1 -0
+		bool (*is_ring_initialized) (struct intel_engine_cs *ring);

This one is unused and I didn't really like the taste of it. So I killed it.
-Daniel

Quoted 127 lines
drivers/gpu/drm/i915/i915_drv.h +11 -0
+	} gt;
+
 	/*
 	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
 	 * will be rejected. Instead look for a better place.
@@ -2224,6 +2239,14 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 			      struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *file_priv);
+int i915_gem_ringbuffer_submission(struct drm_device *dev,
+				   struct drm_file *file,
+				   struct intel_engine_cs *ring,
+				   struct intel_context *ctx,
+				   struct drm_i915_gem_execbuffer2 *args,
+				   struct list_head *vmas,
+				   struct drm_i915_gem_object *batch_obj,
+				   u64 exec_start, u32 flags);
 int i915_gem_execbuffer(struct drm_device *dev, void *data,
 			struct drm_file *file_priv);
 int i915_gem_execbuffer2(struct drm_device *dev, void *data,
@@ -2376,6 +2399,7 @@ void i915_gem_reset(struct drm_device *dev);
 bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_init(struct drm_device *dev);
+int i915_gem_init_rings(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
 int i915_gem_l3_remap(struct intel_engine_cs *ring, int slice);
 void i915_gem_init_swizzling(struct drm_device *dev);
drivers/gpu/drm/i915/i915_gem.c +11 -4
index d8bf4fa..6544286 100644
@@ -4518,7 +4518,7 @@ i915_gem_stop_ringbuffers(struct drm_device *dev)
 	int i;
 
 	for_each_ring(ring, dev_priv, i)
-		intel_stop_ring_buffer(ring);
+		dev_priv->gt.stop_ring(ring);
 }
 
 int
@@ -4635,7 +4635,7 @@ intel_enable_blt(struct drm_device *dev)
 	return true;
 }
 
-static int i915_gem_init_rings(struct drm_device *dev)
+int i915_gem_init_rings(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
@@ -4718,7 +4718,7 @@ i915_gem_init_hw(struct drm_device *dev)
 
 	i915_gem_init_swizzling(dev);
 
-	ret = i915_gem_init_rings(dev);
+	ret = dev_priv->gt.init_rings(dev);
 	if (ret)
 		return ret;
 
@@ -4759,6 +4759,13 @@ int i915_gem_init(struct drm_device *dev)
 			DRM_DEBUG_DRIVER("allow wake ack timed out\n");
 	}
 
+	if (!i915.enable_execlists) {
+		dev_priv->gt.do_execbuf = i915_gem_ringbuffer_submission;
+		dev_priv->gt.init_rings = i915_gem_init_rings;
+		dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer;
+		dev_priv->gt.stop_ring = intel_stop_ring_buffer;
+	}
+
 	i915_gem_init_userptr(dev);
 	i915_gem_init_global_gtt(dev);
 
@@ -4794,7 +4801,7 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
 	int i;
 
 	for_each_ring(ring, dev_priv, i)
-		intel_cleanup_ring_buffer(ring);
+		dev_priv->gt.cleanup_ring(ring);
 }
 
 int
drivers/gpu/drm/i915/i915_gem_execbuffer.c +10 -10
index 4e9b387..8c63d79 100644
@@ -1034,14 +1034,14 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
 	return 0;
 }
 
-static int
-legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
-			     struct intel_engine_cs *ring,
-			     struct intel_context *ctx,
-			     struct drm_i915_gem_execbuffer2 *args,
-			     struct list_head *vmas,
-			     struct drm_i915_gem_object *batch_obj,
-			     u64 exec_start, u32 flags)
+int
+i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
+			       struct intel_engine_cs *ring,
+			       struct intel_context *ctx,
+			       struct drm_i915_gem_execbuffer2 *args,
+			       struct list_head *vmas,
+			       struct drm_i915_gem_object *batch_obj,
+			       u64 exec_start, u32 flags)
 {
 	struct drm_clip_rect *cliprects = NULL;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1408,8 +1408,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 	else
 		exec_start += i915_gem_obj_offset(batch_obj, vm);
 
-	ret = legacy_ringbuffer_submission(dev, file, ring, ctx,
-			args, &eb->vmas, batch_obj, exec_start, flags);
+	ret = dev_priv->gt.do_execbuf(dev, file, ring, ctx, args,
+			&eb->vmas, batch_obj, exec_start, flags);
 	if (ret)
 		goto err;
 
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#48 lore raw

Re: [PATCH 13/43] drm/i915: Abstract the legacy workload submission mechanism away

Quoted 42 lines · Daniel Vetter
Quoted 27 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

As suggested by Daniel Vetter. The idea, in subsequent patches, is to provide an alternative to these vfuncs for the Execlists submission mechanism.

v2: Splitted into two and reordered to illustrate our intentions, instead of showing it off. Also, remove the add_request vfunc and added the stop_ring one.

---
 drivers/gpu/drm/i915/i915_drv.h            |   24 ++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_gem.c            |   15 +++++++++++----
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |   20 ++++++++++----------
 3 files changed, 45 insertions(+), 14 deletions(-)
drivers/gpu/drm/i915/i915_drv.h +2 -0
index ff2c373..1caed52 100644
@@ -1617,6 +1617,21 @@ struct drm_i915_private {
 	/* Old ums support infrastructure, same warning applies. */
 	struct i915_ums_state ums;
 
+	/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
+	struct {

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1631

Quoted 10 lines
drivers/gpu/drm/i915/i915_drv.h +10 -0
+		int (*do_execbuf) (struct drm_device *dev, struct drm_file *file,
+				   struct intel_engine_cs *ring,
+				   struct intel_context *ctx,
+				   struct drm_i915_gem_execbuffer2 *args,
+				   struct list_head *vmas,
+				   struct drm_i915_gem_object *batch_obj,
+				   u64 exec_start, u32 flags);
+		int (*init_rings) (struct drm_device *dev);
+		void (*cleanup_ring) (struct intel_engine_cs *ring);
+		void (*stop_ring) (struct intel_engine_cs *ring);

My rule of thumb is that with just one caller it's probably better to not have a vtable - just makes it harder to follow the code flow.

Quoted 3 lines

Usually (with non-borked code design at least) init/teardown functions have only one caller, so there's a good chance I'll ask you to remove them again.

Also checkpatch (and my eyes!) where unhappy about the space you've put between ) and (. Fixed that too.
-Daniel

Quoted 139 lines

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1632

Quoted 2 lines
drivers/gpu/drm/i915/i915_drv.h +1 -0
+		bool (*is_ring_initialized) (struct intel_engine_cs *ring);

This one is unused and I didn't really like the taste of it. So I killed it.
-Daniel

Quoted 127 lines
drivers/gpu/drm/i915/i915_drv.h +11 -0
+	} gt;
+
 	/*
 	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
 	 * will be rejected. Instead look for a better place.
@@ -2224,6 +2239,14 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 			      struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *file_priv);
+int i915_gem_ringbuffer_submission(struct drm_device *dev,
+				   struct drm_file *file,
+				   struct intel_engine_cs *ring,
+				   struct intel_context *ctx,
+				   struct drm_i915_gem_execbuffer2 *args,
+				   struct list_head *vmas,
+				   struct drm_i915_gem_object *batch_obj,
+				   u64 exec_start, u32 flags);
 int i915_gem_execbuffer(struct drm_device *dev, void *data,
 			struct drm_file *file_priv);
 int i915_gem_execbuffer2(struct drm_device *dev, void *data,
@@ -2376,6 +2399,7 @@ void i915_gem_reset(struct drm_device *dev);
 bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_init(struct drm_device *dev);
+int i915_gem_init_rings(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
 int i915_gem_l3_remap(struct intel_engine_cs *ring, int slice);
 void i915_gem_init_swizzling(struct drm_device *dev);
drivers/gpu/drm/i915/i915_gem.c +11 -4
index d8bf4fa..6544286 100644
@@ -4518,7 +4518,7 @@ i915_gem_stop_ringbuffers(struct drm_device *dev)
 	int i;
 
 	for_each_ring(ring, dev_priv, i)
-		intel_stop_ring_buffer(ring);
+		dev_priv->gt.stop_ring(ring);
 }
 
 int
@@ -4635,7 +4635,7 @@ intel_enable_blt(struct drm_device *dev)
 	return true;
 }
 
-static int i915_gem_init_rings(struct drm_device *dev)
+int i915_gem_init_rings(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
@@ -4718,7 +4718,7 @@ i915_gem_init_hw(struct drm_device *dev)
 
 	i915_gem_init_swizzling(dev);
 
-	ret = i915_gem_init_rings(dev);
+	ret = dev_priv->gt.init_rings(dev);
 	if (ret)
 		return ret;
 
@@ -4759,6 +4759,13 @@ int i915_gem_init(struct drm_device *dev)
 			DRM_DEBUG_DRIVER("allow wake ack timed out\n");
 	}
 
+	if (!i915.enable_execlists) {
+		dev_priv->gt.do_execbuf = i915_gem_ringbuffer_submission;
+		dev_priv->gt.init_rings = i915_gem_init_rings;
+		dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer;
+		dev_priv->gt.stop_ring = intel_stop_ring_buffer;
+	}
+
 	i915_gem_init_userptr(dev);
 	i915_gem_init_global_gtt(dev);
 
@@ -4794,7 +4801,7 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
 	int i;
 
 	for_each_ring(ring, dev_priv, i)
-		intel_cleanup_ring_buffer(ring);
+		dev_priv->gt.cleanup_ring(ring);
 }
 
 int
drivers/gpu/drm/i915/i915_gem_execbuffer.c +10 -10
index 4e9b387..8c63d79 100644
@@ -1034,14 +1034,14 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
 	return 0;
 }
 
-static int
-legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
-			     struct intel_engine_cs *ring,
-			     struct intel_context *ctx,
-			     struct drm_i915_gem_execbuffer2 *args,
-			     struct list_head *vmas,
-			     struct drm_i915_gem_object *batch_obj,
-			     u64 exec_start, u32 flags)
+int
+i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
+			       struct intel_engine_cs *ring,
+			       struct intel_context *ctx,
+			       struct drm_i915_gem_execbuffer2 *args,
+			       struct list_head *vmas,
+			       struct drm_i915_gem_object *batch_obj,
+			       u64 exec_start, u32 flags)
 {
 	struct drm_clip_rect *cliprects = NULL;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1408,8 +1408,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 	else
 		exec_start += i915_gem_obj_offset(batch_obj, vm);
 
-	ret = legacy_ringbuffer_submission(dev, file, ring, ctx,
-			args, &eb->vmas, batch_obj, exec_start, flags);
+	ret = dev_priv->gt.do_execbuf(dev, file, ring, ctx, args,
+			&eb->vmas, batch_obj, exec_start, flags);
 	if (ret)
 		goto err;
 
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#49 lore raw

Re: [PATCH 13/43] drm/i915: Abstract the legacy workload submission mechanism away

In reply to Thomas Daniel

drivers/gpu/drm/i915/i915_gem_execbuffer.c i915_gem_do_execbuffer(struct drm_device *dev, void *data, · line 1412

Quoted 8 lines · Thomas Daniel
drivers/gpu/drm/i915/i915_gem_execbuffer.c +2 -2
@@ -1408,8 +1408,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 	else
 		exec_start += i915_gem_obj_offset(batch_obj, vm);
 
-	ret = legacy_ringbuffer_submission(dev, file, ring, ctx,
-			args, &eb->vmas, batch_obj, exec_start, flags);
+	ret = dev_priv->gt.do_execbuf(dev, file, ring, ctx, args,
+			&eb->vmas, batch_obj, exec_start, flags);

Also misaligned and too long line here. Fixed, too. -Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#50 lore raw

Re: [PATCH 13/43] drm/i915: Abstract the legacy workload submission mechanism away

In reply to Thomas Daniel
Quoted 28 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

As suggested by Daniel Vetter. The idea, in subsequent patches, is to provide an alternative to these vfuncs for the Execlists submission mechanism.

v2: Splitted into two and reordered to illustrate our intentions, instead of showing it off. Also, remove the add_request vfunc and added the stop_ring one.

---
 drivers/gpu/drm/i915/i915_drv.h            |   24 ++++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_gem.c            |   15 +++++++++++----
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |   20 ++++++++++----------
 3 files changed, 45 insertions(+), 14 deletions(-)
drivers/gpu/drm/i915/i915_drv.h +3 -0
index ff2c373..1caed52 100644
@@ -1617,6 +1617,21 @@ struct drm_i915_private {
 	/* Old ums support infrastructure, same warning applies. */
 	struct i915_ums_state ums;
 
+	/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
+	struct {
+		int (*do_execbuf) (struct drm_device *dev, struct drm_file *file,

drivers/gpu/drm/i915/i915_drv.h struct drm_i915_private { · line 1632

Quoted 10 lines
drivers/gpu/drm/i915/i915_drv.h +10 -0
+				   struct intel_engine_cs *ring,
+				   struct intel_context *ctx,
+				   struct drm_i915_gem_execbuffer2 *args,
+				   struct list_head *vmas,
+				   struct drm_i915_gem_object *batch_obj,
+				   u64 exec_start, u32 flags);
+		int (*init_rings) (struct drm_device *dev);
+		void (*cleanup_ring) (struct intel_engine_cs *ring);
+		void (*stop_ring) (struct intel_engine_cs *ring);
+		bool (*is_ring_initialized) (struct intel_engine_cs *ring);

Aside: ring here is a bit a misnomer, we talk about the engines. I guess at the end of all this we should throw a few patches on top to name things correctly with ring/engine where appropriate.
-Daniel

Quoted 127 lines
drivers/gpu/drm/i915/i915_drv.h +11 -0
+	} gt;
+
 	/*
 	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
 	 * will be rejected. Instead look for a better place.
@@ -2224,6 +2239,14 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 			      struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *file_priv);
+int i915_gem_ringbuffer_submission(struct drm_device *dev,
+				   struct drm_file *file,
+				   struct intel_engine_cs *ring,
+				   struct intel_context *ctx,
+				   struct drm_i915_gem_execbuffer2 *args,
+				   struct list_head *vmas,
+				   struct drm_i915_gem_object *batch_obj,
+				   u64 exec_start, u32 flags);
 int i915_gem_execbuffer(struct drm_device *dev, void *data,
 			struct drm_file *file_priv);
 int i915_gem_execbuffer2(struct drm_device *dev, void *data,
@@ -2376,6 +2399,7 @@ void i915_gem_reset(struct drm_device *dev);
 bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_init(struct drm_device *dev);
+int i915_gem_init_rings(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
 int i915_gem_l3_remap(struct intel_engine_cs *ring, int slice);
 void i915_gem_init_swizzling(struct drm_device *dev);
drivers/gpu/drm/i915/i915_gem.c +11 -4
index d8bf4fa..6544286 100644
@@ -4518,7 +4518,7 @@ i915_gem_stop_ringbuffers(struct drm_device *dev)
 	int i;
 
 	for_each_ring(ring, dev_priv, i)
-		intel_stop_ring_buffer(ring);
+		dev_priv->gt.stop_ring(ring);
 }
 
 int
@@ -4635,7 +4635,7 @@ intel_enable_blt(struct drm_device *dev)
 	return true;
 }
 
-static int i915_gem_init_rings(struct drm_device *dev)
+int i915_gem_init_rings(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
@@ -4718,7 +4718,7 @@ i915_gem_init_hw(struct drm_device *dev)
 
 	i915_gem_init_swizzling(dev);
 
-	ret = i915_gem_init_rings(dev);
+	ret = dev_priv->gt.init_rings(dev);
 	if (ret)
 		return ret;
 
@@ -4759,6 +4759,13 @@ int i915_gem_init(struct drm_device *dev)
 			DRM_DEBUG_DRIVER("allow wake ack timed out\n");
 	}
 
+	if (!i915.enable_execlists) {
+		dev_priv->gt.do_execbuf = i915_gem_ringbuffer_submission;
+		dev_priv->gt.init_rings = i915_gem_init_rings;
+		dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer;
+		dev_priv->gt.stop_ring = intel_stop_ring_buffer;
+	}
+
 	i915_gem_init_userptr(dev);
 	i915_gem_init_global_gtt(dev);
 
@@ -4794,7 +4801,7 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
 	int i;
 
 	for_each_ring(ring, dev_priv, i)
-		intel_cleanup_ring_buffer(ring);
+		dev_priv->gt.cleanup_ring(ring);
 }
 
 int
drivers/gpu/drm/i915/i915_gem_execbuffer.c +10 -10
index 4e9b387..8c63d79 100644
@@ -1034,14 +1034,14 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
 	return 0;
 }
 
-static int
-legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
-			     struct intel_engine_cs *ring,
-			     struct intel_context *ctx,
-			     struct drm_i915_gem_execbuffer2 *args,
-			     struct list_head *vmas,
-			     struct drm_i915_gem_object *batch_obj,
-			     u64 exec_start, u32 flags)
+int
+i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
+			       struct intel_engine_cs *ring,
+			       struct intel_context *ctx,
+			       struct drm_i915_gem_execbuffer2 *args,
+			       struct list_head *vmas,
+			       struct drm_i915_gem_object *batch_obj,
+			       u64 exec_start, u32 flags)
 {
 	struct drm_clip_rect *cliprects = NULL;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1408,8 +1408,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 	else
 		exec_start += i915_gem_obj_offset(batch_obj, vm);
 
-	ret = legacy_ringbuffer_submission(dev, file, ring, ctx,
-			args, &eb->vmas, batch_obj, exec_start, flags);
+	ret = dev_priv->gt.do_execbuf(dev, file, ring, ctx, args,
+			&eb->vmas, batch_obj, exec_start, flags);
 	if (ret)
 		goto err;
 
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#51 lore raw

PATCH 14/43 drm/i915/bdw: Skeleton for the new logical rings submission path

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Execlists are indeed a brave new world with respect to workload submission to the GPU.

In previous version of these series, I have tried to impact the legacy ringbuffer submission path as little as possible (mostly, passing the context around and using the correct ringbuffer when I needed one) but Daniel is afraid (probably with a reason) that these changes and, especially, future ones, will end up breaking older gens.

This commit and some others coming next will try to limit the damage by creating an alternative path for workload submission. The first step is here: laying out a new ring init/fini.

---
 drivers/gpu/drm/i915/i915_gem.c  |    5 ++
 drivers/gpu/drm/i915/intel_lrc.c |  151 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.h |   12 +++
 3 files changed, 168 insertions(+)
drivers/gpu/drm/i915/i915_gem.c +5 -0
index 6544286..9560b40 100644
@@ -4764,6 +4764,11 @@ int i915_gem_init(struct drm_device *dev)
 		dev_priv->gt.init_rings = i915_gem_init_rings;
 		dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer;
 		dev_priv->gt.stop_ring = intel_stop_ring_buffer;
+	} else {
+		dev_priv->gt.do_execbuf = intel_execlists_submission;
+		dev_priv->gt.init_rings = intel_logical_rings_init;
+		dev_priv->gt.cleanup_ring = intel_logical_ring_cleanup;
+		dev_priv->gt.stop_ring = intel_logical_ring_stop;
 	}
 
 	i915_gem_init_userptr(dev);
drivers/gpu/drm/i915/intel_lrc.c +151 -0

157 lines not on this page · raw message

drivers/gpu/drm/i915/intel_lrc.h +12 -0
index 3b93572..bf0eff4 100644
@@ -24,6 +24,11 @@
 #ifndef _INTEL_LRC_H_
 #define _INTEL_LRC_H_
 
+/* Logical Rings */
+void intel_logical_ring_stop(struct intel_engine_cs *ring);
+void intel_logical_ring_cleanup(struct intel_engine_cs *ring);
+int intel_logical_rings_init(struct drm_device *dev);
+
 /* Logical Ring Contexts */
 void intel_lr_context_free(struct intel_context *ctx);
 int intel_lr_context_deferred_create(struct intel_context *ctx,
@@ -31,5 +36,12 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 
 /* Execlists */
 int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);
+int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
+			       struct intel_engine_cs *ring,
+			       struct intel_context *ctx,
+			       struct drm_i915_gem_execbuffer2 *args,
+			       struct list_head *vmas,
+			       struct drm_i915_gem_object *batch_obj,
+			       u64 exec_start, u32 flags);
 
 #endif /* _INTEL_LRC_H_ */
Signature · 1 line
1.7.9.5
#52 lore raw

PATCH 15/43 drm/i915/bdw: Generic logical ring init and cleanup

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Allocate and populate the default LRC for every ring, call gen-specific init/cleanup, init/fini the command parser and set the status page (now inside the LRC object). These are things all engines/rings have in common.

Stopping the ring before cleanup and initializing the seqnos is left as a TODO task (we need more infrastructure in place before we can achieve this).

v2: Check the ringbuffer backing obj for ring_is_initialized, instead of the context backing obj (similar, but not exactly the same).

---
 drivers/gpu/drm/i915/i915_gem_context.c |    4 ---
 drivers/gpu/drm/i915/intel_lrc.c        |   54 +++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_ringbuffer.c |   17 ++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    6 +---
 4 files changed, 70 insertions(+), 11 deletions(-)
drivers/gpu/drm/i915/i915_gem_context.c +0 -4
index 288f5de..9085ff1 100644
@@ -450,10 +450,6 @@ int i915_gem_context_init(struct drm_device *dev)
 
 		/* NB: RCS will hold a ref for all rings */
 		ring->default_context = ctx;
-
-		/* FIXME: we really only want to do this for initialized rings */
-		if (i915.enable_execlists)
-			intel_lr_context_deferred_create(ctx, ring);
 	}
 
 	DRM_DEBUG_DRIVER("%s context support initialized\n",
drivers/gpu/drm/i915/intel_lrc.c +52 -2

70 lines not on this page · raw message

drivers/gpu/drm/i915/intel_ringbuffer.c +17 -0
index 279dda4..20eb1a4 100644
@@ -40,6 +40,23 @@
  */
 #define CACHELINE_BYTES 64
 
+bool
+intel_ring_initialized(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+
+	if (!dev)
+		return false;
+
+	if (i915.enable_execlists) {
+		struct intel_context *dctx = ring->default_context;
+		struct intel_ringbuffer *ringbuf = dctx->engine[ring->id].ringbuf;
+
+		return ringbuf->obj;
+	} else
+		return ring->buffer && ring->buffer->obj;
+}
+
 static inline int __ring_space(int head, int tail, int size)
 {
 	int space = head - (tail + I915_RING_FREE_SPACE);
drivers/gpu/drm/i915/intel_ringbuffer.h +1 -5
index be40788..7203ee2 100644
@@ -288,11 +288,7 @@ struct  intel_engine_cs {
 	u32 (*get_cmd_length_mask)(u32 cmd_header);
 };
 
-static inline bool
-intel_ring_initialized(struct intel_engine_cs *ring)
-{
-	return ring->buffer && ring->buffer->obj;
-}
+bool intel_ring_initialized(struct intel_engine_cs *ring);
 
 static inline unsigned
 intel_ring_flag(struct intel_engine_cs *ring)
Signature · 1 line
1.7.9.5
#53 lore raw

Re: [PATCH 15/43] drm/i915/bdw: Generic logical ring init and cleanup

Quoted 28 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Allocate and populate the default LRC for every ring, call gen-specific init/cleanup, init/fini the command parser and set the status page (now inside the LRC object). These are things all engines/rings have in common.

Stopping the ring before cleanup and initializing the seqnos is left as a TODO task (we need more infrastructure in place before we can achieve this).

v2: Check the ringbuffer backing obj for ring_is_initialized, instead of the context backing obj (similar, but not exactly the same).

---
 drivers/gpu/drm/i915/i915_gem_context.c |    4 ---
 drivers/gpu/drm/i915/intel_lrc.c        |   54 +++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_ringbuffer.c |   17 ++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    6 +---
 4 files changed, 70 insertions(+), 11 deletions(-)
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
index 288f5de..9085ff1 100644

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_init(struct drm_device *dev) · line 456

Quoted 7 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -4
@@ -450,10 +450,6 @@ int i915_gem_context_init(struct drm_device *dev)
 
 		/* NB: RCS will hold a ref for all rings */
 		ring->default_context = ctx;
-
-		/* FIXME: we really only want to do this for initialized rings */
-		if (i915.enable_execlists)
-			intel_lr_context_deferred_create(ctx, ring);

Ah, here we go ;-)

Quoted 93 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 	}
 
 	DRM_DEBUG_DRIVER("%s context support initialized\n",
drivers/gpu/drm/i915/intel_lrc.c +52 -2
index cb56bb8..05b7069 100644
@@ -108,12 +108,60 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring)
 
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
 {
-	/* TODO */
+	if (!intel_ring_initialized(ring))
+		return;
+
+	/* TODO: make sure the ring is stopped */
+	ring->preallocated_lazy_request = NULL;
+	ring->outstanding_lazy_seqno = 0;
+
+	if (ring->cleanup)
+		ring->cleanup(ring);
+
+	i915_cmd_parser_fini_ring(ring);
+
+	if (ring->status_page.obj) {
+		kunmap(sg_page(ring->status_page.obj->pages->sgl));
+		ring->status_page.obj = NULL;
+	}
 }
 
 static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring)
 {
-	/* TODO */
+	int ret;
+	struct intel_context *dctx = ring->default_context;
+	struct drm_i915_gem_object *dctx_obj;
+
+	/* Intentionally left blank. */
+	ring->buffer = NULL;
+
+	ring->dev = dev;
+	INIT_LIST_HEAD(&ring->active_list);
+	INIT_LIST_HEAD(&ring->request_list);
+	init_waitqueue_head(&ring->irq_queue);
+
+	ret = intel_lr_context_deferred_create(dctx, ring);
+	if (ret)
+		return ret;
+
+	/* The status page is offset 0 from the context object in LRCs. */
+	dctx_obj = dctx->engine[ring->id].state;
+	ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(dctx_obj);
+	ring->status_page.page_addr = kmap(sg_page(dctx_obj->pages->sgl));
+	if (ring->status_page.page_addr == NULL)
+		return -ENOMEM;
+	ring->status_page.obj = dctx_obj;
+
+	ret = i915_cmd_parser_init_ring(ring);
+	if (ret)
+		return ret;
+
+	if (ring->init) {
+		ret = ring->init(ring);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 
@@ -397,6 +445,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 	int ret;
 
 	BUG_ON(ctx->legacy_hw_ctx.rcs_state != NULL);
+	if (ctx->engine[ring->id].state)
+		return 0;
 
 	context_size = round_up(get_lr_context_size(ring), 4096);
 
drivers/gpu/drm/i915/intel_ringbuffer.c +6 -0
index 279dda4..20eb1a4 100644
@@ -40,6 +40,23 @@
  */
 #define CACHELINE_BYTES 64
 
+bool
+intel_ring_initialized(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+
+	if (!dev)

drivers/gpu/drm/i915/intel_ringbuffer.c line 58

Quoted 10 lines
drivers/gpu/drm/i915/intel_ringbuffer.c +10 -0
+		return false;
+
+	if (i915.enable_execlists) {
+		struct intel_context *dctx = ring->default_context;
+		struct intel_ringbuffer *ringbuf = dctx->engine[ring->id].ringbuf;
+
+		return ringbuf->obj;
+	} else
+		return ring->buffer && ring->buffer->obj;
+}

Looks like I'll not regret having ditched gt.ring_is_initialized. -Daniel

Quoted 28 lines
drivers/gpu/drm/i915/intel_ringbuffer.c +1 -0
+
 static inline int __ring_space(int head, int tail, int size)
 {
 	int space = head - (tail + I915_RING_FREE_SPACE);
drivers/gpu/drm/i915/intel_ringbuffer.h +1 -5
index be40788..7203ee2 100644
@@ -288,11 +288,7 @@ struct  intel_engine_cs {
 	u32 (*get_cmd_length_mask)(u32 cmd_header);
 };
 
-static inline bool
-intel_ring_initialized(struct intel_engine_cs *ring)
-{
-	return ring->buffer && ring->buffer->obj;
-}
+bool intel_ring_initialized(struct intel_engine_cs *ring);
 
 static inline unsigned
 intel_ring_flag(struct intel_engine_cs *ring)
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#54 lore raw

PATCH 16/43 drm/i915/bdw: GEN-specific logical ring init

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Logical rings do not need most of the initialization their legacy ringbuffer counterparts do: we just need the pipe control object for the render ring, enable Execlists on the hardware and a few workarounds.

v2: Squash with: "drm/i915: Extract pipe control fini & make init outside accesible".

---
 drivers/gpu/drm/i915/intel_lrc.c        |   54 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.c |   34 +++++++++++--------
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 ++
 3 files changed, 78 insertions(+), 13 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +54 -0
index 05b7069..7c8b75e 100644
@@ -106,6 +106,49 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring)
 	/* TODO */
 }
 
+static int gen8_init_common_ring(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	I915_WRITE(RING_MODE_GEN7(ring),
+		_MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
+		_MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
+	POSTING_READ(RING_MODE_GEN7(ring));
+	DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name);
+
+	memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
+
+	return 0;
+}
+
+static int gen8_init_render_ring(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = gen8_init_common_ring(ring);
+	if (ret)
+		return ret;
+
+	/* We need to disable the AsyncFlip performance optimisations in order
+	 * to use MI_WAIT_FOR_EVENT within the CS. It should already be
+	 * programmed to '1' on all products.
+	 *
+	 * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv,bdw,chv
+	 */
+	I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
+
+	ret = intel_init_pipe_control(ring);
+	if (ret)
+		return ret;
+
+	I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
+
+	return ret;
+}
+
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
 {
 	if (!intel_ring_initialized(ring))
@@ -176,6 +219,9 @@ static int logical_render_ring_init(struct drm_device *dev)
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT;
 
+	ring->init = gen8_init_render_ring;
+	ring->cleanup = intel_fini_pipe_control;
+
 	return logical_ring_init(dev, ring);
 }
 
@@ -190,6 +236,8 @@ static int logical_bsd_ring_init(struct drm_device *dev)
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
 
+	ring->init = gen8_init_common_ring;
+
 	return logical_ring_init(dev, ring);
 }
 
@@ -204,6 +252,8 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
 
+	ring->init = gen8_init_common_ring;
+
 	return logical_ring_init(dev, ring);
 }
 
@@ -218,6 +268,8 @@ static int logical_blt_ring_init(struct drm_device *dev)
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
 
+	ring->init = gen8_init_common_ring;
+
 	return logical_ring_init(dev, ring);
 }
 
@@ -232,6 +284,8 @@ static int logical_vebox_ring_init(struct drm_device *dev)
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
 
+	ring->init = gen8_init_common_ring;
+
 	return logical_ring_init(dev, ring);
 }
 
drivers/gpu/drm/i915/intel_ringbuffer.c +21 -13
index 20eb1a4..ca45c58 100644
@@ -573,8 +573,25 @@ out:
 	return ret;
 }
 
-static int
-init_pipe_control(struct intel_engine_cs *ring)
+void
+intel_fini_pipe_control(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+
+	if (ring->scratch.obj == NULL)
+		return;
+
+	if (INTEL_INFO(dev)->gen >= 5) {
+		kunmap(sg_page(ring->scratch.obj->pages->sgl));
+		i915_gem_object_ggtt_unpin(ring->scratch.obj);
+	}
+
+	drm_gem_object_unreference(&ring->scratch.obj->base);
+	ring->scratch.obj = NULL;
+}
+
+int
+intel_init_pipe_control(struct intel_engine_cs *ring)
 {
 	int ret;
 
@@ -649,7 +666,7 @@ static int init_render_ring(struct intel_engine_cs *ring)
 			   _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
 
 	if (INTEL_INFO(dev)->gen >= 5) {
-		ret = init_pipe_control(ring);
+		ret = intel_init_pipe_control(ring);
 		if (ret)
 			return ret;
 	}
@@ -684,16 +701,7 @@ static void render_ring_cleanup(struct intel_engine_cs *ring)
 		dev_priv->semaphore_obj = NULL;
 	}
 
-	if (ring->scratch.obj == NULL)
-		return;
-
-	if (INTEL_INFO(dev)->gen >= 5) {
-		kunmap(sg_page(ring->scratch.obj->pages->sgl));
-		i915_gem_object_ggtt_unpin(ring->scratch.obj);
-	}
-
-	drm_gem_object_unreference(&ring->scratch.obj->base);
-	ring->scratch.obj = NULL;
+	intel_fini_pipe_control(ring);
 }
 
 static int gen8_rcs_signal(struct intel_engine_cs *signaller,
drivers/gpu/drm/i915/intel_ringbuffer.h +3 -0
index 7203ee2..c135334 100644
@@ -380,6 +380,9 @@ void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno);
 int intel_ring_flush_all_caches(struct intel_engine_cs *ring);
 int intel_ring_invalidate_all_caches(struct intel_engine_cs *ring);
 
+void intel_fini_pipe_control(struct intel_engine_cs *ring);
+int intel_init_pipe_control(struct intel_engine_cs *ring);
+
 int intel_init_render_ring_buffer(struct drm_device *dev);
 int intel_init_bsd_ring_buffer(struct drm_device *dev);
 int intel_init_bsd2_ring_buffer(struct drm_device *dev);
Signature · 1 line
1.7.9.5
#55 lore raw

Re: [PATCH 16/43] drm/i915/bdw: GEN-specific logical ring init

Quoted 23 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Logical rings do not need most of the initialization their legacy ringbuffer counterparts do: we just need the pipe control object for the render ring, enable Execlists on the hardware and a few workarounds.

v2: Squash with: "drm/i915: Extract pipe control fini & make init outside accesible".

---
 drivers/gpu/drm/i915/intel_lrc.c        |   54 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.c |   34 +++++++++++--------
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 ++
 3 files changed, 78 insertions(+), 13 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index 05b7069..7c8b75e 100644
@@ -106,6 +106,49 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring)
 	/* TODO */

drivers/gpu/drm/i915/intel_lrc.c void intel_logical_ring_stop(struct intel_engine_cs *ring) · line 116

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +8 -0
 }
 
+static int gen8_init_common_ring(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	I915_WRITE(RING_MODE_GEN7(ring),
+		_MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
+		_MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));

Please build up a bit a closer relationship with checkpatch.pl, thanks.

Fixed while merging.
-Daniel

Quoted 164 lines
drivers/gpu/drm/i915/intel_lrc.c +46 -0
+	POSTING_READ(RING_MODE_GEN7(ring));
+	DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name);
+
+	memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
+
+	return 0;
+}
+
+static int gen8_init_render_ring(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = gen8_init_common_ring(ring);
+	if (ret)
+		return ret;
+
+	/* We need to disable the AsyncFlip performance optimisations in order
+	 * to use MI_WAIT_FOR_EVENT within the CS. It should already be
+	 * programmed to '1' on all products.
+	 *
+	 * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv,bdw,chv
+	 */
+	I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
+
+	ret = intel_init_pipe_control(ring);
+	if (ret)
+		return ret;
+
+	I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
+
+	return ret;
+}
+
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
 {
 	if (!intel_ring_initialized(ring))
@@ -176,6 +219,9 @@ static int logical_render_ring_init(struct drm_device *dev)
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT;
 
+	ring->init = gen8_init_render_ring;
+	ring->cleanup = intel_fini_pipe_control;
+
 	return logical_ring_init(dev, ring);
 }
 
@@ -190,6 +236,8 @@ static int logical_bsd_ring_init(struct drm_device *dev)
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
 
+	ring->init = gen8_init_common_ring;
+
 	return logical_ring_init(dev, ring);
 }
 
@@ -204,6 +252,8 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
 
+	ring->init = gen8_init_common_ring;
+
 	return logical_ring_init(dev, ring);
 }
 
@@ -218,6 +268,8 @@ static int logical_blt_ring_init(struct drm_device *dev)
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
 
+	ring->init = gen8_init_common_ring;
+
 	return logical_ring_init(dev, ring);
 }
 
@@ -232,6 +284,8 @@ static int logical_vebox_ring_init(struct drm_device *dev)
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
 
+	ring->init = gen8_init_common_ring;
+
 	return logical_ring_init(dev, ring);
 }
 
drivers/gpu/drm/i915/intel_ringbuffer.c +21 -13
index 20eb1a4..ca45c58 100644
@@ -573,8 +573,25 @@ out:
 	return ret;
 }
 
-static int
-init_pipe_control(struct intel_engine_cs *ring)
+void
+intel_fini_pipe_control(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+
+	if (ring->scratch.obj == NULL)
+		return;
+
+	if (INTEL_INFO(dev)->gen >= 5) {
+		kunmap(sg_page(ring->scratch.obj->pages->sgl));
+		i915_gem_object_ggtt_unpin(ring->scratch.obj);
+	}
+
+	drm_gem_object_unreference(&ring->scratch.obj->base);
+	ring->scratch.obj = NULL;
+}
+
+int
+intel_init_pipe_control(struct intel_engine_cs *ring)
 {
 	int ret;
 
@@ -649,7 +666,7 @@ static int init_render_ring(struct intel_engine_cs *ring)
 			   _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
 
 	if (INTEL_INFO(dev)->gen >= 5) {
-		ret = init_pipe_control(ring);
+		ret = intel_init_pipe_control(ring);
 		if (ret)
 			return ret;
 	}
@@ -684,16 +701,7 @@ static void render_ring_cleanup(struct intel_engine_cs *ring)
 		dev_priv->semaphore_obj = NULL;
 	}
 
-	if (ring->scratch.obj == NULL)
-		return;
-
-	if (INTEL_INFO(dev)->gen >= 5) {
-		kunmap(sg_page(ring->scratch.obj->pages->sgl));
-		i915_gem_object_ggtt_unpin(ring->scratch.obj);
-	}
-
-	drm_gem_object_unreference(&ring->scratch.obj->base);
-	ring->scratch.obj = NULL;
+	intel_fini_pipe_control(ring);
 }
 
 static int gen8_rcs_signal(struct intel_engine_cs *signaller,
drivers/gpu/drm/i915/intel_ringbuffer.h +3 -0
index 7203ee2..c135334 100644
@@ -380,6 +380,9 @@ void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno);
 int intel_ring_flush_all_caches(struct intel_engine_cs *ring);
 int intel_ring_invalidate_all_caches(struct intel_engine_cs *ring);
 
+void intel_fini_pipe_control(struct intel_engine_cs *ring);
+int intel_init_pipe_control(struct intel_engine_cs *ring);
+
 int intel_init_render_ring_buffer(struct drm_device *dev);
 int intel_init_bsd_ring_buffer(struct drm_device *dev);
 int intel_init_bsd2_ring_buffer(struct drm_device *dev);
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#56 lore raw

PATCH 17/43 drm/i915/bdw: GEN-specific logical ring set/get seqno

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

No mistery here: the seqno is still retrieved from the engine's HW status page (the one in the default context. For the moment, I see no reason to worry about other context's HWS page).

---
 drivers/gpu/drm/i915/intel_lrc.c |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +20 -0
index 7c8b75e..f171fd5 100644
@@ -149,6 +149,16 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
 	return ret;
 }
 
+static u32 gen8_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency)
+{
+	return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
+static void gen8_set_seqno(struct intel_engine_cs *ring, u32 seqno)
+{
+	intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
+}
+
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
 {
 	if (!intel_ring_initialized(ring))
@@ -221,6 +231,8 @@ static int logical_render_ring_init(struct drm_device *dev)
 
 	ring->init = gen8_init_render_ring;
 	ring->cleanup = intel_fini_pipe_control;
+	ring->get_seqno = gen8_get_seqno;
+	ring->set_seqno = gen8_set_seqno;
 
 	return logical_ring_init(dev, ring);
 }
@@ -237,6 +249,8 @@ static int logical_bsd_ring_init(struct drm_device *dev)
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
+	ring->get_seqno = gen8_get_seqno;
+	ring->set_seqno = gen8_set_seqno;
 
 	return logical_ring_init(dev, ring);
 }
@@ -253,6 +267,8 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
+	ring->get_seqno = gen8_get_seqno;
+	ring->set_seqno = gen8_set_seqno;
 
 	return logical_ring_init(dev, ring);
 }
@@ -269,6 +285,8 @@ static int logical_blt_ring_init(struct drm_device *dev)
 		GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
+	ring->get_seqno = gen8_get_seqno;
+	ring->set_seqno = gen8_set_seqno;
 
 	return logical_ring_init(dev, ring);
 }
@@ -285,6 +303,8 @@ static int logical_vebox_ring_init(struct drm_device *dev)
 		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
+	ring->get_seqno = gen8_get_seqno;
+	ring->set_seqno = gen8_set_seqno;
 
 	return logical_ring_init(dev, ring);
 }
Signature · 1 line
1.7.9.5
#57 lore raw

Re: [PATCH 17/43] drm/i915/bdw: GEN-specific logical ring set/get seqno

Quoted 7 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

No mistery here: the seqno is still retrieved from the engine's HW status page (the one in the default context. For the moment, I see no reason to worry about other context's HWS page).

Ok, merged or bikeshedded up to this one. I need a bit a break to recharge, will continue later on.

Cheers, Daniel

Quoted 77 lines
---
 drivers/gpu/drm/i915/intel_lrc.c |   20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +20 -0
index 7c8b75e..f171fd5 100644
@@ -149,6 +149,16 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
 	return ret;
 }
 
+static u32 gen8_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency)
+{
+	return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
+static void gen8_set_seqno(struct intel_engine_cs *ring, u32 seqno)
+{
+	intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
+}
+
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
 {
 	if (!intel_ring_initialized(ring))
@@ -221,6 +231,8 @@ static int logical_render_ring_init(struct drm_device *dev)
 
 	ring->init = gen8_init_render_ring;
 	ring->cleanup = intel_fini_pipe_control;
+	ring->get_seqno = gen8_get_seqno;
+	ring->set_seqno = gen8_set_seqno;
 
 	return logical_ring_init(dev, ring);
 }
@@ -237,6 +249,8 @@ static int logical_bsd_ring_init(struct drm_device *dev)
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
+	ring->get_seqno = gen8_get_seqno;
+	ring->set_seqno = gen8_set_seqno;
 
 	return logical_ring_init(dev, ring);
 }
@@ -253,6 +267,8 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
+	ring->get_seqno = gen8_get_seqno;
+	ring->set_seqno = gen8_set_seqno;
 
 	return logical_ring_init(dev, ring);
 }
@@ -269,6 +285,8 @@ static int logical_blt_ring_init(struct drm_device *dev)
 		GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
+	ring->get_seqno = gen8_get_seqno;
+	ring->set_seqno = gen8_set_seqno;
 
 	return logical_ring_init(dev, ring);
 }
@@ -285,6 +303,8 @@ static int logical_vebox_ring_init(struct drm_device *dev)
 		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
+	ring->get_seqno = gen8_get_seqno;
+	ring->set_seqno = gen8_set_seqno;
 
 	return logical_ring_init(dev, ring);
 }
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#58 lore raw

PATCH 18/43 drm/i915/bdw: New logical ring submission mechanism

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Well, new-ish: if all this code looks familiar, that's because it's a clone of the existing submission mechanism (with some modifications here and there to adapt it to LRCs and Execlists).

And why did we do this instead of reusing code, one might wonder? Well, there are some fears that the differences are big enough that they will end up breaking all platforms.

Also, Execlists offer several advantages, like control over when the GPU is done with a given workload, that can help simplify the submission mechanism, no doubt. I am interested in getting Execlists to work first and foremost, but in the future this parallel submission mechanism will help us to fine tune the mechanism without affecting old gens.

v2: Pass the ringbuffer only (whenever possible).

---
 drivers/gpu/drm/i915/intel_lrc.c        |  193 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.h        |   12 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c |   20 ++--
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 +
 4 files changed, 218 insertions(+), 10 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +193 -0
index f171fd5..bd37d51 100644
@@ -106,6 +106,199 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring)
 	/* TODO */
 }
 
+void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
+{
+	intel_logical_ring_advance(ringbuf);
+
+	if (intel_ring_stopped(ringbuf->ring))
+		return;
+
+	/* TODO: how to submit a context to the ELSP is not here yet */
+}
+
+static int logical_ring_alloc_seqno(struct intel_engine_cs *ring)
+{
+	if (ring->outstanding_lazy_seqno)
+		return 0;
+
+	if (ring->preallocated_lazy_request == NULL) {
+		struct drm_i915_gem_request *request;
+
+		request = kmalloc(sizeof(*request), GFP_KERNEL);
+		if (request == NULL)
+			return -ENOMEM;
+
+		ring->preallocated_lazy_request = request;
+	}
+
+	return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno);
+}
+
+static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, int bytes)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_i915_gem_request *request;
+	u32 seqno = 0;
+	int ret;
+
+	if (ringbuf->last_retired_head != -1) {
+		ringbuf->head = ringbuf->last_retired_head;
+		ringbuf->last_retired_head = -1;
+
+		ringbuf->space = intel_ring_space(ringbuf);
+		if (ringbuf->space >= bytes)
+			return 0;
+	}
+
+	list_for_each_entry(request, &ring->request_list, list) {
+		if (__intel_ring_space(request->tail, ringbuf->tail,
+				ringbuf->size) >= bytes) {
+			seqno = request->seqno;
+			break;
+		}
+	}
+
+	if (seqno == 0)
+		return -ENOSPC;
+
+	ret = i915_wait_seqno(ring, seqno);
+	if (ret)
+		return ret;
+
+	/* TODO: make sure we update the right ringbuffer's last_retired_head
+	 * when retiring requests */
+	i915_gem_retire_requests_ring(ring);
+	ringbuf->head = ringbuf->last_retired_head;
+	ringbuf->last_retired_head = -1;
+
+	ringbuf->space = intel_ring_space(ringbuf);
+	return 0;
+}
+
+static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, int bytes)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	unsigned long end;
+	int ret;
+
+	ret = logical_ring_wait_request(ringbuf, bytes);
+	if (ret != -ENOSPC)
+		return ret;
+
+	/* Force the context submission in case we have been skipping it */
+	intel_logical_ring_advance_and_submit(ringbuf);
+
+	/* With GEM the hangcheck timer should kick us out of the loop,
+	 * leaving it early runs the risk of corrupting GEM state (due
+	 * to running on almost untested codepaths). But on resume
+	 * timers don't work yet, so prevent a complete hang in that
+	 * case by choosing an insanely large timeout. */
+	end = jiffies + 60 * HZ;
+
+	do {
+		ringbuf->head = I915_READ_HEAD(ring);
+		ringbuf->space = intel_ring_space(ringbuf);
+		if (ringbuf->space >= bytes) {
+			ret = 0;
+			break;
+		}
+
+		if (!drm_core_check_feature(dev, DRIVER_MODESET) &&
+		    dev->primary->master) {
+			struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+			if (master_priv->sarea_priv)
+				master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+		}
+
+		msleep(1);
+
+		if (dev_priv->mm.interruptible && signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		ret = i915_gem_check_wedge(&dev_priv->gpu_error,
+					   dev_priv->mm.interruptible);
+		if (ret)
+			break;
+
+		if (time_after(jiffies, end)) {
+			ret = -EBUSY;
+			break;
+		}
+	} while (1);
+
+	return ret;
+}
+
+static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf)
+{
+	uint32_t __iomem *virt;
+	int rem = ringbuf->size - ringbuf->tail;
+
+	if (ringbuf->space < rem) {
+		int ret = logical_ring_wait_for_space(ringbuf, rem);
+		if (ret)
+			return ret;
+	}
+
+	virt = ringbuf->virtual_start + ringbuf->tail;
+	rem /= 4;
+	while (rem--)
+		iowrite32(MI_NOOP, virt++);
+
+	ringbuf->tail = 0;
+	ringbuf->space = intel_ring_space(ringbuf);
+
+	return 0;
+}
+
+static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, int bytes)
+{
+	int ret;
+
+	if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) {
+		ret = logical_ring_wrap_buffer(ringbuf);
+		if (unlikely(ret))
+			return ret;
+	}
+
+	if (unlikely(ringbuf->space < bytes)) {
+		ret = logical_ring_wait_for_space(ringbuf, bytes);
+		if (unlikely(ret))
+			return ret;
+	}
+
+	return 0;
+}
+
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = i915_gem_check_wedge(&dev_priv->gpu_error,
+				   dev_priv->mm.interruptible);
+	if (ret)
+		return ret;
+
+	ret = logical_ring_prepare(ringbuf, num_dwords * sizeof(uint32_t));
+	if (ret)
+		return ret;
+
+	/* Preallocate the olr before touching the ring */
+	ret = logical_ring_alloc_seqno(ring);
+	if (ret)
+		return ret;
+
+	ringbuf->space -= num_dwords * sizeof(uint32_t);
+	return 0;
+}
+
 static int gen8_init_common_ring(struct intel_engine_cs *ring)
 {
 	struct drm_device *dev = ring->dev;
drivers/gpu/drm/i915/intel_lrc.h +12 -0
index bf0eff4..16798b6 100644
@@ -29,6 +29,18 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring);
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring);
 int intel_logical_rings_init(struct drm_device *dev);
 
+void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf);
+static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf)
+{
+	ringbuf->tail &= ringbuf->size - 1;
+}
+static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf, u32 data)
+{
+	iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
+	ringbuf->tail += 4;
+}
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
+
 /* Logical Ring Contexts */
 void intel_lr_context_free(struct intel_context *ctx);
 int intel_lr_context_deferred_create(struct intel_context *ctx,
drivers/gpu/drm/i915/intel_ringbuffer.c +10 -10
index ca45c58..dc2a991 100644
@@ -57,7 +57,7 @@ intel_ring_initialized(struct intel_engine_cs *ring)
 		return ring->buffer && ring->buffer->obj;
 }
 
-static inline int __ring_space(int head, int tail, int size)
+int __intel_ring_space(int head, int tail, int size)
 {
 	int space = head - (tail + I915_RING_FREE_SPACE);
 	if (space < 0)
@@ -65,12 +65,12 @@ static inline int __ring_space(int head, int tail, int size)
 	return space;
 }
 
-static inline int ring_space(struct intel_ringbuffer *ringbuf)
+int intel_ring_space(struct intel_ringbuffer *ringbuf)
 {
-	return __ring_space(ringbuf->head & HEAD_ADDR, ringbuf->tail, ringbuf->size);
+	return __intel_ring_space(ringbuf->head & HEAD_ADDR, ringbuf->tail, ringbuf->size);
 }
 
-static bool intel_ring_stopped(struct intel_engine_cs *ring)
+bool intel_ring_stopped(struct intel_engine_cs *ring)
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	return dev_priv->gpu_error.stop_rings & intel_ring_flag(ring);
@@ -561,7 +561,7 @@ static int init_ring_common(struct intel_engine_cs *ring)
 	else {
 		ringbuf->head = I915_READ_HEAD(ring);
 		ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
-		ringbuf->space = ring_space(ringbuf);
+		ringbuf->space = intel_ring_space(ringbuf);
 		ringbuf->last_retired_head = -1;
 	}
 
@@ -1679,13 +1679,13 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
 		ringbuf->head = ringbuf->last_retired_head;
 		ringbuf->last_retired_head = -1;
 
-		ringbuf->space = ring_space(ringbuf);
+		ringbuf->space = intel_ring_space(ringbuf);
 		if (ringbuf->space >= n)
 			return 0;
 	}
 
 	list_for_each_entry(request, &ring->request_list, list) {
-		if (__ring_space(request->tail, ringbuf->tail, ringbuf->size) >= n) {
+		if (__intel_ring_space(request->tail, ringbuf->tail, ringbuf->size) >= n) {
 			seqno = request->seqno;
 			break;
 		}
@@ -1702,7 +1702,7 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
 	ringbuf->head = ringbuf->last_retired_head;
 	ringbuf->last_retired_head = -1;
 
-	ringbuf->space = ring_space(ringbuf);
+	ringbuf->space = intel_ring_space(ringbuf);
 	return 0;
 }
 
@@ -1731,7 +1731,7 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n)
 	trace_i915_ring_wait_begin(ring);
 	do {
 		ringbuf->head = I915_READ_HEAD(ring);
-		ringbuf->space = ring_space(ringbuf);
+		ringbuf->space = intel_ring_space(ringbuf);
 		if (ringbuf->space >= n) {
 			ret = 0;
 			break;
@@ -1783,7 +1783,7 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring)
 		iowrite32(MI_NOOP, virt++);
 
 	ringbuf->tail = 0;
-	ringbuf->space = ring_space(ringbuf);
+	ringbuf->space = intel_ring_space(ringbuf);
 
 	return 0;
 }
drivers/gpu/drm/i915/intel_ringbuffer.h +3 -0
index c135334..c305df0 100644
@@ -373,6 +373,9 @@ static inline void intel_ring_advance(struct intel_engine_cs *ring)
 	struct intel_ringbuffer *ringbuf = ring->buffer;
 	ringbuf->tail &= ringbuf->size - 1;
 }
+int __intel_ring_space(int head, int tail, int size);
+int intel_ring_space(struct intel_ringbuffer *ringbuf);
+bool intel_ring_stopped(struct intel_engine_cs *ring);
 void __intel_ring_advance(struct intel_engine_cs *ring);
 
 int __must_check intel_ring_idle(struct intel_engine_cs *ring);
Signature · 1 line
1.7.9.5
#59 lore raw

Re: [PATCH 18/43] drm/i915/bdw: New logical ring submission mechanism

Quoted 130 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Well, new-ish: if all this code looks familiar, that's because it's a clone of the existing submission mechanism (with some modifications here and there to adapt it to LRCs and Execlists).

And why did we do this instead of reusing code, one might wonder? Well, there are some fears that the differences are big enough that they will end up breaking all platforms.

Also, Execlists offer several advantages, like control over when the GPU is done with a given workload, that can help simplify the submission mechanism, no doubt. I am interested in getting Execlists to work first and foremost, but in the future this parallel submission mechanism will help us to fine tune the mechanism without affecting old gens.

v2: Pass the ringbuffer only (whenever possible).

---
 drivers/gpu/drm/i915/intel_lrc.c        |  193 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.h        |   12 ++
 drivers/gpu/drm/i915/intel_ringbuffer.c |   20 ++--
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 +
 4 files changed, 218 insertions(+), 10 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +95 -0
index f171fd5..bd37d51 100644
@@ -106,6 +106,199 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring)
 	/* TODO */
 }
 
+void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
+{
+	intel_logical_ring_advance(ringbuf);
+
+	if (intel_ring_stopped(ringbuf->ring))
+		return;
+
+	/* TODO: how to submit a context to the ELSP is not here yet */
+}
+
+static int logical_ring_alloc_seqno(struct intel_engine_cs *ring)
+{
+	if (ring->outstanding_lazy_seqno)
+		return 0;
+
+	if (ring->preallocated_lazy_request == NULL) {
+		struct drm_i915_gem_request *request;
+
+		request = kmalloc(sizeof(*request), GFP_KERNEL);
+		if (request == NULL)
+			return -ENOMEM;
+
+		ring->preallocated_lazy_request = request;
+	}
+
+	return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno);
+}
+
+static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, int bytes)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_i915_gem_request *request;
+	u32 seqno = 0;
+	int ret;
+
+	if (ringbuf->last_retired_head != -1) {
+		ringbuf->head = ringbuf->last_retired_head;
+		ringbuf->last_retired_head = -1;
+
+		ringbuf->space = intel_ring_space(ringbuf);
+		if (ringbuf->space >= bytes)
+			return 0;
+	}
+
+	list_for_each_entry(request, &ring->request_list, list) {
+		if (__intel_ring_space(request->tail, ringbuf->tail,
+				ringbuf->size) >= bytes) {
+			seqno = request->seqno;
+			break;
+		}
+	}
+
+	if (seqno == 0)
+		return -ENOSPC;
+
+	ret = i915_wait_seqno(ring, seqno);
+	if (ret)
+		return ret;
+
+	/* TODO: make sure we update the right ringbuffer's last_retired_head
+	 * when retiring requests */
+	i915_gem_retire_requests_ring(ring);
+	ringbuf->head = ringbuf->last_retired_head;
+	ringbuf->last_retired_head = -1;
+
+	ringbuf->space = intel_ring_space(ringbuf);
+	return 0;
+}
+
+static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, int bytes)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	unsigned long end;
+	int ret;
+
+	ret = logical_ring_wait_request(ringbuf, bytes);
+	if (ret != -ENOSPC)
+		return ret;
+
+	/* Force the context submission in case we have been skipping it */
+	intel_logical_ring_advance_and_submit(ringbuf);
+
+	/* With GEM the hangcheck timer should kick us out of the loop,
+	 * leaving it early runs the risk of corrupting GEM state (due
+	 * to running on almost untested codepaths). But on resume
+	 * timers don't work yet, so prevent a complete hang in that
+	 * case by choosing an insanely large timeout. */
+	end = jiffies + 60 * HZ;
+
+	do {
+		ringbuf->head = I915_READ_HEAD(ring);
+		ringbuf->space = intel_ring_space(ringbuf);
+		if (ringbuf->space >= bytes) {

drivers/gpu/drm/i915/intel_lrc.c void intel_logical_ring_stop(struct intel_engine_cs *ring) · line 213

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +10 -0
+			ret = 0;
+			break;
+		}
+
+		if (!drm_core_check_feature(dev, DRIVER_MODESET) &&
+		    dev->primary->master) {
+			struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+			if (master_priv->sarea_priv)
+				master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+		}

sarea is legacy gunk. Really bad legacy gunk. The DRIVE_MODESET check should have been a give-away. Also checkpatch.

Fixed while applying.
-Daniel

Quoted 216 lines
drivers/gpu/drm/i915/intel_lrc.c +88 -0
+
+		msleep(1);
+
+		if (dev_priv->mm.interruptible && signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		ret = i915_gem_check_wedge(&dev_priv->gpu_error,
+					   dev_priv->mm.interruptible);
+		if (ret)
+			break;
+
+		if (time_after(jiffies, end)) {
+			ret = -EBUSY;
+			break;
+		}
+	} while (1);
+
+	return ret;
+}
+
+static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf)
+{
+	uint32_t __iomem *virt;
+	int rem = ringbuf->size - ringbuf->tail;
+
+	if (ringbuf->space < rem) {
+		int ret = logical_ring_wait_for_space(ringbuf, rem);
+		if (ret)
+			return ret;
+	}
+
+	virt = ringbuf->virtual_start + ringbuf->tail;
+	rem /= 4;
+	while (rem--)
+		iowrite32(MI_NOOP, virt++);
+
+	ringbuf->tail = 0;
+	ringbuf->space = intel_ring_space(ringbuf);
+
+	return 0;
+}
+
+static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, int bytes)
+{
+	int ret;
+
+	if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) {
+		ret = logical_ring_wrap_buffer(ringbuf);
+		if (unlikely(ret))
+			return ret;
+	}
+
+	if (unlikely(ringbuf->space < bytes)) {
+		ret = logical_ring_wait_for_space(ringbuf, bytes);
+		if (unlikely(ret))
+			return ret;
+	}
+
+	return 0;
+}
+
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = i915_gem_check_wedge(&dev_priv->gpu_error,
+				   dev_priv->mm.interruptible);
+	if (ret)
+		return ret;
+
+	ret = logical_ring_prepare(ringbuf, num_dwords * sizeof(uint32_t));
+	if (ret)
+		return ret;
+
+	/* Preallocate the olr before touching the ring */
+	ret = logical_ring_alloc_seqno(ring);
+	if (ret)
+		return ret;
+
+	ringbuf->space -= num_dwords * sizeof(uint32_t);
+	return 0;
+}
+
 static int gen8_init_common_ring(struct intel_engine_cs *ring)
 {
 	struct drm_device *dev = ring->dev;
drivers/gpu/drm/i915/intel_lrc.h +12 -0
index bf0eff4..16798b6 100644
@@ -29,6 +29,18 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring);
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring);
 int intel_logical_rings_init(struct drm_device *dev);
 
+void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf);
+static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf)
+{
+	ringbuf->tail &= ringbuf->size - 1;
+}
+static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf, u32 data)
+{
+	iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
+	ringbuf->tail += 4;
+}
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
+
 /* Logical Ring Contexts */
 void intel_lr_context_free(struct intel_context *ctx);
 int intel_lr_context_deferred_create(struct intel_context *ctx,
drivers/gpu/drm/i915/intel_ringbuffer.c +10 -10
index ca45c58..dc2a991 100644
@@ -57,7 +57,7 @@ intel_ring_initialized(struct intel_engine_cs *ring)
 		return ring->buffer && ring->buffer->obj;
 }
 
-static inline int __ring_space(int head, int tail, int size)
+int __intel_ring_space(int head, int tail, int size)
 {
 	int space = head - (tail + I915_RING_FREE_SPACE);
 	if (space < 0)
@@ -65,12 +65,12 @@ static inline int __ring_space(int head, int tail, int size)
 	return space;
 }
 
-static inline int ring_space(struct intel_ringbuffer *ringbuf)
+int intel_ring_space(struct intel_ringbuffer *ringbuf)
 {
-	return __ring_space(ringbuf->head & HEAD_ADDR, ringbuf->tail, ringbuf->size);
+	return __intel_ring_space(ringbuf->head & HEAD_ADDR, ringbuf->tail, ringbuf->size);
 }
 
-static bool intel_ring_stopped(struct intel_engine_cs *ring)
+bool intel_ring_stopped(struct intel_engine_cs *ring)
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	return dev_priv->gpu_error.stop_rings & intel_ring_flag(ring);
@@ -561,7 +561,7 @@ static int init_ring_common(struct intel_engine_cs *ring)
 	else {
 		ringbuf->head = I915_READ_HEAD(ring);
 		ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
-		ringbuf->space = ring_space(ringbuf);
+		ringbuf->space = intel_ring_space(ringbuf);
 		ringbuf->last_retired_head = -1;
 	}
 
@@ -1679,13 +1679,13 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
 		ringbuf->head = ringbuf->last_retired_head;
 		ringbuf->last_retired_head = -1;
 
-		ringbuf->space = ring_space(ringbuf);
+		ringbuf->space = intel_ring_space(ringbuf);
 		if (ringbuf->space >= n)
 			return 0;
 	}
 
 	list_for_each_entry(request, &ring->request_list, list) {
-		if (__ring_space(request->tail, ringbuf->tail, ringbuf->size) >= n) {
+		if (__intel_ring_space(request->tail, ringbuf->tail, ringbuf->size) >= n) {
 			seqno = request->seqno;
 			break;
 		}
@@ -1702,7 +1702,7 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
 	ringbuf->head = ringbuf->last_retired_head;
 	ringbuf->last_retired_head = -1;
 
-	ringbuf->space = ring_space(ringbuf);
+	ringbuf->space = intel_ring_space(ringbuf);
 	return 0;
 }
 
@@ -1731,7 +1731,7 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n)
 	trace_i915_ring_wait_begin(ring);
 	do {
 		ringbuf->head = I915_READ_HEAD(ring);
-		ringbuf->space = ring_space(ringbuf);
+		ringbuf->space = intel_ring_space(ringbuf);
 		if (ringbuf->space >= n) {
 			ret = 0;
 			break;
@@ -1783,7 +1783,7 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring)
 		iowrite32(MI_NOOP, virt++);
 
 	ringbuf->tail = 0;
-	ringbuf->space = ring_space(ringbuf);
+	ringbuf->space = intel_ring_space(ringbuf);
 
 	return 0;
 }
drivers/gpu/drm/i915/intel_ringbuffer.h +3 -0
index c135334..c305df0 100644
@@ -373,6 +373,9 @@ static inline void intel_ring_advance(struct intel_engine_cs *ring)
 	struct intel_ringbuffer *ringbuf = ring->buffer;
 	ringbuf->tail &= ringbuf->size - 1;
 }
+int __intel_ring_space(int head, int tail, int size);
+int intel_ring_space(struct intel_ringbuffer *ringbuf);
+bool intel_ring_stopped(struct intel_engine_cs *ring);
 void __intel_ring_advance(struct intel_engine_cs *ring);
 
 int __must_check intel_ring_idle(struct intel_engine_cs *ring);
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#60 lore raw

PATCH 19/43 drm/i915/bdw: GEN-specific logical ring emit request

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Very similar to the legacy add_request, only modified to account for logical ringbuffer.

v2: Use MI_GLOBAL_GTT, as suggested by Brad Volkin.

v3: Unify render and non-render in the same function, as noticed by Brad Volkin.

---
 drivers/gpu/drm/i915/i915_reg.h         |    1 +
 drivers/gpu/drm/i915/intel_lrc.c        |   31 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 +++
 3 files changed, 35 insertions(+)
drivers/gpu/drm/i915/i915_reg.h +1 -0
index 043a6ea..70dddac 100644
@@ -272,6 +272,7 @@
 #define   MI_SEMAPHORE_POLL		(1<<15)
 #define   MI_SEMAPHORE_SAD_GTE_SDD	(1<<12)
 #define MI_STORE_DWORD_IMM	MI_INSTR(0x20, 1)
+#define MI_STORE_DWORD_IMM_GEN8	MI_INSTR(0x20, 2)
 #define   MI_MEM_VIRTUAL	(1 << 22) /* 965+ only */
 #define MI_STORE_DWORD_INDEX	MI_INSTR(0x21, 1)
 #define   MI_STORE_DWORD_INDEX_SHIFT 2
drivers/gpu/drm/i915/intel_lrc.c +31 -0
index bd37d51..64bda7a 100644
@@ -352,6 +352,32 @@ static void gen8_set_seqno(struct intel_engine_cs *ring, u32 seqno)
 	intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
 }
 
+static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	u32 cmd;
+	int ret;
+
+	ret = intel_logical_ring_begin(ringbuf, 6);
+	if (ret)
+		return ret;
+
+	cmd = MI_STORE_DWORD_IMM_GEN8;
+	cmd |= MI_GLOBAL_GTT;
+
+	intel_logical_ring_emit(ringbuf, cmd);
+	intel_logical_ring_emit(ringbuf,
+				(ring->status_page.gfx_addr +
+				(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT)));
+	intel_logical_ring_emit(ringbuf, 0);
+	intel_logical_ring_emit(ringbuf, ring->outstanding_lazy_seqno);
+	intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT);
+	intel_logical_ring_emit(ringbuf, MI_NOOP);
+	intel_logical_ring_advance_and_submit(ringbuf);
+
+	return 0;
+}
+
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
 {
 	if (!intel_ring_initialized(ring))
@@ -426,6 +452,7 @@ static int logical_render_ring_init(struct drm_device *dev)
 	ring->cleanup = intel_fini_pipe_control;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
+	ring->emit_request = gen8_emit_request;
 
 	return logical_ring_init(dev, ring);
 }
@@ -444,6 +471,7 @@ static int logical_bsd_ring_init(struct drm_device *dev)
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
+	ring->emit_request = gen8_emit_request;
 
 	return logical_ring_init(dev, ring);
 }
@@ -462,6 +490,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
+	ring->emit_request = gen8_emit_request;
 
 	return logical_ring_init(dev, ring);
 }
@@ -480,6 +509,7 @@ static int logical_blt_ring_init(struct drm_device *dev)
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
+	ring->emit_request = gen8_emit_request;
 
 	return logical_ring_init(dev, ring);
 }
@@ -498,6 +528,7 @@ static int logical_vebox_ring_init(struct drm_device *dev)
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
+	ring->emit_request = gen8_emit_request;
 
 	return logical_ring_init(dev, ring);
 }
drivers/gpu/drm/i915/intel_ringbuffer.h +3 -0
index c305df0..176ee6a 100644
@@ -215,6 +215,9 @@ struct  intel_engine_cs {
 				  unsigned int num_dwords);
 	} semaphore;
 
+	/* Execlists */
+	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
+
 	/**
 	 * List of objects currently involved in rendering from the
 	 * ringbuffer.
Signature · 1 line
1.7.9.5
#61 lore raw

PATCH 20/43 drm/i915/bdw: GEN-specific logical ring emit flush

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Same as the legacy-style ring->flush.

v2: The BSD invalidate bit still exists in GEN8! Add it for the VCS rings (but still consolidate the blt and bsd ring flushes into one). This was noticed by Brad Volkin.

v3: The command for BSD and for other rings is slightly different:
get it exactly the same as in gen6_ring_flush + gen6_bsd_ring_flush

---
 drivers/gpu/drm/i915/intel_lrc.c        |   82 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.c |    7 ---
 drivers/gpu/drm/i915/intel_ringbuffer.h |   10 ++++
 3 files changed, 92 insertions(+), 7 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +82 -0
index 64bda7a..5dd63d6 100644
@@ -342,6 +342,83 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
 	return ret;
 }
 
+static int gen8_emit_flush(struct intel_ringbuffer *ringbuf,
+			   u32 invalidate_domains,
+			   u32 unused)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	uint32_t cmd;
+	int ret;
+
+	ret = intel_logical_ring_begin(ringbuf, 4);
+	if (ret)
+		return ret;
+
+	cmd = MI_FLUSH_DW + 1;
+
+	if (ring == &dev_priv->ring[VCS]) {
+		if (invalidate_domains & I915_GEM_GPU_DOMAINS)
+			cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD |
+				MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
+	} else {
+		if (invalidate_domains & I915_GEM_DOMAIN_RENDER)
+			cmd |= MI_INVALIDATE_TLB | MI_FLUSH_DW_STORE_INDEX |
+				MI_FLUSH_DW_OP_STOREDW;
+	}
+
+	intel_logical_ring_emit(ringbuf, cmd);
+	intel_logical_ring_emit(ringbuf, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
+	intel_logical_ring_emit(ringbuf, 0); /* upper addr */
+	intel_logical_ring_emit(ringbuf, 0); /* value */
+	intel_logical_ring_advance(ringbuf);
+
+	return 0;
+}
+
+static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf,
+				  u32 invalidate_domains,
+				  u32 flush_domains)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
+	u32 flags = 0;
+	int ret;
+
+	flags |= PIPE_CONTROL_CS_STALL;
+
+	if (flush_domains) {
+		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
+		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+	}
+
+	if (invalidate_domains) {
+		flags |= PIPE_CONTROL_TLB_INVALIDATE;
+		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
+		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
+		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
+		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
+		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
+		flags |= PIPE_CONTROL_QW_WRITE;
+		flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
+	}
+
+	ret = intel_logical_ring_begin(ringbuf, 6);
+	if (ret)
+		return ret;
+
+	intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6));
+	intel_logical_ring_emit(ringbuf, flags);
+	intel_logical_ring_emit(ringbuf, scratch_addr);
+	intel_logical_ring_emit(ringbuf, 0);
+	intel_logical_ring_emit(ringbuf, 0);
+	intel_logical_ring_emit(ringbuf, 0);
+	intel_logical_ring_advance(ringbuf);
+
+	return 0;
+}
+
 static u32 gen8_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency)
 {
 	return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
@@ -453,6 +530,7 @@ static int logical_render_ring_init(struct drm_device *dev)
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
+	ring->emit_flush = gen8_emit_flush_render;
 
 	return logical_ring_init(dev, ring);
 }
@@ -472,6 +550,7 @@ static int logical_bsd_ring_init(struct drm_device *dev)
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
+	ring->emit_flush = gen8_emit_flush;
 
 	return logical_ring_init(dev, ring);
 }
@@ -491,6 +570,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
+	ring->emit_flush = gen8_emit_flush;
 
 	return logical_ring_init(dev, ring);
 }
@@ -510,6 +590,7 @@ static int logical_blt_ring_init(struct drm_device *dev)
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
+	ring->emit_flush = gen8_emit_flush;
 
 	return logical_ring_init(dev, ring);
 }
@@ -529,6 +610,7 @@ static int logical_vebox_ring_init(struct drm_device *dev)
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
+	ring->emit_flush = gen8_emit_flush;
 
 	return logical_ring_init(dev, ring);
 }
drivers/gpu/drm/i915/intel_ringbuffer.c +0 -7
index dc2a991..3188403 100644
@@ -33,13 +33,6 @@
 #include "i915_trace.h"
 #include "intel_drv.h"
 
-/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill,
- * but keeps the logic simple. Indeed, the whole purpose of this macro is just
- * to give some inclination as to some of the magic values used in the various
- * workarounds!
- */
-#define CACHELINE_BYTES 64
-
 bool
 intel_ring_initialized(struct intel_engine_cs *ring)
 {
drivers/gpu/drm/i915/intel_ringbuffer.h +10 -0
index 176ee6a..6e22866 100644
@@ -5,6 +5,13 @@
 
 #define I915_CMD_HASH_ORDER 9
 
+/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill,
+ * but keeps the logic simple. Indeed, the whole purpose of this macro is just
+ * to give some inclination as to some of the magic values used in the various
+ * workarounds!
+ */
+#define CACHELINE_BYTES 64
+
 /*
  * Gen2 BSpec "1. Programming Environment" / 1.4.4.6 "Ring Buffer Use"
  * Gen3 BSpec "vol1c Memory Interface Functions" / 2.3.4.5 "Ring Buffer Use"
@@ -217,6 +224,9 @@ struct  intel_engine_cs {
 
 	/* Execlists */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
+	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
+				      u32 invalidate_domains,
+				      u32 flush_domains);
 
 	/**
 	 * List of objects currently involved in rendering from the
Signature · 1 line
1.7.9.5
#62 lore raw

PATCH 21/43 drm/i915/bdw: Emission of requests with logical rings

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

On a previous iteration of this patch, I created an Execlists version of __i915_add_request and asbtracted it away as a vfunc. Daniel Vetter wondered then why that was needed:

"with the clean split in command submission I expect every function to know wether it'll submit to an lrc (everything in intel_lrc.c) or wether it'll submit to a legacy ring (existing code), so I don't see a need for an add_request vfunc."

The honest, hairy truth is that this patch is the glue keeping the whole logical ring puzzle together:

- i915_add_request is used by intel_ring_idle, which in turn is used by i915_gpu_idle, which in turn is used in several places inside the eviction and gtt codes.
- Also, it is used by i915_gem_check_olr, which is littered all over i915_gem.c
- ...

If I were to duplicate all the code that directly or indirectly uses __i915_add_request, I'll end up creating a separate driver.

To show the differences between the existing legacy version and the new Execlists one, this time I have special-cased __i915_add_request instead of adding an add_request vfunc. I hope this helps to untangle this Gordian knot.

---
 drivers/gpu/drm/i915/i915_gem.c  |   72 ++++++++++++++++++++++++++++----------
 drivers/gpu/drm/i915/intel_lrc.c |   30 +++++++++++++---
 drivers/gpu/drm/i915/intel_lrc.h |    1 +
 3 files changed, 80 insertions(+), 23 deletions(-)
drivers/gpu/drm/i915/i915_gem.c +53 -19
index 9560b40..1c83b9c 100644
@@ -2327,10 +2327,21 @@ int __i915_add_request(struct intel_engine_cs *ring,
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	struct drm_i915_gem_request *request;
+	struct intel_ringbuffer *ringbuf;
 	u32 request_ring_position, request_start;
 	int ret;
 
-	request_start = intel_ring_get_tail(ring->buffer);
+	request = ring->preallocated_lazy_request;
+	if (WARN_ON(request == NULL))
+		return -ENOMEM;
+
+	if (i915.enable_execlists) {
+		struct intel_context *ctx = request->ctx;
+		ringbuf = ctx->engine[ring->id].ringbuf;
+	} else
+		ringbuf = ring->buffer;
+
+	request_start = intel_ring_get_tail(ringbuf);
 	/*
 	 * Emit any outstanding flushes - execbuf can fail to emit the flush
 	 * after having emitted the batchbuffer command. Hence we need to fix
@@ -2338,24 +2349,32 @@ int __i915_add_request(struct intel_engine_cs *ring,
 	 * is that the flush _must_ happen before the next request, no matter
 	 * what.
 	 */
-	ret = intel_ring_flush_all_caches(ring);
-	if (ret)
-		return ret;
-
-	request = ring->preallocated_lazy_request;
-	if (WARN_ON(request == NULL))
-		return -ENOMEM;
+	if (i915.enable_execlists) {
+		ret = logical_ring_flush_all_caches(ringbuf);
+		if (ret)
+			return ret;
+	} else {
+		ret = intel_ring_flush_all_caches(ring);
+		if (ret)
+			return ret;
+	}
 
 	/* Record the position of the start of the request so that
 	 * should we detect the updated seqno part-way through the
 	 * GPU processing the request, we never over-estimate the
 	 * position of the head.
 	 */
-	request_ring_position = intel_ring_get_tail(ring->buffer);
+	request_ring_position = intel_ring_get_tail(ringbuf);
 
-	ret = ring->add_request(ring);
-	if (ret)
-		return ret;
+	if (i915.enable_execlists) {
+		ret = ring->emit_request(ringbuf);
+		if (ret)
+			return ret;
+	} else {
+		ret = ring->add_request(ring);
+		if (ret)
+			return ret;
+	}
 
 	request->seqno = intel_ring_get_seqno(ring);
 	request->ring = ring;
@@ -2370,12 +2389,14 @@ int __i915_add_request(struct intel_engine_cs *ring,
 	 */
 	request->batch_obj = obj;
 
-	/* Hold a reference to the current context so that we can inspect
-	 * it later in case a hangcheck error event fires.
-	 */
-	request->ctx = ring->last_context;
-	if (request->ctx)
-		i915_gem_context_reference(request->ctx);
+	if (!i915.enable_execlists) {
+		/* Hold a reference to the current context so that we can inspect
+		 * it later in case a hangcheck error event fires.
+		 */
+		request->ctx = ring->last_context;
+		if (request->ctx)
+			i915_gem_context_reference(request->ctx);
+	}
 
 	request->emitted_jiffies = jiffies;
 	list_add_tail(&request->list, &ring->request_list);
@@ -2630,6 +2651,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
 	while (!list_empty(&ring->request_list)) {
 		struct drm_i915_gem_request *request;
+		struct intel_ringbuffer *ringbuf;
 
 		request = list_first_entry(&ring->request_list,
 					   struct drm_i915_gem_request,
@@ -2639,12 +2661,24 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 			break;
 
 		trace_i915_gem_request_retire(ring, request->seqno);
+
+		/* This is one of the few common intersection points
+		 * between legacy ringbuffer submission and execlists:
+		 * we need to tell them apart in order to find the correct
+		 * ringbuffer to which the request belongs to.
+		 */
+		if (i915.enable_execlists) {
+			struct intel_context *ctx = request->ctx;
+			ringbuf = ctx->engine[ring->id].ringbuf;
+		} else
+			ringbuf = ring->buffer;
+
 		/* We know the GPU must have read the request to have
 		 * sent us the seqno + interrupt, so use the position
 		 * of tail of the request to update the last known position
 		 * of the GPU head.
 		 */
-		ring->buffer->last_retired_head = request->tail;
+		ringbuf->last_retired_head = request->tail;
 
 		i915_gem_free_request(request);
 	}
drivers/gpu/drm/i915/intel_lrc.c +26 -4
index 5dd63d6..dcf59c6 100644
@@ -106,6 +106,22 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring)
 	/* TODO */
 }
 
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	int ret;
+
+	if (!ring->gpu_caches_dirty)
+		return 0;
+
+	ret = ring->emit_flush(ringbuf, 0, I915_GEM_GPU_DOMAINS);
+	if (ret)
+		return ret;
+
+	ring->gpu_caches_dirty = false;
+	return 0;
+}
+
 void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
 {
 	intel_logical_ring_advance(ringbuf);
@@ -116,7 +132,8 @@ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
 	/* TODO: how to submit a context to the ELSP is not here yet */
 }
 
-static int logical_ring_alloc_seqno(struct intel_engine_cs *ring)
+static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
+				    struct intel_context *ctx)
 {
 	if (ring->outstanding_lazy_seqno)
 		return 0;
@@ -128,6 +145,13 @@ static int logical_ring_alloc_seqno(struct intel_engine_cs *ring)
 		if (request == NULL)
 			return -ENOMEM;
 
+		/* Hold a reference to the context this request belongs to
+		 * (we will need it when the time comes to emit/retire the
+		 * request).
+		 */
+		request->ctx = ctx;
+		i915_gem_context_reference(request->ctx);
+
 		ring->preallocated_lazy_request = request;
 	}
 
@@ -165,8 +189,6 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, int bytes
 	if (ret)
 		return ret;
 
-	/* TODO: make sure we update the right ringbuffer's last_retired_head
-	 * when retiring requests */
 	i915_gem_retire_requests_ring(ring);
 	ringbuf->head = ringbuf->last_retired_head;
 	ringbuf->last_retired_head = -1;
@@ -291,7 +313,7 @@ int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
 		return ret;
 
 	/* Preallocate the olr before touching the ring */
-	ret = logical_ring_alloc_seqno(ring);
+	ret = logical_ring_alloc_seqno(ring, ringbuf->ctx);
 	if (ret)
 		return ret;
 
drivers/gpu/drm/i915/intel_lrc.h +1 -0
index 16798b6..696e09e 100644
@@ -29,6 +29,7 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring);
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring);
 int intel_logical_rings_init(struct drm_device *dev);
 
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf);
 void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf);
 static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf)
 {
Signature · 1 line
1.7.9.5
#63 lore raw

Re: [PATCH 21/43] drm/i915/bdw: Emission of requests with logical rings

Quoted 6 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

On a previous iteration of this patch, I created an Execlists version of __i915_add_request and asbtracted it away as a vfunc. Daniel Vetter wondered then why that was needed:

Quoted 7 lines

"with the clean split in command submission I expect every function to know wether it'll submit to an lrc (everything in intel_lrc.c) or wether it'll submit to a legacy ring (existing code), so I don't see a need for an add_request vfunc."

The honest, hairy truth is that this patch is the glue keeping the whole logical ring puzzle together:

Oops, I didn't spot this and it's indeed not terribly pretty.

Quoted 4 lines

- i915_add_request is used by intel_ring_idle, which in turn is used by i915_gpu_idle, which in turn is used in several places inside the eviction and gtt codes.

This should probably be folded in with the lrc specific version of stop_rings and so should work out.

Quoted 2 lines

- Also, it is used by i915_gem_check_olr, which is littered all over i915_gem.c

We now always preallocate the request struct, so olr is officially dead. Well almost, except for non-execbuf stuff that we emit through the rings. Which is nothing for lrc/execlist mode.

Also there's the icky-bitty problem with ringbuf->ctx which makes this patch not apply any more. I think we need to revise or at least discuss a bit.

Quoted 204 lines

- ...

If I were to duplicate all the code that directly or indirectly uses __i915_add_request, I'll end up creating a separate driver.

To show the differences between the existing legacy version and the new Execlists one, this time I have special-cased __i915_add_request instead of adding an add_request vfunc. I hope this helps to untangle this Gordian knot.

---
 drivers/gpu/drm/i915/i915_gem.c  |   72 ++++++++++++++++++++++++++++----------
 drivers/gpu/drm/i915/intel_lrc.c |   30 +++++++++++++---
 drivers/gpu/drm/i915/intel_lrc.h |    1 +
 3 files changed, 80 insertions(+), 23 deletions(-)
drivers/gpu/drm/i915/i915_gem.c +53 -19
index 9560b40..1c83b9c 100644
@@ -2327,10 +2327,21 @@ int __i915_add_request(struct intel_engine_cs *ring,
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	struct drm_i915_gem_request *request;
+	struct intel_ringbuffer *ringbuf;
 	u32 request_ring_position, request_start;
 	int ret;
 
-	request_start = intel_ring_get_tail(ring->buffer);
+	request = ring->preallocated_lazy_request;
+	if (WARN_ON(request == NULL))
+		return -ENOMEM;
+
+	if (i915.enable_execlists) {
+		struct intel_context *ctx = request->ctx;
+		ringbuf = ctx->engine[ring->id].ringbuf;
+	} else
+		ringbuf = ring->buffer;
+
+	request_start = intel_ring_get_tail(ringbuf);
 	/*
 	 * Emit any outstanding flushes - execbuf can fail to emit the flush
 	 * after having emitted the batchbuffer command. Hence we need to fix
@@ -2338,24 +2349,32 @@ int __i915_add_request(struct intel_engine_cs *ring,
 	 * is that the flush _must_ happen before the next request, no matter
 	 * what.
 	 */
-	ret = intel_ring_flush_all_caches(ring);
-	if (ret)
-		return ret;
-
-	request = ring->preallocated_lazy_request;
-	if (WARN_ON(request == NULL))
-		return -ENOMEM;
+	if (i915.enable_execlists) {
+		ret = logical_ring_flush_all_caches(ringbuf);
+		if (ret)
+			return ret;
+	} else {
+		ret = intel_ring_flush_all_caches(ring);
+		if (ret)
+			return ret;
+	}
 
 	/* Record the position of the start of the request so that
 	 * should we detect the updated seqno part-way through the
 	 * GPU processing the request, we never over-estimate the
 	 * position of the head.
 	 */
-	request_ring_position = intel_ring_get_tail(ring->buffer);
+	request_ring_position = intel_ring_get_tail(ringbuf);
 
-	ret = ring->add_request(ring);
-	if (ret)
-		return ret;
+	if (i915.enable_execlists) {
+		ret = ring->emit_request(ringbuf);
+		if (ret)
+			return ret;
+	} else {
+		ret = ring->add_request(ring);
+		if (ret)
+			return ret;
+	}
 
 	request->seqno = intel_ring_get_seqno(ring);
 	request->ring = ring;
@@ -2370,12 +2389,14 @@ int __i915_add_request(struct intel_engine_cs *ring,
 	 */
 	request->batch_obj = obj;
 
-	/* Hold a reference to the current context so that we can inspect
-	 * it later in case a hangcheck error event fires.
-	 */
-	request->ctx = ring->last_context;
-	if (request->ctx)
-		i915_gem_context_reference(request->ctx);
+	if (!i915.enable_execlists) {
+		/* Hold a reference to the current context so that we can inspect
+		 * it later in case a hangcheck error event fires.
+		 */
+		request->ctx = ring->last_context;
+		if (request->ctx)
+			i915_gem_context_reference(request->ctx);
+	}
 
 	request->emitted_jiffies = jiffies;
 	list_add_tail(&request->list, &ring->request_list);
@@ -2630,6 +2651,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
 	while (!list_empty(&ring->request_list)) {
 		struct drm_i915_gem_request *request;
+		struct intel_ringbuffer *ringbuf;
 
 		request = list_first_entry(&ring->request_list,
 					   struct drm_i915_gem_request,
@@ -2639,12 +2661,24 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 			break;
 
 		trace_i915_gem_request_retire(ring, request->seqno);
+
+		/* This is one of the few common intersection points
+		 * between legacy ringbuffer submission and execlists:
+		 * we need to tell them apart in order to find the correct
+		 * ringbuffer to which the request belongs to.
+		 */
+		if (i915.enable_execlists) {
+			struct intel_context *ctx = request->ctx;
+			ringbuf = ctx->engine[ring->id].ringbuf;
+		} else
+			ringbuf = ring->buffer;
+
 		/* We know the GPU must have read the request to have
 		 * sent us the seqno + interrupt, so use the position
 		 * of tail of the request to update the last known position
 		 * of the GPU head.
 		 */
-		ring->buffer->last_retired_head = request->tail;
+		ringbuf->last_retired_head = request->tail;
 
 		i915_gem_free_request(request);
 	}
drivers/gpu/drm/i915/intel_lrc.c +25 -3
index 5dd63d6..dcf59c6 100644
@@ -106,6 +106,22 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring)
 	/* TODO */
 }
 
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	int ret;
+
+	if (!ring->gpu_caches_dirty)
+		return 0;
+
+	ret = ring->emit_flush(ringbuf, 0, I915_GEM_GPU_DOMAINS);
+	if (ret)
+		return ret;
+
+	ring->gpu_caches_dirty = false;
+	return 0;
+}
+
 void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
 {
 	intel_logical_ring_advance(ringbuf);
@@ -116,7 +132,8 @@ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
 	/* TODO: how to submit a context to the ELSP is not here yet */
 }
 
-static int logical_ring_alloc_seqno(struct intel_engine_cs *ring)
+static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
+				    struct intel_context *ctx)
 {
 	if (ring->outstanding_lazy_seqno)
 		return 0;
@@ -128,6 +145,13 @@ static int logical_ring_alloc_seqno(struct intel_engine_cs *ring)
 		if (request == NULL)
 			return -ENOMEM;
 
+		/* Hold a reference to the context this request belongs to
+		 * (we will need it when the time comes to emit/retire the
+		 * request).
+		 */
+		request->ctx = ctx;
+		i915_gem_context_reference(request->ctx);
+
 		ring->preallocated_lazy_request = request;
 	}
 
@@ -165,8 +189,6 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, int bytes
 	if (ret)
 		return ret;
 
-	/* TODO: make sure we update the right ringbuffer's last_retired_head
-	 * when retiring requests */
 	i915_gem_retire_requests_ring(ring);
 	ringbuf->head = ringbuf->last_retired_head;
 	ringbuf->last_retired_head = -1;

drivers/gpu/drm/i915/intel_lrc.c int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords) · line 316

Quoted 5 lines
drivers/gpu/drm/i915/intel_lrc.c +1 -1
@@ -291,7 +313,7 @@ int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
 		return ret;
 
 	/* Preallocate the olr before touching the ring */
-	ret = logical_ring_alloc_seqno(ring);
+	ret = logical_ring_alloc_seqno(ring, ringbuf->ctx);

Ok, this is hairy. Really hairy, since this uses ringbuf->ctx. Not sure we really want this or need this.

Quoted 22 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -0
 	if (ret)
 		return ret;
 
drivers/gpu/drm/i915/intel_lrc.h +1 -0
index 16798b6..696e09e 100644
@@ -29,6 +29,7 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring);
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring);
 int intel_logical_rings_init(struct drm_device *dev);
 
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf);
 void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf);
 static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf)
 {
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#64 lore raw

Re: [PATCH 21/43] drm/i915/bdw: Emission of requests with logical rings

Quoted 23 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 9:57 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 21/43] drm/i915/bdw: Emission of requests with logical rings

Quoted 11 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

On a previous iteration of this patch, I created an Execlists version of __i915_add_request and asbtracted it away as a vfunc. Daniel Vetter wondered then why that was needed:

"with the clean split in command submission I expect every function to know wether it'll submit to an lrc (everything in intel_lrc.c) or wether it'll submit to a legacy ring (existing code), so I don't see a need for an add_request vfunc."

Quoted 4 lines
Quoted 2 lines

The honest, hairy truth is that this patch is the glue keeping the whole logical ring puzzle together:

Oops, I didn't spot this and it's indeed not terribly pretty.

Are you saying you want to go back to a vfunc for add_request?

Quoted 11 lines
Quoted 4 lines

- i915_add_request is used by intel_ring_idle, which in turn is used by i915_gpu_idle, which in turn is used in several places inside the eviction and gtt codes.

This should probably be folded in with the lrc specific version of stop_rings and so should work out.

Quoted 2 lines

- Also, it is used by i915_gem_check_olr, which is littered all over i915_gem.c

Quoted 7 lines

We now always preallocate the request struct, so olr is officially dead. Well almost, except for non-execbuf stuff that we emit through the rings. Which is nothing for lrc/execlist mode.

Also there's the icky-bitty problem with ringbuf->ctx which makes this patch not apply any more. I think we need to revise or at least discuss a bit.

Context is required when doing an advance_and_submit so that we know which context to queue in the execlist queue.

Quoted 215 lines
Quoted 5 lines

- ...

If I were to duplicate all the code that directly or indirectly uses __i915_add_request, I'll end up creating a separate driver.

Quoted 8 lines

To show the differences between the existing legacy version and the new Execlists one, this time I have special-cased __i915_add_request instead of adding an add_request vfunc. I hope this helps to untangle this Gordian knot.

---
 drivers/gpu/drm/i915/i915_gem.c  |   72

++++++++++++++++++++++++++++----------

Quoted 31 lines
 drivers/gpu/drm/i915/intel_lrc.c |   30 +++++++++++++---
 drivers/gpu/drm/i915/intel_lrc.h |    1 +
 3 files changed, 80 insertions(+), 23 deletions(-)
(quoted diff) +0 -0

b/drivers/gpu/drm/i915/i915_gem.c index 9560b40..1c83b9c 100644

drivers/gpu/drm/i915/i915_gem.c +12 -1
@@ -2327,10 +2327,21 @@ int __i915_add_request(struct intel_engine_cs
 *ring,  {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	struct drm_i915_gem_request *request;
+	struct intel_ringbuffer *ringbuf;
 	u32 request_ring_position, request_start;
 	int ret;
 
-	request_start = intel_ring_get_tail(ring->buffer);
+	request = ring->preallocated_lazy_request;
+	if (WARN_ON(request == NULL))
+		return -ENOMEM;
+
+	if (i915.enable_execlists) {
+		struct intel_context *ctx = request->ctx;
+		ringbuf = ctx->engine[ring->id].ringbuf;
+	} else
+		ringbuf = ring->buffer;
+
+	request_start = intel_ring_get_tail(ringbuf);
 	/*
 	 * Emit any outstanding flushes - execbuf can fail to emit the flush
 	 * after having emitted the batchbuffer command. Hence we need to
Quoted 1 line

fix @@ -2338,24 +2349,32 @@ int __i915_add_request(struct

intel_engine_cs *ring,

Quoted 1 line

* is that the flush _must_ happen before the next request, no

matter

drivers/gpu/drm/i915/i915_gem.c int __i915_add_request(struct intel_engine_cs

Quoted 43 lines
drivers/gpu/drm/i915/i915_gem.c +19 -11
 	 * what.
 	 */
-	ret = intel_ring_flush_all_caches(ring);
-	if (ret)
-		return ret;
-
-	request = ring->preallocated_lazy_request;
-	if (WARN_ON(request == NULL))
-		return -ENOMEM;
+	if (i915.enable_execlists) {
+		ret = logical_ring_flush_all_caches(ringbuf);
+		if (ret)
+			return ret;
+	} else {
+		ret = intel_ring_flush_all_caches(ring);
+		if (ret)
+			return ret;
+	}
 
 	/* Record the position of the start of the request so that
 	 * should we detect the updated seqno part-way through the
 	 * GPU processing the request, we never over-estimate the
 	 * position of the head.
 	 */
-	request_ring_position = intel_ring_get_tail(ring->buffer);
+	request_ring_position = intel_ring_get_tail(ringbuf);
 
-	ret = ring->add_request(ring);
-	if (ret)
-		return ret;
+	if (i915.enable_execlists) {
+		ret = ring->emit_request(ringbuf);
+		if (ret)
+			return ret;
+	} else {
+		ret = ring->add_request(ring);
+		if (ret)
+			return ret;
+	}
 
 	request->seqno = intel_ring_get_seqno(ring);
 	request->ring = ring;
@@ -2370,12 +2389,14 @@ int __i915_add_request(struct intel_engine_cs

*ring,

drivers/gpu/drm/i915/i915_gem.c int __i915_add_request(struct intel_engine_cs *ring,

Quoted 11 lines
drivers/gpu/drm/i915/i915_gem.c +2 -6
 	 */
 	request->batch_obj = obj;
 
-	/* Hold a reference to the current context so that we can inspect
-	 * it later in case a hangcheck error event fires.
-	 */
-	request->ctx = ring->last_context;
-	if (request->ctx)
-		i915_gem_context_reference(request->ctx);
+	if (!i915.enable_execlists) {
+		/* Hold a reference to the current context so that we can

inspect

drivers/gpu/drm/i915/i915_gem.c i915_gem_retire_requests_ring(struct

Quoted 18 lines
drivers/gpu/drm/i915/i915_gem.c +8 -0
+		 * it later in case a hangcheck error event fires.
+		 */
+		request->ctx = ring->last_context;
+		if (request->ctx)
+			i915_gem_context_reference(request->ctx);
+	}
 
 	request->emitted_jiffies = jiffies;
 	list_add_tail(&request->list, &ring->request_list); @@ -2630,6
+2651,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
 	while (!list_empty(&ring->request_list)) {
 		struct drm_i915_gem_request *request;
+		struct intel_ringbuffer *ringbuf;
 
 		request = list_first_entry(&ring->request_list,
 					   struct drm_i915_gem_request,
@@ -2639,12 +2661,24 @@ i915_gem_retire_requests_ring(struct

intel_engine_cs *ring)

drivers/gpu/drm/i915/intel_lrc.c void intel_logical_ring_stop(struct intel_engine_cs

Quoted 31 lines
drivers/gpu/drm/i915/i915_gem.c +13 -1
 			break;
 
 		trace_i915_gem_request_retire(ring, request->seqno);
+
+		/* This is one of the few common intersection points
+		 * between legacy ringbuffer submission and execlists:
+		 * we need to tell them apart in order to find the correct
+		 * ringbuffer to which the request belongs to.
+		 */
+		if (i915.enable_execlists) {
+			struct intel_context *ctx = request->ctx;
+			ringbuf = ctx->engine[ring->id].ringbuf;
+		} else
+			ringbuf = ring->buffer;
+
 		/* We know the GPU must have read the request to have
 		 * sent us the seqno + interrupt, so use the position
 		 * of tail of the request to update the last known position
 		 * of the GPU head.
 		 */
-		ring->buffer->last_retired_head = request->tail;
+		ringbuf->last_retired_head = request->tail;
 
 		i915_gem_free_request(request);
 	}
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index 5dd63d6..dcf59c6 100644
@@ -106,6 +106,22 @@ void intel_logical_ring_stop(struct intel_engine_cs

*ring)

drivers/gpu/drm/i915/intel_lrc.c void intel_logical_ring_advance_and_submit(struct

Quoted 22 lines
drivers/gpu/drm/i915/intel_lrc.c +15 -0
 	/* TODO */
 }
 
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf) {
+	struct intel_engine_cs *ring = ringbuf->ring;
+	int ret;
+
+	if (!ring->gpu_caches_dirty)
+		return 0;
+
+	ret = ring->emit_flush(ringbuf, 0, I915_GEM_GPU_DOMAINS);
+	if (ret)
+		return ret;
+
+	ring->gpu_caches_dirty = false;
+	return 0;
+}
+
 void intel_logical_ring_advance_and_submit(struct intel_ringbuffer
 *ringbuf)  {
 	intel_logical_ring_advance(ringbuf);
@@ -116,7 +132,8 @@ void intel_logical_ring_advance_and_submit(struct

intel_ringbuffer *ringbuf)

drivers/gpu/drm/i915/intel_lrc.c static int logical_ring_alloc_seqno(struct

Quoted 9 lines
drivers/gpu/drm/i915/intel_lrc.c +2 -1
 	/* TODO: how to submit a context to the ELSP is not here yet */  }
 
-static int logical_ring_alloc_seqno(struct intel_engine_cs *ring)
+static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
+				    struct intel_context *ctx)
 {
 	if (ring->outstanding_lazy_seqno)
 		return 0;
@@ -128,6 +145,13 @@ static int logical_ring_alloc_seqno(struct

intel_engine_cs *ring)

drivers/gpu/drm/i915/intel_lrc.c static int logical_ring_wait_request(struct

Quoted 14 lines
drivers/gpu/drm/i915/intel_lrc.c +7 -0
 		if (request == NULL)
 			return -ENOMEM;
 
+		/* Hold a reference to the context this request belongs to
+		 * (we will need it when the time comes to emit/retire the
+		 * request).
+		 */
+		request->ctx = ctx;
+		i915_gem_context_reference(request->ctx);
+
 		ring->preallocated_lazy_request = request;
 	}
 
@@ -165,8 +189,6 @@ static int logical_ring_wait_request(struct

intel_ringbuffer *ringbuf, int bytes

drivers/gpu/drm/i915/intel_lrc.c static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, int bytes

Quoted 4 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -1
 	if (ret)
 		return ret;
 
-	/* TODO: make sure we update the right ringbuffer's

last_retired_head

drivers/gpu/drm/i915/intel_lrc.c int intel_logical_ring_begin(struct intel_ringbuffer

Quoted 5 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -1
-	 * when retiring requests */
 	i915_gem_retire_requests_ring(ring);
 	ringbuf->head = ringbuf->last_retired_head;
 	ringbuf->last_retired_head = -1;
@@ -291,7 +313,7 @@ int intel_logical_ring_begin(struct intel_ringbuffer

*ringbuf, int num_dwords)

Quoted 9 lines

drivers/gpu/drm/i915/intel_lrc.c int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords) · line 316

Quoted 5 lines
drivers/gpu/drm/i915/intel_lrc.c +1 -1
 		return ret;
 
 	/* Preallocate the olr before touching the ring */
-	ret = logical_ring_alloc_seqno(ring);
+	ret = logical_ring_alloc_seqno(ring, ringbuf->ctx);

Ok, this is hairy. Really hairy, since this uses ringbuf->ctx. Not sure we really want this or need this.

alloc_seqno needs to know the context since it also preallocates and populates the request, which belongs to a specific context. Having the logical context pointer inside the ring buffer makes the code a lot more elegant imo, since we don't have to keep passing buffer and context around when there is only one context which can use each ring buffer, just as keeping the engine pointer in the ring buffer means we don't have to pass the engine with it.

As I said in my reply to your patch 8 review I'm happy for ctx to be renamed to avoid confusion in the legacy path

Thomas.

Quoted 28 lines
Quoted 19 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -0
 	if (ret)
 		return ret;
 
drivers/gpu/drm/i915/intel_lrc.h +1 -1
index 16798b6..696e09e 100644
@@ -29,6 +29,7 @@ void intel_logical_ring_stop(struct intel_engine_cs
 *ring);  void intel_logical_ring_cleanup(struct intel_engine_cs
 *ring);  int intel_logical_rings_init(struct drm_device *dev);
 
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf);
 void intel_logical_ring_advance_and_submit(struct intel_ringbuffer
 *ringbuf);  static inline void intel_logical_ring_advance(struct
 intel_ringbuffer *ringbuf)  {
--

1.7.9.5

Quoted 4 lines

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#65 lore raw

Re: [PATCH 21/43] drm/i915/bdw: Emission of requests with logical rings

Quoted 23 lines · Thomas
Quoted 23 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 9:57 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 21/43] drm/i915/bdw: Emission of requests with logical rings

Quoted 11 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

On a previous iteration of this patch, I created an Execlists version of __i915_add_request and asbtracted it away as a vfunc. Daniel Vetter wondered then why that was needed:

"with the clean split in command submission I expect every function to know wether it'll submit to an lrc (everything in intel_lrc.c) or wether it'll submit to a legacy ring (existing code), so I don't see a need for an add_request vfunc."

Quoted 5 lines
Quoted 4 lines
Quoted 2 lines

The honest, hairy truth is that this patch is the glue keeping the whole logical ring puzzle together:

Oops, I didn't spot this and it's indeed not terribly pretty.

Are you saying you want to go back to a vfunc for add_request?

Nope, I'd have expected that there's no need for such a switch at all, and that all these differences disappear behind the execbuf cmd submission abstraction.

Quoted 14 lines
Quoted 14 lines
Quoted 3 lines

- i915_add_request is used by intel_ring_idle, which in turn is used by i915_gpu_idle, which in turn is used in several places inside the eviction and gtt codes.

This should probably be folded in with the lrc specific version of stop_rings and so should work out.

Quoted 2 lines

- Also, it is used by i915_gem_check_olr, which is littered all over i915_gem.c

We now always preallocate the request struct, so olr is officially dead. Well almost, except for non-execbuf stuff that we emit through the rings. Which is nothing for lrc/execlist mode.

Quoted 5 lines
Quoted 3 lines

Also there's the icky-bitty problem with ringbuf->ctx which makes this patch not apply any more. I think we need to revise or at least discuss a bit.

Context is required when doing an advance_and_submit so that we know which context to queue in the execlist queue.

Might need to re-read, but imo it's not a good idea to do a submit in there. If I understand this correctly there should only be a need for an ELSP write (or queueing it up) at the end of the execlist-specific cmd submission implementation. The ringbuffer writes we do before that for the different pieces (flushes, seqno write, bb_start, whatever) should just update the tail pointer in the ring.

Or do I miss something really big here?

Quoted 233 lines
Quoted 216 lines
Quoted 6 lines

- ...

If I were to duplicate all the code that directly or indirectly uses __i915_add_request, I'll end up creating a separate driver.

Quoted 8 lines

To show the differences between the existing legacy version and the new Execlists one, this time I have special-cased __i915_add_request instead of adding an add_request vfunc. I hope this helps to untangle this Gordian knot.

---
 drivers/gpu/drm/i915/i915_gem.c  |   72

++++++++++++++++++++++++++++----------

Quoted 31 lines
 drivers/gpu/drm/i915/intel_lrc.c |   30 +++++++++++++---
 drivers/gpu/drm/i915/intel_lrc.h |    1 +
 3 files changed, 80 insertions(+), 23 deletions(-)
(quoted diff) +0 -0

b/drivers/gpu/drm/i915/i915_gem.c index 9560b40..1c83b9c 100644

drivers/gpu/drm/i915/i915_gem.c +12 -1
@@ -2327,10 +2327,21 @@ int __i915_add_request(struct intel_engine_cs
 *ring,  {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	struct drm_i915_gem_request *request;
+	struct intel_ringbuffer *ringbuf;
 	u32 request_ring_position, request_start;
 	int ret;
 
-	request_start = intel_ring_get_tail(ring->buffer);
+	request = ring->preallocated_lazy_request;
+	if (WARN_ON(request == NULL))
+		return -ENOMEM;
+
+	if (i915.enable_execlists) {
+		struct intel_context *ctx = request->ctx;
+		ringbuf = ctx->engine[ring->id].ringbuf;
+	} else
+		ringbuf = ring->buffer;
+
+	request_start = intel_ring_get_tail(ringbuf);
 	/*
 	 * Emit any outstanding flushes - execbuf can fail to emit the flush
 	 * after having emitted the batchbuffer command. Hence we need to
Quoted 1 line

fix @@ -2338,24 +2349,32 @@ int __i915_add_request(struct

intel_engine_cs *ring,

Quoted 1 line

* is that the flush _must_ happen before the next request, no

matter

drivers/gpu/drm/i915/i915_gem.c int __i915_add_request(struct intel_engine_cs

Quoted 43 lines
drivers/gpu/drm/i915/i915_gem.c +19 -11
 	 * what.
 	 */
-	ret = intel_ring_flush_all_caches(ring);
-	if (ret)
-		return ret;
-
-	request = ring->preallocated_lazy_request;
-	if (WARN_ON(request == NULL))
-		return -ENOMEM;
+	if (i915.enable_execlists) {
+		ret = logical_ring_flush_all_caches(ringbuf);
+		if (ret)
+			return ret;
+	} else {
+		ret = intel_ring_flush_all_caches(ring);
+		if (ret)
+			return ret;
+	}
 
 	/* Record the position of the start of the request so that
 	 * should we detect the updated seqno part-way through the
 	 * GPU processing the request, we never over-estimate the
 	 * position of the head.
 	 */
-	request_ring_position = intel_ring_get_tail(ring->buffer);
+	request_ring_position = intel_ring_get_tail(ringbuf);
 
-	ret = ring->add_request(ring);
-	if (ret)
-		return ret;
+	if (i915.enable_execlists) {
+		ret = ring->emit_request(ringbuf);
+		if (ret)
+			return ret;
+	} else {
+		ret = ring->add_request(ring);
+		if (ret)
+			return ret;
+	}
 
 	request->seqno = intel_ring_get_seqno(ring);
 	request->ring = ring;
@@ -2370,12 +2389,14 @@ int __i915_add_request(struct intel_engine_cs

*ring,

drivers/gpu/drm/i915/i915_gem.c int __i915_add_request(struct intel_engine_cs *ring,

Quoted 11 lines
drivers/gpu/drm/i915/i915_gem.c +2 -6
 	 */
 	request->batch_obj = obj;
 
-	/* Hold a reference to the current context so that we can inspect
-	 * it later in case a hangcheck error event fires.
-	 */
-	request->ctx = ring->last_context;
-	if (request->ctx)
-		i915_gem_context_reference(request->ctx);
+	if (!i915.enable_execlists) {
+		/* Hold a reference to the current context so that we can

inspect

drivers/gpu/drm/i915/i915_gem.c i915_gem_retire_requests_ring(struct

Quoted 18 lines
drivers/gpu/drm/i915/i915_gem.c +8 -0
+		 * it later in case a hangcheck error event fires.
+		 */
+		request->ctx = ring->last_context;
+		if (request->ctx)
+			i915_gem_context_reference(request->ctx);
+	}
 
 	request->emitted_jiffies = jiffies;
 	list_add_tail(&request->list, &ring->request_list); @@ -2630,6
+2651,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
 	while (!list_empty(&ring->request_list)) {
 		struct drm_i915_gem_request *request;
+		struct intel_ringbuffer *ringbuf;
 
 		request = list_first_entry(&ring->request_list,
 					   struct drm_i915_gem_request,
@@ -2639,12 +2661,24 @@ i915_gem_retire_requests_ring(struct

intel_engine_cs *ring)

drivers/gpu/drm/i915/intel_lrc.c void intel_logical_ring_stop(struct intel_engine_cs

Quoted 31 lines
drivers/gpu/drm/i915/i915_gem.c +13 -1
 			break;
 
 		trace_i915_gem_request_retire(ring, request->seqno);
+
+		/* This is one of the few common intersection points
+		 * between legacy ringbuffer submission and execlists:
+		 * we need to tell them apart in order to find the correct
+		 * ringbuffer to which the request belongs to.
+		 */
+		if (i915.enable_execlists) {
+			struct intel_context *ctx = request->ctx;
+			ringbuf = ctx->engine[ring->id].ringbuf;
+		} else
+			ringbuf = ring->buffer;
+
 		/* We know the GPU must have read the request to have
 		 * sent us the seqno + interrupt, so use the position
 		 * of tail of the request to update the last known position
 		 * of the GPU head.
 		 */
-		ring->buffer->last_retired_head = request->tail;
+		ringbuf->last_retired_head = request->tail;
 
 		i915_gem_free_request(request);
 	}
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index 5dd63d6..dcf59c6 100644
@@ -106,6 +106,22 @@ void intel_logical_ring_stop(struct intel_engine_cs

*ring)

drivers/gpu/drm/i915/intel_lrc.c void intel_logical_ring_advance_and_submit(struct

Quoted 22 lines
drivers/gpu/drm/i915/intel_lrc.c +15 -0
 	/* TODO */
 }
 
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf) {
+	struct intel_engine_cs *ring = ringbuf->ring;
+	int ret;
+
+	if (!ring->gpu_caches_dirty)
+		return 0;
+
+	ret = ring->emit_flush(ringbuf, 0, I915_GEM_GPU_DOMAINS);
+	if (ret)
+		return ret;
+
+	ring->gpu_caches_dirty = false;
+	return 0;
+}
+
 void intel_logical_ring_advance_and_submit(struct intel_ringbuffer
 *ringbuf)  {
 	intel_logical_ring_advance(ringbuf);
@@ -116,7 +132,8 @@ void intel_logical_ring_advance_and_submit(struct

intel_ringbuffer *ringbuf)

drivers/gpu/drm/i915/intel_lrc.c static int logical_ring_alloc_seqno(struct

Quoted 9 lines
drivers/gpu/drm/i915/intel_lrc.c +2 -1
 	/* TODO: how to submit a context to the ELSP is not here yet */  }
 
-static int logical_ring_alloc_seqno(struct intel_engine_cs *ring)
+static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
+				    struct intel_context *ctx)
 {
 	if (ring->outstanding_lazy_seqno)
 		return 0;
@@ -128,6 +145,13 @@ static int logical_ring_alloc_seqno(struct

intel_engine_cs *ring)

drivers/gpu/drm/i915/intel_lrc.c static int logical_ring_wait_request(struct

Quoted 14 lines
drivers/gpu/drm/i915/intel_lrc.c +7 -0
 		if (request == NULL)
 			return -ENOMEM;
 
+		/* Hold a reference to the context this request belongs to
+		 * (we will need it when the time comes to emit/retire the
+		 * request).
+		 */
+		request->ctx = ctx;
+		i915_gem_context_reference(request->ctx);
+
 		ring->preallocated_lazy_request = request;
 	}
 
@@ -165,8 +189,6 @@ static int logical_ring_wait_request(struct

intel_ringbuffer *ringbuf, int bytes

drivers/gpu/drm/i915/intel_lrc.c static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf, int bytes

Quoted 4 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -1
 	if (ret)
 		return ret;
 
-	/* TODO: make sure we update the right ringbuffer's

last_retired_head

drivers/gpu/drm/i915/intel_lrc.c int intel_logical_ring_begin(struct intel_ringbuffer

Quoted 5 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -1
-	 * when retiring requests */
 	i915_gem_retire_requests_ring(ring);
 	ringbuf->head = ringbuf->last_retired_head;
 	ringbuf->last_retired_head = -1;
@@ -291,7 +313,7 @@ int intel_logical_ring_begin(struct intel_ringbuffer

*ringbuf, int num_dwords)

Quoted 9 lines

drivers/gpu/drm/i915/intel_lrc.c int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords) · line 316

Quoted 5 lines
drivers/gpu/drm/i915/intel_lrc.c +1 -1
 		return ret;
 
 	/* Preallocate the olr before touching the ring */
-	ret = logical_ring_alloc_seqno(ring);
+	ret = logical_ring_alloc_seqno(ring, ringbuf->ctx);

Ok, this is hairy. Really hairy, since this uses ringbuf->ctx. Not sure we really want this or need this.

alloc_seqno needs to know the context since it also preallocates and populates the request, which belongs to a specific context. Having the logical context pointer inside the ring buffer makes the code a lot more elegant imo, since we don't have to keep passing buffer and context around when there is only one context which can use each ring buffer, just as keeping the engine pointer in the ring buffer means we don't have to pass the engine with it.

Quoted 2 lines

As I said in my reply to your patch 8 review I'm happy for ctx to be renamed to avoid confusion in the legacy path

Well I'm not yet sold on whether we need it at all. For this case here doing the request allocation deeply buried in the ring_begin function isn't pretty. It's an artifact of 5 years of engineering history for the legacy gem codepaths essentially, and with execlists (and the new explicitly fenced world everyone wants to have) I don't think it's a sound decision any more.

Imo for execlist it would make a lot more sense to do this request preallocation much higher up in the execlist cmd submission function. That's kinda one of the reasons I wanted that abstraction. It would be placed after all the prep work and argument checking is done right before we start to fill in new instructions into the lrc ring.

logical_ring_begin would then only have a
WARN_ON(!request_not_preallocated).

Cheers, Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#66 lore raw

PATCH 22/43 drm/i915/bdw: Ring idle and stop with logical rings

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

This is a hard one, since there is no direct hardware ring to control when in Execlists.

We reuse intel_ring_idle here, but it should be fine as long as i915_add_request does the ring thing.

---
 drivers/gpu/drm/i915/intel_lrc.c |   24 ++++++++++++++++++++++--
 1 file changed, 22 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +22 -2
index dcf59c6..c30518c 100644
@@ -103,7 +103,24 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
 
 void intel_logical_ring_stop(struct intel_engine_cs *ring)
 {
-	/* TODO */
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	int ret;
+
+	if (!intel_ring_initialized(ring))
+		return;
+
+	ret = intel_ring_idle(ring);
+	if (ret && !i915_reset_in_progress(&to_i915(ring->dev)->gpu_error))
+		DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
+			  ring->name, ret);
+
+	/* TODO: Is this correct with Execlists enabled? */
+	I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING));
+	if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) {
+		DRM_ERROR("%s :timed out trying to stop ring\n", ring->name);
+		return;
+	}
+	I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING));
 }
 
 int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
@@ -479,10 +496,13 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
 
 void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
 {
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
 	if (!intel_ring_initialized(ring))
 		return;
 
-	/* TODO: make sure the ring is stopped */
+	intel_logical_ring_stop(ring);
+	WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
 	ring->preallocated_lazy_request = NULL;
 	ring->outstanding_lazy_seqno = 0;
 
Signature · 1 line
1.7.9.5
#67 lore raw

PATCH 23/43 drm/i915/bdw: Interrupts with logical rings

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

We need to attend context switch interrupts from all rings. Also, fixed writing IMR/IER and added HWSTAM at ring init time.

Notice that, if added to irq_enable_mask, the context switch interrupts would be incorrectly masked out when the user interrupts are due to no users waiting on a sequence number. Therefore, this commit adds a bitmask of interrupts to be kept unmasked at all times.

v2: Disable HWSTAM, as suggested by Damien (nobody listens to these interrupts, anyway).

v3: Add new get/put_irq functions.

---
 drivers/gpu/drm/i915/i915_irq.c         |   19 ++++++++--
 drivers/gpu/drm/i915/i915_reg.h         |    3 ++
 drivers/gpu/drm/i915/intel_lrc.c        |   58 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    1 +
 4 files changed, 78 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/i915_irq.c +16 -3
index a38b5c3..f77a4ca 100644
@@ -1643,6 +1643,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 				notify_ring(dev, &dev_priv->ring[RCS]);
 			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");
 		} else
 			DRM_ERROR("The master control interrupt lied (GT0)!\n");
 	}
@@ -1655,9 +1657,13 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 			vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, &dev_priv->ring[VCS]);
+			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+				DRM_DEBUG_DRIVER("TODO: Context switch\n");
 			vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, &dev_priv->ring[VCS2]);
+			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+				DRM_DEBUG_DRIVER("TODO: Context switch\n");
 		} else
 			DRM_ERROR("The master control interrupt lied (GT1)!\n");
 	}
@@ -1681,6 +1687,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 			vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, &dev_priv->ring[VECS]);
+			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+				DRM_DEBUG_DRIVER("TODO: Context switch\n");
 		} else
 			DRM_ERROR("The master control interrupt lied (GT3)!\n");
 	}
@@ -3768,12 +3776,17 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
 	/* These are interrupts we'll toggle with the ring mask register */
 	uint32_t gt_interrupts[] = {
 		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
 			GT_RENDER_L3_PARITY_ERROR_INTERRUPT |
-			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
+			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
-			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
+			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
 		0,
-		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT
+		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT
 		};
 
 	for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++)
drivers/gpu/drm/i915/i915_reg.h +3 -0
index 70dddac..bfc0c01 100644
@@ -1062,6 +1062,7 @@ enum punit_power_well {
 #define RING_ACTHD_UDW(base)	((base)+0x5c)
 #define RING_NOPID(base)	((base)+0x94)
 #define RING_IMR(base)		((base)+0xa8)
+#define RING_HWSTAM(base)	((base)+0x98)
 #define RING_TIMESTAMP(base)	((base)+0x358)
 #define   TAIL_ADDR		0x001FFFF8
 #define   HEAD_WRAP_COUNT	0xFFE00000
@@ -4590,6 +4591,8 @@ enum punit_power_well {
 #define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
 #define GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
 
+#define GEN8_GT_CONTEXT_SWITCH_INTERRUPT	(1 <<  8)
+
 #define GEN8_BCS_IRQ_SHIFT 16
 #define GEN8_RCS_IRQ_SHIFT 0
 #define GEN8_VCS2_IRQ_SHIFT 16
drivers/gpu/drm/i915/intel_lrc.c +58 -0

130 lines not on this page · raw message

drivers/gpu/drm/i915/intel_ringbuffer.h +1 -0
index 6e22866..09102b2 100644
@@ -223,6 +223,7 @@ struct  intel_engine_cs {
 	} semaphore;
 
 	/* Execlists */
+	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
 				      u32 invalidate_domains,
Signature · 1 line
1.7.9.5
#68 lore raw

Re: [PATCH 23/43] drm/i915/bdw: Interrupts with logical rings

Quoted 10 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

We need to attend context switch interrupts from all rings. Also, fixed writing IMR/IER and added HWSTAM at ring init time.

Notice that, if added to irq_enable_mask, the context switch interrupts would be incorrectly masked out when the user interrupts are due to no users waiting on a sequence number. Therefore, this commit adds a bitmask of interrupts to be kept unmasked at all times.

Quoted 7 lines

v2: Disable HWSTAM, as suggested by Damien (nobody listens to these interrupts, anyway).

v3: Add new get/put_irq functions.

irq_keep_mask is a nifty idea, would be pretty to roll it out for legacy rings too. But totally optional.
-Daniel

Quoted 246 lines
---
 drivers/gpu/drm/i915/i915_irq.c         |   19 ++++++++--
 drivers/gpu/drm/i915/i915_reg.h         |    3 ++
 drivers/gpu/drm/i915/intel_lrc.c        |   58 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    1 +
 4 files changed, 78 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/i915_irq.c +16 -3
index a38b5c3..f77a4ca 100644
@@ -1643,6 +1643,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 				notify_ring(dev, &dev_priv->ring[RCS]);
 			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");
 		} else
 			DRM_ERROR("The master control interrupt lied (GT0)!\n");
 	}
@@ -1655,9 +1657,13 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 			vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, &dev_priv->ring[VCS]);
+			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+				DRM_DEBUG_DRIVER("TODO: Context switch\n");
 			vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, &dev_priv->ring[VCS2]);
+			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+				DRM_DEBUG_DRIVER("TODO: Context switch\n");
 		} else
 			DRM_ERROR("The master control interrupt lied (GT1)!\n");
 	}
@@ -1681,6 +1687,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 			vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, &dev_priv->ring[VECS]);
+			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+				DRM_DEBUG_DRIVER("TODO: Context switch\n");
 		} else
 			DRM_ERROR("The master control interrupt lied (GT3)!\n");
 	}
@@ -3768,12 +3776,17 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
 	/* These are interrupts we'll toggle with the ring mask register */
 	uint32_t gt_interrupts[] = {
 		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
 			GT_RENDER_L3_PARITY_ERROR_INTERRUPT |
-			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
+			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
-			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
+			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
 		0,
-		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT
+		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT
 		};
 
 	for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++)
drivers/gpu/drm/i915/i915_reg.h +3 -0
index 70dddac..bfc0c01 100644
@@ -1062,6 +1062,7 @@ enum punit_power_well {
 #define RING_ACTHD_UDW(base)	((base)+0x5c)
 #define RING_NOPID(base)	((base)+0x94)
 #define RING_IMR(base)		((base)+0xa8)
+#define RING_HWSTAM(base)	((base)+0x98)
 #define RING_TIMESTAMP(base)	((base)+0x358)
 #define   TAIL_ADDR		0x001FFFF8
 #define   HEAD_WRAP_COUNT	0xFFE00000
@@ -4590,6 +4591,8 @@ enum punit_power_well {
 #define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
 #define GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
 
+#define GEN8_GT_CONTEXT_SWITCH_INTERRUPT	(1 <<  8)
+
 #define GEN8_BCS_IRQ_SHIFT 16
 #define GEN8_RCS_IRQ_SHIFT 0
 #define GEN8_VCS2_IRQ_SHIFT 16
drivers/gpu/drm/i915/intel_lrc.c +58 -0
index c30518c..a6dcb3a 100644
@@ -343,6 +343,9 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring)
 	struct drm_device *dev = ring->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
+	I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff);
+
 	I915_WRITE(RING_MODE_GEN7(ring),
 		_MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
 		_MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
@@ -381,6 +384,39 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
 	return ret;
 }
 
+static bool gen8_logical_ring_get_irq(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	unsigned long flags;
+
+	if (!dev->irq_enabled)
+		return false;
+
+	spin_lock_irqsave(&dev_priv->irq_lock, flags);
+	if (ring->irq_refcount++ == 0) {
+		I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
+		POSTING_READ(RING_IMR(ring->mmio_base));
+	}
+	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+	return true;
+}
+
+static void gen8_logical_ring_put_irq(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev_priv->irq_lock, flags);
+	if (--ring->irq_refcount == 0) {
+		I915_WRITE_IMR(ring, ~ring->irq_keep_mask);
+		POSTING_READ(RING_IMR(ring->mmio_base));
+	}
+	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+}
+
 static int gen8_emit_flush(struct intel_ringbuffer *ringbuf,
 			   u32 invalidate_domains,
 			   u32 unused)
@@ -566,6 +602,10 @@ static int logical_render_ring_init(struct drm_device *dev)
 	ring->mmio_base = RENDER_RING_BASE;
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT;
+	ring->irq_keep_mask =
+		GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT;
+	if (HAS_L3_DPF(dev))
+		ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 
 	ring->init = gen8_init_render_ring;
 	ring->cleanup = intel_fini_pipe_control;
@@ -573,6 +613,8 @@ static int logical_render_ring_init(struct drm_device *dev)
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
 	ring->emit_flush = gen8_emit_flush_render;
+	ring->irq_get = gen8_logical_ring_get_irq;
+	ring->irq_put = gen8_logical_ring_put_irq;
 
 	return logical_ring_init(dev, ring);
 }
@@ -587,12 +629,16 @@ static int logical_bsd_ring_init(struct drm_device *dev)
 	ring->mmio_base = GEN6_BSD_RING_BASE;
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
+	ring->irq_keep_mask =
+		GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
 	ring->emit_flush = gen8_emit_flush;
+	ring->irq_get = gen8_logical_ring_get_irq;
+	ring->irq_put = gen8_logical_ring_put_irq;
 
 	return logical_ring_init(dev, ring);
 }
@@ -607,12 +653,16 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
 	ring->mmio_base = GEN8_BSD2_RING_BASE;
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
+	ring->irq_keep_mask =
+		GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
 	ring->emit_flush = gen8_emit_flush;
+	ring->irq_get = gen8_logical_ring_get_irq;
+	ring->irq_put = gen8_logical_ring_put_irq;
 
 	return logical_ring_init(dev, ring);
 }
@@ -627,12 +677,16 @@ static int logical_blt_ring_init(struct drm_device *dev)
 	ring->mmio_base = BLT_RING_BASE;
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+	ring->irq_keep_mask =
+		GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
 	ring->emit_flush = gen8_emit_flush;
+	ring->irq_get = gen8_logical_ring_get_irq;
+	ring->irq_put = gen8_logical_ring_put_irq;
 
 	return logical_ring_init(dev, ring);
 }
@@ -647,12 +701,16 @@ static int logical_vebox_ring_init(struct drm_device *dev)
 	ring->mmio_base = VEBOX_RING_BASE;
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
+	ring->irq_keep_mask =
+		GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
 	ring->emit_flush = gen8_emit_flush;
+	ring->irq_get = gen8_logical_ring_get_irq;
+	ring->irq_put = gen8_logical_ring_put_irq;
 
 	return logical_ring_init(dev, ring);
 }
drivers/gpu/drm/i915/intel_ringbuffer.h +1 -0
index 6e22866..09102b2 100644
@@ -223,6 +223,7 @@ struct  intel_engine_cs {
 	} semaphore;
 
 	/* Execlists */
+	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
 				      u32 invalidate_domains,
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#69 lore raw

Re: [PATCH 23/43] drm/i915/bdw: Interrupts with logical rings

In reply to Thomas Daniel
Quoted 94 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

We need to attend context switch interrupts from all rings. Also, fixed writing IMR/IER and added HWSTAM at ring init time.

Notice that, if added to irq_enable_mask, the context switch interrupts would be incorrectly masked out when the user interrupts are due to no users waiting on a sequence number. Therefore, this commit adds a bitmask of interrupts to be kept unmasked at all times.

v2: Disable HWSTAM, as suggested by Damien (nobody listens to these interrupts, anyway).

v3: Add new get/put_irq functions.

---
 drivers/gpu/drm/i915/i915_irq.c         |   19 ++++++++--
 drivers/gpu/drm/i915/i915_reg.h         |    3 ++
 drivers/gpu/drm/i915/intel_lrc.c        |   58 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    1 +
 4 files changed, 78 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/i915_irq.c +16 -3
index a38b5c3..f77a4ca 100644
@@ -1643,6 +1643,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 				notify_ring(dev, &dev_priv->ring[RCS]);
 			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");
 		} else
 			DRM_ERROR("The master control interrupt lied (GT0)!\n");
 	}
@@ -1655,9 +1657,13 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 			vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, &dev_priv->ring[VCS]);
+			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+				DRM_DEBUG_DRIVER("TODO: Context switch\n");
 			vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, &dev_priv->ring[VCS2]);
+			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+				DRM_DEBUG_DRIVER("TODO: Context switch\n");
 		} else
 			DRM_ERROR("The master control interrupt lied (GT1)!\n");
 	}
@@ -1681,6 +1687,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 			vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
 			if (vcs & GT_RENDER_USER_INTERRUPT)
 				notify_ring(dev, &dev_priv->ring[VECS]);
+			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
+				DRM_DEBUG_DRIVER("TODO: Context switch\n");
 		} else
 			DRM_ERROR("The master control interrupt lied (GT3)!\n");
 	}
@@ -3768,12 +3776,17 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
 	/* These are interrupts we'll toggle with the ring mask register */
 	uint32_t gt_interrupts[] = {
 		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
 			GT_RENDER_L3_PARITY_ERROR_INTERRUPT |
-			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
+			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
-			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
+			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
 		0,
-		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT
+		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT |
+			GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT
 		};
 
 	for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++)
drivers/gpu/drm/i915/i915_reg.h +1 -0
index 70dddac..bfc0c01 100644
@@ -1062,6 +1062,7 @@ enum punit_power_well {
 #define RING_ACTHD_UDW(base)	((base)+0x5c)
 #define RING_NOPID(base)	((base)+0x94)
 #define RING_IMR(base)		((base)+0xa8)
+#define RING_HWSTAM(base)	((base)+0x98)
 #define RING_TIMESTAMP(base)	((base)+0x358)
 #define   TAIL_ADDR		0x001FFFF8
 #define   HEAD_WRAP_COUNT	0xFFE00000

drivers/gpu/drm/i915/i915_reg.h enum punit_power_well { · line 4594

Quoted 4 lines
drivers/gpu/drm/i915/i915_reg.h +1 -0
@@ -4590,6 +4591,8 @@ enum punit_power_well {
 #define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which)))
 #define GEN8_GT_IER(which) (0x4430c + (0x10 * (which)))
 
+#define GEN8_GT_CONTEXT_SWITCH_INTERRUPT	(1 <<  8)

This looked misplaced - I've moved it to its brethren and dropped the GEN8_ prefix for consistency.
-Daniel

Quoted 165 lines
drivers/gpu/drm/i915/i915_reg.h +1 -0
+
 #define GEN8_BCS_IRQ_SHIFT 16
 #define GEN8_RCS_IRQ_SHIFT 0
 #define GEN8_VCS2_IRQ_SHIFT 16
drivers/gpu/drm/i915/intel_lrc.c +58 -0
index c30518c..a6dcb3a 100644
@@ -343,6 +343,9 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring)
 	struct drm_device *dev = ring->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
+	I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff);
+
 	I915_WRITE(RING_MODE_GEN7(ring),
 		_MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
 		_MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
@@ -381,6 +384,39 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
 	return ret;
 }
 
+static bool gen8_logical_ring_get_irq(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	unsigned long flags;
+
+	if (!dev->irq_enabled)
+		return false;
+
+	spin_lock_irqsave(&dev_priv->irq_lock, flags);
+	if (ring->irq_refcount++ == 0) {
+		I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
+		POSTING_READ(RING_IMR(ring->mmio_base));
+	}
+	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+	return true;
+}
+
+static void gen8_logical_ring_put_irq(struct intel_engine_cs *ring)
+{
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev_priv->irq_lock, flags);
+	if (--ring->irq_refcount == 0) {
+		I915_WRITE_IMR(ring, ~ring->irq_keep_mask);
+		POSTING_READ(RING_IMR(ring->mmio_base));
+	}
+	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+}
+
 static int gen8_emit_flush(struct intel_ringbuffer *ringbuf,
 			   u32 invalidate_domains,
 			   u32 unused)
@@ -566,6 +602,10 @@ static int logical_render_ring_init(struct drm_device *dev)
 	ring->mmio_base = RENDER_RING_BASE;
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT;
+	ring->irq_keep_mask =
+		GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT;
+	if (HAS_L3_DPF(dev))
+		ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
 
 	ring->init = gen8_init_render_ring;
 	ring->cleanup = intel_fini_pipe_control;
@@ -573,6 +613,8 @@ static int logical_render_ring_init(struct drm_device *dev)
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
 	ring->emit_flush = gen8_emit_flush_render;
+	ring->irq_get = gen8_logical_ring_get_irq;
+	ring->irq_put = gen8_logical_ring_put_irq;
 
 	return logical_ring_init(dev, ring);
 }
@@ -587,12 +629,16 @@ static int logical_bsd_ring_init(struct drm_device *dev)
 	ring->mmio_base = GEN6_BSD_RING_BASE;
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
+	ring->irq_keep_mask =
+		GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
 	ring->emit_flush = gen8_emit_flush;
+	ring->irq_get = gen8_logical_ring_get_irq;
+	ring->irq_put = gen8_logical_ring_put_irq;
 
 	return logical_ring_init(dev, ring);
 }
@@ -607,12 +653,16 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
 	ring->mmio_base = GEN8_BSD2_RING_BASE;
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
+	ring->irq_keep_mask =
+		GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
 	ring->emit_flush = gen8_emit_flush;
+	ring->irq_get = gen8_logical_ring_get_irq;
+	ring->irq_put = gen8_logical_ring_put_irq;
 
 	return logical_ring_init(dev, ring);
 }
@@ -627,12 +677,16 @@ static int logical_blt_ring_init(struct drm_device *dev)
 	ring->mmio_base = BLT_RING_BASE;
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+	ring->irq_keep_mask =
+		GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
 	ring->emit_flush = gen8_emit_flush;
+	ring->irq_get = gen8_logical_ring_get_irq;
+	ring->irq_put = gen8_logical_ring_put_irq;
 
 	return logical_ring_init(dev, ring);
 }
@@ -647,12 +701,16 @@ static int logical_vebox_ring_init(struct drm_device *dev)
 	ring->mmio_base = VEBOX_RING_BASE;
 	ring->irq_enable_mask =
 		GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
+	ring->irq_keep_mask =
+		GEN8_GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
 
 	ring->init = gen8_init_common_ring;
 	ring->get_seqno = gen8_get_seqno;
 	ring->set_seqno = gen8_set_seqno;
 	ring->emit_request = gen8_emit_request;
 	ring->emit_flush = gen8_emit_flush;
+	ring->irq_get = gen8_logical_ring_get_irq;
+	ring->irq_put = gen8_logical_ring_put_irq;
 
 	return logical_ring_init(dev, ring);
 }
drivers/gpu/drm/i915/intel_ringbuffer.h +1 -0
index 6e22866..09102b2 100644
@@ -223,6 +223,7 @@ struct  intel_engine_cs {
 	} semaphore;
 
 	/* Execlists */
+	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
 				      u32 invalidate_domains,
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#70 lore raw

PATCH 24/43 drm/i915/bdw: GEN-specific logical ring emit batchbuffer start

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Dispatch_execbuffer's evil twin.

---
 drivers/gpu/drm/i915/intel_lrc.c        |   28 ++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    2 ++
 2 files changed, 30 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +28 -0
index a6dcb3a..55ee8dd 100644
@@ -384,6 +384,29 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
 	return ret;
 }
 
+static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf,
+			      u64 offset, unsigned flags)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	bool ppgtt = dev_priv->mm.aliasing_ppgtt != NULL &&
+		!(flags & I915_DISPATCH_SECURE);
+	int ret;
+
+	ret = intel_logical_ring_begin(ringbuf, 4);
+	if (ret)
+		return ret;
+
+	/* FIXME(BDW): Address space and security selectors. */
+	intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8));
+	intel_logical_ring_emit(ringbuf, lower_32_bits(offset));
+	intel_logical_ring_emit(ringbuf, upper_32_bits(offset));
+	intel_logical_ring_emit(ringbuf, MI_NOOP);
+	intel_logical_ring_advance(ringbuf);
+
+	return 0;
+}
+
 static bool gen8_logical_ring_get_irq(struct intel_engine_cs *ring)
 {
 	struct drm_device *dev = ring->dev;
@@ -615,6 +638,7 @@ static int logical_render_ring_init(struct drm_device *dev)
 	ring->emit_flush = gen8_emit_flush_render;
 	ring->irq_get = gen8_logical_ring_get_irq;
 	ring->irq_put = gen8_logical_ring_put_irq;
+	ring->emit_bb_start = gen8_emit_bb_start;
 
 	return logical_ring_init(dev, ring);
 }
@@ -639,6 +663,7 @@ static int logical_bsd_ring_init(struct drm_device *dev)
 	ring->emit_flush = gen8_emit_flush;
 	ring->irq_get = gen8_logical_ring_get_irq;
 	ring->irq_put = gen8_logical_ring_put_irq;
+	ring->emit_bb_start = gen8_emit_bb_start;
 
 	return logical_ring_init(dev, ring);
 }
@@ -663,6 +688,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
 	ring->emit_flush = gen8_emit_flush;
 	ring->irq_get = gen8_logical_ring_get_irq;
 	ring->irq_put = gen8_logical_ring_put_irq;
+	ring->emit_bb_start = gen8_emit_bb_start;
 
 	return logical_ring_init(dev, ring);
 }
@@ -687,6 +713,7 @@ static int logical_blt_ring_init(struct drm_device *dev)
 	ring->emit_flush = gen8_emit_flush;
 	ring->irq_get = gen8_logical_ring_get_irq;
 	ring->irq_put = gen8_logical_ring_put_irq;
+	ring->emit_bb_start = gen8_emit_bb_start;
 
 	return logical_ring_init(dev, ring);
 }
@@ -711,6 +738,7 @@ static int logical_vebox_ring_init(struct drm_device *dev)
 	ring->emit_flush = gen8_emit_flush;
 	ring->irq_get = gen8_logical_ring_get_irq;
 	ring->irq_put = gen8_logical_ring_put_irq;
+	ring->emit_bb_start = gen8_emit_bb_start;
 
 	return logical_ring_init(dev, ring);
 }
drivers/gpu/drm/i915/intel_ringbuffer.h +2 -0
index 09102b2..c885d5c 100644
@@ -228,6 +228,8 @@ struct  intel_engine_cs {
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
 				      u32 invalidate_domains,
 				      u32 flush_domains);
+	int		(*emit_bb_start)(struct intel_ringbuffer *ringbuf,
+					 u64 offset, unsigned flags);
 
 	/**
 	 * List of objects currently involved in rendering from the
Signature · 1 line
1.7.9.5
#71 lore raw

Re: [PATCH 24/43] drm/i915/bdw: GEN-specific logical ring emit batchbuffer start

Quoted 15 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Dispatch_execbuffer's evil twin.

---
 drivers/gpu/drm/i915/intel_lrc.c        |   28 ++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    2 ++
 2 files changed, 30 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index a6dcb3a..55ee8dd 100644

drivers/gpu/drm/i915/intel_lrc.c static int gen8_init_render_ring(struct intel_engine_cs *ring) · line 392

Quoted 9 lines
drivers/gpu/drm/i915/intel_lrc.c +6 -0
@@ -384,6 +384,29 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
 	return ret;
 }
 
+static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf,
+			      u64 offset, unsigned flags)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	bool ppgtt = dev_priv->mm.aliasing_ppgtt != NULL &&

The aliasing ppgtt check here is fairly decent bullocks, especially since full ppgtt is a requirement for execlists. I've ditched it since a series from myself will otherwise break this patch.
-Daniel

Quoted 80 lines
drivers/gpu/drm/i915/intel_lrc.c +22 -0
+		!(flags & I915_DISPATCH_SECURE);
+	int ret;
+
+	ret = intel_logical_ring_begin(ringbuf, 4);
+	if (ret)
+		return ret;
+
+	/* FIXME(BDW): Address space and security selectors. */
+	intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8));
+	intel_logical_ring_emit(ringbuf, lower_32_bits(offset));
+	intel_logical_ring_emit(ringbuf, upper_32_bits(offset));
+	intel_logical_ring_emit(ringbuf, MI_NOOP);
+	intel_logical_ring_advance(ringbuf);
+
+	return 0;
+}
+
 static bool gen8_logical_ring_get_irq(struct intel_engine_cs *ring)
 {
 	struct drm_device *dev = ring->dev;
@@ -615,6 +638,7 @@ static int logical_render_ring_init(struct drm_device *dev)
 	ring->emit_flush = gen8_emit_flush_render;
 	ring->irq_get = gen8_logical_ring_get_irq;
 	ring->irq_put = gen8_logical_ring_put_irq;
+	ring->emit_bb_start = gen8_emit_bb_start;
 
 	return logical_ring_init(dev, ring);
 }
@@ -639,6 +663,7 @@ static int logical_bsd_ring_init(struct drm_device *dev)
 	ring->emit_flush = gen8_emit_flush;
 	ring->irq_get = gen8_logical_ring_get_irq;
 	ring->irq_put = gen8_logical_ring_put_irq;
+	ring->emit_bb_start = gen8_emit_bb_start;
 
 	return logical_ring_init(dev, ring);
 }
@@ -663,6 +688,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
 	ring->emit_flush = gen8_emit_flush;
 	ring->irq_get = gen8_logical_ring_get_irq;
 	ring->irq_put = gen8_logical_ring_put_irq;
+	ring->emit_bb_start = gen8_emit_bb_start;
 
 	return logical_ring_init(dev, ring);
 }
@@ -687,6 +713,7 @@ static int logical_blt_ring_init(struct drm_device *dev)
 	ring->emit_flush = gen8_emit_flush;
 	ring->irq_get = gen8_logical_ring_get_irq;
 	ring->irq_put = gen8_logical_ring_put_irq;
+	ring->emit_bb_start = gen8_emit_bb_start;
 
 	return logical_ring_init(dev, ring);
 }
@@ -711,6 +738,7 @@ static int logical_vebox_ring_init(struct drm_device *dev)
 	ring->emit_flush = gen8_emit_flush;
 	ring->irq_get = gen8_logical_ring_get_irq;
 	ring->irq_put = gen8_logical_ring_put_irq;
+	ring->emit_bb_start = gen8_emit_bb_start;
 
 	return logical_ring_init(dev, ring);
 }
drivers/gpu/drm/i915/intel_ringbuffer.h +2 -0
index 09102b2..c885d5c 100644
@@ -228,6 +228,8 @@ struct  intel_engine_cs {
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
 				      u32 invalidate_domains,
 				      u32 flush_domains);
+	int		(*emit_bb_start)(struct intel_ringbuffer *ringbuf,
+					 u64 offset, unsigned flags);
 
 	/**
 	 * List of objects currently involved in rendering from the
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#72 lore raw

Re: [PATCH 24/43] drm/i915/bdw: GEN-specific logical ring emit batchbuffer start

Quoted 31 lines · Daniel Vetter
Quoted 15 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Dispatch_execbuffer's evil twin.

---
 drivers/gpu/drm/i915/intel_lrc.c        |   28 ++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    2 ++
 2 files changed, 30 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index a6dcb3a..55ee8dd 100644

drivers/gpu/drm/i915/intel_lrc.c static int gen8_init_render_ring(struct intel_engine_cs *ring) · line 392

Quoted 9 lines
drivers/gpu/drm/i915/intel_lrc.c +6 -0
@@ -384,6 +384,29 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
 	return ret;
 }
 
+static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf,
+			      u64 offset, unsigned flags)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	bool ppgtt = dev_priv->mm.aliasing_ppgtt != NULL &&

The aliasing ppgtt check here is fairly decent bullocks, especially since full ppgtt is a requirement for execlists. I've ditched it since a series from myself will otherwise break this patch.
-Daniel

Quoted 9 lines

drivers/gpu/drm/i915/intel_lrc.c static int gen8_init_render_ring(struct intel_engine_cs *ring) · line 401

Quoted 9 lines
drivers/gpu/drm/i915/intel_lrc.c +9 -0
+		!(flags & I915_DISPATCH_SECURE);
+	int ret;
+
+	ret = intel_logical_ring_begin(ringbuf, 4);
+	if (ret)
+		return ret;
+
+	/* FIXME(BDW): Address space and security selectors. */
+	intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8));

Also please follow up with a patch to replace the magic 8 here with a proper define. Usual approach is to build this up with an u32 cmd_flags or so. Patch should obviously also rectify the legacy ring stuff. -Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#73 lore raw

PATCH 25/43 drm/i915/bdw: Workload submission mechanism for Execlists

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

This is what i915_gem_do_execbuffer calls when it wants to execute some worload in an Execlists world.

v2: Check arguments before doing stuff in intel_execlists_submission. Also, get rel_constants parsing right.

---
 drivers/gpu/drm/i915/i915_drv.h            |    6 ++
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |    4 +-
 drivers/gpu/drm/i915/intel_lrc.c           |  130 +++++++++++++++++++++++++++-
 3 files changed, 137 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/i915_drv.h +6 -0
index 1caed52..4303e2c 100644
@@ -2239,6 +2239,12 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 			      struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *file_priv);
+void i915_gem_execbuffer_move_to_active(struct list_head *vmas,
+					struct intel_engine_cs *ring);
+void i915_gem_execbuffer_retire_commands(struct drm_device *dev,
+					 struct drm_file *file,
+					 struct intel_engine_cs *ring,
+					 struct drm_i915_gem_object *obj);
 int i915_gem_ringbuffer_submission(struct drm_device *dev,
 				   struct drm_file *file,
 				   struct intel_engine_cs *ring,
drivers/gpu/drm/i915/i915_gem_execbuffer.c +2 -2
index 8c63d79..cae7df8 100644
@@ -962,7 +962,7 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
 	return ctx;
 }
 
-static void
+void
 i915_gem_execbuffer_move_to_active(struct list_head *vmas,
 				   struct intel_engine_cs *ring)
 {
@@ -994,7 +994,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
 	}
 }
 
-static void
+void
 i915_gem_execbuffer_retire_commands(struct drm_device *dev,
 				    struct drm_file *file,
 				    struct intel_engine_cs *ring,
drivers/gpu/drm/i915/intel_lrc.c +129 -1

142 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#74 lore raw

Re: [PATCH 25/43] drm/i915/bdw: Workload submission mechanism for Execlists

Quoted 93 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

This is what i915_gem_do_execbuffer calls when it wants to execute some worload in an Execlists world.

v2: Check arguments before doing stuff in intel_execlists_submission. Also, get rel_constants parsing right.

---
 drivers/gpu/drm/i915/i915_drv.h            |    6 ++
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |    4 +-
 drivers/gpu/drm/i915/intel_lrc.c           |  130 +++++++++++++++++++++++++++-
 3 files changed, 137 insertions(+), 3 deletions(-)
drivers/gpu/drm/i915/i915_drv.h +6 -0
index 1caed52..4303e2c 100644
@@ -2239,6 +2239,12 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 			      struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *file_priv);
+void i915_gem_execbuffer_move_to_active(struct list_head *vmas,
+					struct intel_engine_cs *ring);
+void i915_gem_execbuffer_retire_commands(struct drm_device *dev,
+					 struct drm_file *file,
+					 struct intel_engine_cs *ring,
+					 struct drm_i915_gem_object *obj);
 int i915_gem_ringbuffer_submission(struct drm_device *dev,
 				   struct drm_file *file,
 				   struct intel_engine_cs *ring,
drivers/gpu/drm/i915/i915_gem_execbuffer.c +2 -2
index 8c63d79..cae7df8 100644
@@ -962,7 +962,7 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
 	return ctx;
 }
 
-static void
+void
 i915_gem_execbuffer_move_to_active(struct list_head *vmas,
 				   struct intel_engine_cs *ring)
 {
@@ -994,7 +994,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
 	}
 }
 
-static void
+void
 i915_gem_execbuffer_retire_commands(struct drm_device *dev,
 				    struct drm_file *file,
 				    struct intel_engine_cs *ring,
drivers/gpu/drm/i915/intel_lrc.c +31 -0
index 55ee8dd..cd834b3 100644
@@ -89,6 +89,57 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
 	return 0;
 }
 
+static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	uint32_t flush_domains;
+	int ret;
+
+	flush_domains = 0;
+	if (ring->gpu_caches_dirty)
+		flush_domains = I915_GEM_GPU_DOMAINS;
+
+	ret = ring->emit_flush(ringbuf, I915_GEM_GPU_DOMAINS, flush_domains);
+	if (ret)
+		return ret;
+
+	ring->gpu_caches_dirty = false;
+	return 0;
+}
+
+static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf,
+				 struct list_head *vmas)
+{
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct i915_vma *vma;
+	uint32_t flush_domains = 0;
+	bool flush_chipset = false;
+	int ret;
+
+	list_for_each_entry(vma, vmas, exec_list) {
+		struct drm_i915_gem_object *obj = vma->obj;
+		ret = i915_gem_object_sync(obj, ring);
+		if (ret)

drivers/gpu/drm/i915/intel_lrc.c int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists · line 132

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +10 -0
+			return ret;
+
+		if (obj->base.write_domain & I915_GEM_DOMAIN_CPU)
+			flush_chipset |= i915_gem_clflush_object(obj, false);
+
+		flush_domains |= obj->base.write_domain;
+	}
+
+	if (flush_chipset)
+		i915_gem_chipset_flush(ring->dev);

chipset flush is gen5 and earlier only. I'll ditch it.

Quoted 54 lines
drivers/gpu/drm/i915/intel_lrc.c +46 -1
+
+	if (flush_domains & I915_GEM_DOMAIN_GTT)
+		wmb();
+
+	/* Unconditionally invalidate gpu caches and ensure that we do flush
+	 * any residual writes from the previous batch.
+	 */
+	return logical_ring_invalidate_all_caches(ringbuf);
+}
+
 int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
 			       struct intel_engine_cs *ring,
 			       struct intel_context *ctx,
@@ -97,7 +148,84 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
 			       struct drm_i915_gem_object *batch_obj,
 			       u64 exec_start, u32 flags)
 {
-	/* TODO */
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+	int instp_mode;
+	u32 instp_mask;
+	int ret;
+
+	instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
+	instp_mask = I915_EXEC_CONSTANTS_MASK;
+	switch (instp_mode) {
+	case I915_EXEC_CONSTANTS_REL_GENERAL:
+	case I915_EXEC_CONSTANTS_ABSOLUTE:
+	case I915_EXEC_CONSTANTS_REL_SURFACE:
+		if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) {
+			DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
+			return -EINVAL;
+		}
+
+		if (instp_mode != dev_priv->relative_constants_mode) {
+			if (instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
+				DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
+				return -EINVAL;
+			}
+
+			/* The HW changed the meaning on this bit on gen6 */
+			instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE;
+		}
+		break;
+	default:
+		DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode);
+		return -EINVAL;
+	}
+
+	if (args->num_cliprects != 0) {
+		DRM_DEBUG("clip rectangles are only valid on pre-gen5\n");
+		return -EINVAL;
+	} else {

drivers/gpu/drm/i915/intel_lrc.c int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, · line 196

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +10 -0
+		if (args->DR4 == 0xffffffff) {
+			DRM_DEBUG("UXA submitting garbage DR4, fixing up\n");
+			args->DR4 = 0;
+		}
+
+		if (args->DR1 || args->DR4 || args->cliprects_ptr) {
+			DRM_DEBUG("0 cliprects but dirt in cliprects fields\n");
+			return -EINVAL;
+		}
+	}

Yay for all the legacy nonsense that we can ditch here ;-) -Daniel

Quoted 42 lines
drivers/gpu/drm/i915/intel_lrc.c +32 -0
+
+	if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
+		DRM_DEBUG("sol reset is gen7 only\n");
+		return -EINVAL;
+	}
+
+	ret = execlists_move_to_gpu(ringbuf, vmas);
+	if (ret)
+		return ret;
+
+	if (ring == &dev_priv->ring[RCS] &&
+			instp_mode != dev_priv->relative_constants_mode) {
+		ret = intel_logical_ring_begin(ringbuf, 4);
+		if (ret)
+			return ret;
+
+		intel_logical_ring_emit(ringbuf, MI_NOOP);
+		intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(1));
+		intel_logical_ring_emit(ringbuf, INSTPM);
+		intel_logical_ring_emit(ringbuf, instp_mask << 16 | instp_mode);
+		intel_logical_ring_advance(ringbuf);
+
+		dev_priv->relative_constants_mode = instp_mode;
+	}
+
+	ret = ring->emit_bb_start(ringbuf, exec_start, flags);
+	if (ret)
+		return ret;
+
+	i915_gem_execbuffer_move_to_active(vmas, ring);
+	i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
+
 	return 0;
 }
 
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#75 lore raw

PATCH 26/43 drm/i915/bdw: Always use MMIO flips with Execlists

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

The normal flip function places things in the ring in the legacy way, so we either fix that or force MMIO flips always as we do in this patch.

---
 drivers/gpu/drm/i915/intel_display.c |    2 ++
 drivers/gpu/drm/i915/intel_lrc.c     |    3 ++-
 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/intel_display.c +2 -0
index 5ed6a1a..8129af4 100644
@@ -9482,6 +9482,8 @@ static bool use_mmio_flip(struct intel_engine_cs *ring,
 		return false;
 	else if (i915.use_mmio_flip > 0)
 		return true;
+	else if (i915.enable_execlists)
+		return true;
 	else
 		return ring != obj->ring;
 }
drivers/gpu/drm/i915/intel_lrc.c +2 -1
index cd834b3..0a04c03 100644
@@ -83,7 +83,8 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
 	if (enable_execlists == 0)
 		return 0;
 
-	if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev))
+	if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev) &&
+			i915.use_mmio_flip >= 0)
 		return 1;
 
 	return 0;
Signature · 1 line
1.7.9.5
#76 lore raw

Re: [PATCH 26/43] drm/i915/bdw: Always use MMIO flips with Execlists

Quoted 30 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

The normal flip function places things in the ring in the legacy way, so we either fix that or force MMIO flips always as we do in this patch.

---
 drivers/gpu/drm/i915/intel_display.c |    2 ++
 drivers/gpu/drm/i915/intel_lrc.c     |    3 ++-
 2 files changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/i915/intel_display.c +2 -0
index 5ed6a1a..8129af4 100644
@@ -9482,6 +9482,8 @@ static bool use_mmio_flip(struct intel_engine_cs *ring,
 		return false;
 	else if (i915.use_mmio_flip > 0)
 		return true;
+	else if (i915.enable_execlists)
+		return true;
 	else
 		return ring != obj->ring;
 }
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index cd834b3..0a04c03 100644

drivers/gpu/drm/i915/intel_lrc.c int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists · line 87

Quoted 6 lines
drivers/gpu/drm/i915/intel_lrc.c +2 -1
@@ -83,7 +83,8 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
 	if (enable_execlists == 0)
 		return 0;
 
-	if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev))
+	if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev) &&
+			i915.use_mmio_flip >= 0)

Almost every patch gets the alignment wrong somewhere. Not terribly amused.
-Daniel

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -0
 		return 1;
 
 	return 0;
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#77 lore raw

PATCH 27/43 drm/i915/bdw: Render state init for Execlists

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

The batchbuffer that sets the render context state is submitted in a different way, and from different places.

We needed to make both the render state preparation and free functions outside accesible, and namespace accordingly. This mess is so that all LR, LRC and Execlists functionality can go together in intel_lrc.c: we can fix all of this later on, once the interfaces are clear.

v2: Create a separate ctx->rcs_initialized for the Execlists case, as suggested by Chris Wilson.

---
 drivers/gpu/drm/i915/i915_drv.h              |    4 +--
 drivers/gpu/drm/i915/i915_gem_context.c      |   17 +++++++++-
 drivers/gpu/drm/i915/i915_gem_render_state.c |   40 ++++++++++++++--------
 drivers/gpu/drm/i915/i915_gem_render_state.h |   47 ++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.c             |   46 +++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.h             |    2 ++
 drivers/gpu/drm/i915/intel_renderstate.h     |    8 +----
 7 files changed, 139 insertions(+), 25 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/i915_gem_render_state.h
drivers/gpu/drm/i915/i915_drv.h +2 -2
index 4303e2c..b7cf0ec 100644
@@ -37,6 +37,7 @@
 #include "intel_ringbuffer.h"
 #include "intel_lrc.h"
 #include "i915_gem_gtt.h"
+#include "i915_gem_render_state.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -623,6 +624,7 @@ struct intel_context {
 	} legacy_hw_ctx;
 
 	/* Execlists */
+	bool rcs_initialized;
 	struct {
 		struct drm_i915_gem_object *state;
 		struct intel_ringbuffer *ringbuf;
@@ -2553,8 +2555,6 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 				   struct drm_file *file);
 
-/* i915_gem_render_state.c */
-int i915_gem_render_state_init(struct intel_engine_cs *ring);
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct drm_device *dev,
 					  struct i915_address_space *vm,
drivers/gpu/drm/i915/i915_gem_context.c +16 -1
index 9085ff1..0dc6992 100644
@@ -513,8 +513,23 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
 		ppgtt->enable(ppgtt);
 	}
 
-	if (i915.enable_execlists)
+	if (i915.enable_execlists) {
+		struct intel_context *dctx;
+
+		ring = &dev_priv->ring[RCS];
+		dctx = ring->default_context;
+
+		if (!dctx->rcs_initialized) {
+			ret = intel_lr_context_render_state_init(ring, dctx);
+			if (ret) {
+				DRM_ERROR("Init render state failed: %d\n", ret);
+				return ret;
+			}
+			dctx->rcs_initialized = true;
+		}
+
 		return 0;
+	}
 
 	/* FIXME: We should make this work, even in reset */
 	if (i915_reset_in_progress(&dev_priv->gpu_error))
drivers/gpu/drm/i915/i915_gem_render_state.c +25 -15
index e60be3f..a9a62d7 100644
@@ -28,13 +28,6 @@
 #include "i915_drv.h"
 #include "intel_renderstate.h"
 
-struct render_state {
-	const struct intel_renderstate_rodata *rodata;
-	struct drm_i915_gem_object *obj;
-	u64 ggtt_offset;
-	int gen;
-};
-
 static const struct intel_renderstate_rodata *
 render_state_get_rodata(struct drm_device *dev, const int gen)
 {
@@ -127,30 +120,47 @@ static int render_state_setup(struct render_state *so)
 	return 0;
 }
 
-static void render_state_fini(struct render_state *so)
+void i915_gem_render_state_fini(struct render_state *so)
 {
 	i915_gem_object_ggtt_unpin(so->obj);
 	drm_gem_object_unreference(&so->obj->base);
 }
 
-int i915_gem_render_state_init(struct intel_engine_cs *ring)
+int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
+				  struct render_state *so)
 {
-	struct render_state so;
 	int ret;
 
 	if (WARN_ON(ring->id != RCS))
 		return -ENOENT;
 
-	ret = render_state_init(&so, ring->dev);
+	ret = render_state_init(so, ring->dev);
 	if (ret)
 		return ret;
 
-	if (so.rodata == NULL)
+	if (so->rodata == NULL)
 		return 0;
 
-	ret = render_state_setup(&so);
+	ret = render_state_setup(so);
+	if (ret) {
+		i915_gem_render_state_fini(so);
+		return ret;
+	}
+
+	return 0;
+}
+
+int i915_gem_render_state_init(struct intel_engine_cs *ring)
+{
+	struct render_state so;
+	int ret;
+
+	ret = i915_gem_render_state_prepare(ring, &so);
 	if (ret)
-		goto out;
+		return ret;
+
+	if (so.rodata == NULL)
+		return 0;
 
 	ret = ring->dispatch_execbuffer(ring,
 					so.ggtt_offset,
@@ -164,6 +174,6 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring)
 	ret = __i915_add_request(ring, NULL, so.obj, NULL);
 	/* __i915_add_request moves object to inactive if it fails */
 out:
-	render_state_fini(&so);
+	i915_gem_render_state_fini(&so);
 	return ret;
 }
drivers/gpu/drm/i915/i915_gem_render_state.h new file +47 -0

47 lines not on this page · raw message

drivers/gpu/drm/i915/intel_lrc.c +46 -0

58 lines not on this page · raw message

drivers/gpu/drm/i915/intel_lrc.h +2 -0
index 696e09e..f20c3d2 100644
@@ -43,6 +43,8 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf, u32
 int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
 
 /* Logical Ring Contexts */
+int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+				       struct intel_context *ctx);
 void intel_lr_context_free(struct intel_context *ctx);
 int intel_lr_context_deferred_create(struct intel_context *ctx,
 				     struct intel_engine_cs *ring);
drivers/gpu/drm/i915/intel_renderstate.h +1 -7
index fd4f662..6c792d3 100644
@@ -24,13 +24,7 @@
 #ifndef _INTEL_RENDERSTATE_H
 #define _INTEL_RENDERSTATE_H
 
-#include <linux/types.h>
-
-struct intel_renderstate_rodata {
-	const u32 *reloc;
-	const u32 *batch;
-	const u32 batch_items;
-};
+#include "i915_drv.h"
 
 extern const struct intel_renderstate_rodata gen6_null_state;
 extern const struct intel_renderstate_rodata gen7_null_state;
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#78 lore raw

Re: [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 70 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

The batchbuffer that sets the render context state is submitted in a different way, and from different places.

We needed to make both the render state preparation and free functions outside accesible, and namespace accordingly. This mess is so that all LR, LRC and Execlists functionality can go together in intel_lrc.c: we can fix all of this later on, once the interfaces are clear.

v2: Create a separate ctx->rcs_initialized for the Execlists case, as suggested by Chris Wilson.

---
 drivers/gpu/drm/i915/i915_drv.h              |    4 +--
 drivers/gpu/drm/i915/i915_gem_context.c      |   17 +++++++++-
 drivers/gpu/drm/i915/i915_gem_render_state.c |   40 ++++++++++++++--------
 drivers/gpu/drm/i915/i915_gem_render_state.h |   47 ++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.c             |   46 +++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.h             |    2 ++
 drivers/gpu/drm/i915/intel_renderstate.h     |    8 +----
 7 files changed, 139 insertions(+), 25 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/i915_gem_render_state.h
drivers/gpu/drm/i915/i915_drv.h +2 -2
index 4303e2c..b7cf0ec 100644
@@ -37,6 +37,7 @@
 #include "intel_ringbuffer.h"
 #include "intel_lrc.h"
 #include "i915_gem_gtt.h"
+#include "i915_gem_render_state.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -623,6 +624,7 @@ struct intel_context {
 	} legacy_hw_ctx;
 
 	/* Execlists */
+	bool rcs_initialized;
 	struct {
 		struct drm_i915_gem_object *state;
 		struct intel_ringbuffer *ringbuf;
@@ -2553,8 +2555,6 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 				   struct drm_file *file);
 
-/* i915_gem_render_state.c */
-int i915_gem_render_state_init(struct intel_engine_cs *ring);
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct drm_device *dev,
 					  struct i915_address_space *vm,
drivers/gpu/drm/i915/i915_gem_context.c +7 -1
index 9085ff1..0dc6992 100644
@@ -513,8 +513,23 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
 		ppgtt->enable(ppgtt);
 	}
 
-	if (i915.enable_execlists)
+	if (i915.enable_execlists) {
+		struct intel_context *dctx;
+
+		ring = &dev_priv->ring[RCS];
+		dctx = ring->default_context;
+
+		if (!dctx->rcs_initialized) {

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv) · line 532

Quoted 10 lines
drivers/gpu/drm/i915/i915_gem_context.c +9 -0
+			ret = intel_lr_context_render_state_init(ring, dctx);
+			if (ret) {
+				DRM_ERROR("Init render state failed: %d\n", ret);
+				return ret;
+			}
+			dctx->rcs_initialized = true;
+		}
+
 		return 0;
+	}

This looks very much like the wrong place. We should init the render state when we create the context, or when we switch to it for the first time. The later is what the legacy contexts currently do in do_switch.

But ctx_enable should do the switch to the default context and that's about it. If there's some depency then I guess we should stall the creation of the default context a bit, maybe.

In any case someone needs to explain this better and if there's not other wey this at least needs a bit comment. So I'll punt for now. -Daniel

Quoted 240 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 	/* FIXME: We should make this work, even in reset */
 	if (i915_reset_in_progress(&dev_priv->gpu_error))
drivers/gpu/drm/i915/i915_gem_render_state.c +25 -15
index e60be3f..a9a62d7 100644
@@ -28,13 +28,6 @@
 #include "i915_drv.h"
 #include "intel_renderstate.h"
 
-struct render_state {
-	const struct intel_renderstate_rodata *rodata;
-	struct drm_i915_gem_object *obj;
-	u64 ggtt_offset;
-	int gen;
-};
-
 static const struct intel_renderstate_rodata *
 render_state_get_rodata(struct drm_device *dev, const int gen)
 {
@@ -127,30 +120,47 @@ static int render_state_setup(struct render_state *so)
 	return 0;
 }
 
-static void render_state_fini(struct render_state *so)
+void i915_gem_render_state_fini(struct render_state *so)
 {
 	i915_gem_object_ggtt_unpin(so->obj);
 	drm_gem_object_unreference(&so->obj->base);
 }
 
-int i915_gem_render_state_init(struct intel_engine_cs *ring)
+int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
+				  struct render_state *so)
 {
-	struct render_state so;
 	int ret;
 
 	if (WARN_ON(ring->id != RCS))
 		return -ENOENT;
 
-	ret = render_state_init(&so, ring->dev);
+	ret = render_state_init(so, ring->dev);
 	if (ret)
 		return ret;
 
-	if (so.rodata == NULL)
+	if (so->rodata == NULL)
 		return 0;
 
-	ret = render_state_setup(&so);
+	ret = render_state_setup(so);
+	if (ret) {
+		i915_gem_render_state_fini(so);
+		return ret;
+	}
+
+	return 0;
+}
+
+int i915_gem_render_state_init(struct intel_engine_cs *ring)
+{
+	struct render_state so;
+	int ret;
+
+	ret = i915_gem_render_state_prepare(ring, &so);
 	if (ret)
-		goto out;
+		return ret;
+
+	if (so.rodata == NULL)
+		return 0;
 
 	ret = ring->dispatch_execbuffer(ring,
 					so.ggtt_offset,
@@ -164,6 +174,6 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring)
 	ret = __i915_add_request(ring, NULL, so.obj, NULL);
 	/* __i915_add_request moves object to inactive if it fails */
 out:
-	render_state_fini(&so);
+	i915_gem_render_state_fini(&so);
 	return ret;
 }
drivers/gpu/drm/i915/i915_gem_render_state.h new file +47 -0
new file mode 100644
index 0000000..c44961e
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _I915_GEM_RENDER_STATE_H_
+#define _I915_GEM_RENDER_STATE_H_
+
+#include <linux/types.h>
+
+struct intel_renderstate_rodata {
+	const u32 *reloc;
+	const u32 *batch;
+	const u32 batch_items;
+};
+
+struct render_state {
+	const struct intel_renderstate_rodata *rodata;
+	struct drm_i915_gem_object *obj;
+	u64 ggtt_offset;
+	int gen;
+};
+
+int i915_gem_render_state_init(struct intel_engine_cs *ring);
+void i915_gem_render_state_fini(struct render_state *so);
+int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
+				  struct render_state *so);
+
+#endif /* _I915_GEM_RENDER_STATE_H_ */
drivers/gpu/drm/i915/intel_lrc.c +46 -0
index 0a04c03..4549eec 100644
@@ -925,6 +925,37 @@ cleanup_render_ring:
 	return ret;
 }
 
+int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+				       struct intel_context *ctx)
+{
+	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+	struct render_state so;
+	struct drm_i915_file_private *file_priv = ctx->file_priv;
+	struct drm_file *file = file_priv? file_priv->file : NULL;
+	int ret;
+
+	ret = i915_gem_render_state_prepare(ring, &so);
+	if (ret)
+		return ret;
+
+	if (so.rodata == NULL)
+		return 0;
+
+	ret = ring->emit_bb_start(ringbuf,
+			so.ggtt_offset,
+			I915_DISPATCH_SECURE);
+	if (ret)
+		goto out;
+
+	i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
+
+	ret = __i915_add_request(ring, file, so.obj, NULL);
+	/* intel_logical_ring_add_request moves object to inactive if it fails */
+out:
+	i915_gem_render_state_fini(&so);
+	return ret;
+}
+
 static int
 populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_obj,
 		    struct intel_engine_cs *ring, struct intel_ringbuffer *ringbuf)
@@ -1142,6 +1173,21 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 	ctx->engine[ring->id].ringbuf = ringbuf;
 	ctx->engine[ring->id].state = ctx_obj;
 
+	/* The default context will have to wait, because we are not yet
+	 * ready to send a batchbuffer at this point */
+	if (ring->id == RCS && !ctx->rcs_initialized &&
+			ctx != ring->default_context) {
+		ret = intel_lr_context_render_state_init(ring, ctx);
+		if (ret) {
+			DRM_ERROR("Init render state failed: %d\n", ret);
+			ctx->engine[ring->id].ringbuf = NULL;
+			ctx->engine[ring->id].state = NULL;
+			intel_destroy_ringbuffer_obj(ringbuf);
+			goto error;
+		}
+		ctx->rcs_initialized = true;
+	}
+
 	return 0;
 
 error:
drivers/gpu/drm/i915/intel_lrc.h +2 -0
index 696e09e..f20c3d2 100644
@@ -43,6 +43,8 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf, u32
 int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
 
 /* Logical Ring Contexts */
+int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+				       struct intel_context *ctx);
 void intel_lr_context_free(struct intel_context *ctx);
 int intel_lr_context_deferred_create(struct intel_context *ctx,
 				     struct intel_engine_cs *ring);
drivers/gpu/drm/i915/intel_renderstate.h +1 -7
index fd4f662..6c792d3 100644
@@ -24,13 +24,7 @@
 #ifndef _INTEL_RENDERSTATE_H
 #define _INTEL_RENDERSTATE_H
 
-#include <linux/types.h>
-
-struct intel_renderstate_rodata {
-	const u32 *reloc;
-	const u32 *batch;
-	const u32 batch_items;
-};
+#include "i915_drv.h"
 
 extern const struct intel_renderstate_rodata gen6_null_state;
 extern const struct intel_renderstate_rodata gen7_null_state;
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#79 lore raw

Re: [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 105 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 10:25 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 10 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

The batchbuffer that sets the render context state is submitted in a different way, and from different places.

We needed to make both the render state preparation and free functions outside accesible, and namespace accordingly. This mess is so that all LR, LRC and Execlists functionality can go together in intel_lrc.c: we can fix all of this later on, once the interfaces are clear.

Quoted 8 lines

v2: Create a separate ctx->rcs_initialized for the Execlists case, as suggested by Chris Wilson.

---
 drivers/gpu/drm/i915/i915_drv.h              |    4 +--
 drivers/gpu/drm/i915/i915_gem_context.c      |   17 +++++++++-
 drivers/gpu/drm/i915/i915_gem_render_state.c |   40 ++++++++++++++--

------

Quoted 1 line
 drivers/gpu/drm/i915/i915_gem_render_state.h |   47

++++++++++++++++++++++++++

Quoted 1 line
 drivers/gpu/drm/i915/intel_lrc.c             |   46

+++++++++++++++++++++++++

Quoted 26 lines
 drivers/gpu/drm/i915/intel_lrc.h             |    2 ++
 drivers/gpu/drm/i915/intel_renderstate.h     |    8 +----
 7 files changed, 139 insertions(+), 25 deletions(-)  create mode

100644 drivers/gpu/drm/i915/i915_gem_render_state.h

(quoted diff) +0 -0

b/drivers/gpu/drm/i915/i915_drv.h index 4303e2c..b7cf0ec 100644

drivers/gpu/drm/i915/i915_drv.h +2 -0
@@ -37,6 +37,7 @@
 #include "intel_ringbuffer.h"
 #include "intel_lrc.h"
 #include "i915_gem_gtt.h"
+#include "i915_gem_render_state.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -623,6 +624,7 @@ struct intel_context {
 	} legacy_hw_ctx;
 
 	/* Execlists */
+	bool rcs_initialized;
 	struct {
 		struct drm_i915_gem_object *state;
 		struct intel_ringbuffer *ringbuf;
@@ -2553,8 +2555,6 @@ int i915_gem_context_create_ioctl(struct
Quoted 1 line

drm_device *dev, void *data, int i915_gem_context_destroy_ioctl(struct

drm_device *dev, void *data,

drivers/gpu/drm/i915/i915_drv.h int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,

Quoted 7 lines
drivers/gpu/drm/i915/i915_drv.h +0 -2
 				   struct drm_file *file);
 
-/* i915_gem_render_state.c */
-int i915_gem_render_state_init(struct intel_engine_cs *ring);
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct drm_device *dev,
 					  struct i915_address_space *vm, diff

--git

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct

Quoted 6 lines

a/drivers/gpu/drm/i915/i915_gem_context.c
b/drivers/gpu/drm/i915/i915_gem_context.c
index 9085ff1..0dc6992 100644

drivers/gpu/drm/i915/i915_gem_context.c +0 -0
@@ -513,8 +513,23 @@ int i915_gem_context_enable(struct

drm_i915_private *dev_priv)

Quoted 4 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -1
 		ppgtt->enable(ppgtt);
 	}
 
-	if (i915.enable_execlists)

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv)

Quoted 10 lines
drivers/gpu/drm/i915/i915_gem_context.c +10 -0
+	if (i915.enable_execlists) {
+		struct intel_context *dctx;
+
+		ring = &dev_priv->ring[RCS];
+		dctx = ring->default_context;
+
+		if (!dctx->rcs_initialized) {
+			ret = intel_lr_context_render_state_init(ring, dctx);
+			if (ret) {
+				DRM_ERROR("Init render state failed: %d\n",

ret);

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv) · line 532

Quoted 7 lines
drivers/gpu/drm/i915/i915_gem_context.c +6 -0
+				return ret;
+			}
+			dctx->rcs_initialized = true;
+		}
+
 		return 0;
+	}

This looks very much like the wrong place. We should init the render state when we create the context, or when we switch to it for the first time. The later is what the legacy contexts currently do in do_switch.

Quoted 1 line

But ctx_enable should do the switch to the default context and that's about

Well, a side-effect of switching to the default context in legacy mode is that the render state gets initialized. I could move the lr render state init call into an enable_execlists branch in i915_switch_context() but that doen't seem like the right place.

How about in i915_gem_init() after calling i915_gem_init_hw()?

Quoted 5 lines

it. If there's some depency then I guess we should stall the creation of the default context a bit, maybe.

In any case someone needs to explain this better and if there's not other wey this at least needs a bit comment. So I'll punt for now.

When the default context is created the driver is not ready to execute a batch. That is why the render state init can't be done then.

Thomas.

Quoted 273 lines

-Daniel

drivers/gpu/drm/i915/i915_gem_render_state.c int i915_gem_render_state_init(struct

Quoted 76 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 	/* FIXME: We should make this work, even in reset */
 	if (i915_reset_in_progress(&dev_priv->gpu_error))
drivers/gpu/drm/i915/i915_gem_render_state.c +0 -7
index e60be3f..a9a62d7 100644
@@ -28,13 +28,6 @@
 #include "i915_drv.h"
 #include "intel_renderstate.h"
 
-struct render_state {
-	const struct intel_renderstate_rodata *rodata;
-	struct drm_i915_gem_object *obj;
-	u64 ggtt_offset;
-	int gen;
-};
-
 static const struct intel_renderstate_rodata *

render_state_get_rodata(struct drm_device *dev, const int gen) { @@ -127,30 +120,47 @@ static int render_state_setup(struct render_state *so)

drivers/gpu/drm/i915/i915_gem_render_state.c +23 -7
 	return 0;
 }
 
-static void render_state_fini(struct render_state *so)
+void i915_gem_render_state_fini(struct render_state *so)
 {
 	i915_gem_object_ggtt_unpin(so->obj);
 	drm_gem_object_unreference(&so->obj->base);
 }
 
-int i915_gem_render_state_init(struct intel_engine_cs *ring)
+int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
+				  struct render_state *so)
 {
-	struct render_state so;
 	int ret;
 
 	if (WARN_ON(ring->id != RCS))
 		return -ENOENT;
 
-	ret = render_state_init(&so, ring->dev);
+	ret = render_state_init(so, ring->dev);
 	if (ret)
 		return ret;
 
-	if (so.rodata == NULL)
+	if (so->rodata == NULL)
 		return 0;
 
-	ret = render_state_setup(&so);
+	ret = render_state_setup(so);
+	if (ret) {
+		i915_gem_render_state_fini(so);
+		return ret;
+	}
+
+	return 0;
+}
+
+int i915_gem_render_state_init(struct intel_engine_cs *ring) {
+	struct render_state so;
+	int ret;
+
+	ret = i915_gem_render_state_prepare(ring, &so);
 	if (ret)
-		goto out;
+		return ret;
+
+	if (so.rodata == NULL)
+		return 0;
 
 	ret = ring->dispatch_execbuffer(ring,
 					so.ggtt_offset,
@@ -164,6 +174,6 @@ int i915_gem_render_state_init(struct

intel_engine_cs *ring)

Quoted 26 lines
drivers/gpu/drm/i915/i915_gem_render_state.c +1 -1
 	ret = __i915_add_request(ring, NULL, so.obj, NULL);
 	/* __i915_add_request moves object to inactive if it fails */
 out:
-	render_state_fini(&so);
+	i915_gem_render_state_fini(&so);
 	return ret;
 }
drivers/gpu/drm/i915/i915_gem_render_state.h new file +12 -0
new file mode 100644
index 0000000..c44961e
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+obtaining a
+ * copy of this software and associated documentation files (the
+"Software"),
+ * to deal in the Software without restriction, including without
+limitation
+ * the rights to use, copy, modify, merge, publish, distribute,
+sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom

drivers/gpu/drm/i915/i915_gem_render_state.h line 22

Quoted 10 lines
drivers/gpu/drm/i915/i915_gem_render_state.h new file +10 -0
+the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including
+the next
+ * paragraph) shall be included in all copies or substantial portions
+of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY

KIND,

drivers/gpu/drm/i915/i915_gem_render_state.h line 26

Quoted 4 lines
drivers/gpu/drm/i915/i915_gem_render_state.h new file +4 -0
+EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN

NO EVENT

drivers/gpu/drm/i915/i915_gem_render_state.h line 28

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_render_state.h new file +2 -0
+SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,

DAMAGES

drivers/gpu/drm/i915/i915_gem_render_state.h line 30

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_render_state.h new file +2 -0
+OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR

OTHERWISE,

drivers/gpu/drm/i915/i915_gem_render_state.h line 32

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_render_state.h new file +2 -0
+ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE

OR

Quoted 60 lines
drivers/gpu/drm/i915/i915_gem_render_state.h new file +28 -0
+OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _I915_GEM_RENDER_STATE_H_
+#define _I915_GEM_RENDER_STATE_H_
+
+#include <linux/types.h>
+
+struct intel_renderstate_rodata {
+	const u32 *reloc;
+	const u32 *batch;
+	const u32 batch_items;
+};
+
+struct render_state {
+	const struct intel_renderstate_rodata *rodata;
+	struct drm_i915_gem_object *obj;
+	u64 ggtt_offset;
+	int gen;
+};
+
+int i915_gem_render_state_init(struct intel_engine_cs *ring); void
+i915_gem_render_state_fini(struct render_state *so); int
+i915_gem_render_state_prepare(struct intel_engine_cs *ring,
+				  struct render_state *so);
+
+#endif /* _I915_GEM_RENDER_STATE_H_ */
drivers/gpu/drm/i915/intel_lrc.c +23 -0
index 0a04c03..4549eec 100644
@@ -925,6 +925,37 @@ cleanup_render_ring:
 	return ret;
 }
 
+int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+				       struct intel_context *ctx) {
+	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+	struct render_state so;
+	struct drm_i915_file_private *file_priv = ctx->file_priv;
+	struct drm_file *file = file_priv? file_priv->file : NULL;
+	int ret;
+
+	ret = i915_gem_render_state_prepare(ring, &so);
+	if (ret)
+		return ret;
+
+	if (so.rodata == NULL)
+		return 0;
+
+	ret = ring->emit_bb_start(ringbuf,
+			so.ggtt_offset,
+			I915_DISPATCH_SECURE);
+	if (ret)
+		goto out;
+
+	i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
+

drivers/gpu/drm/i915/intel_lrc.c cleanup_render_ring: · line 960

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +8 -0
+	ret = __i915_add_request(ring, file, so.obj, NULL);
+	/* intel_logical_ring_add_request moves object to inactive if it
+fails */
+out:
+	i915_gem_render_state_fini(&so);
+	return ret;
+}
+
 static int
 populate_lr_context(struct intel_context *ctx, struct

drm_i915_gem_object *ctx_obj,

drivers/gpu/drm/i915/intel_lrc.c cleanup_render_ring: · line 961

Quoted 1 line
drivers/gpu/drm/i915/intel_lrc.c +0 -0
 		    struct intel_engine_cs *ring, struct intel_ringbuffer

*ringbuf)

drivers/gpu/drm/i915/intel_lrc.c int intel_lr_context_deferred_create(struct

Quoted 1 line
drivers/gpu/drm/i915/intel_lrc.c +0 -0
@@ -1142,6 +1173,21 @@ int intel_lr_context_deferred_create(struct

intel_context *ctx,

Quoted 59 lines
drivers/gpu/drm/i915/intel_lrc.c +15 -0
 	ctx->engine[ring->id].ringbuf = ringbuf;
 	ctx->engine[ring->id].state = ctx_obj;
 
+	/* The default context will have to wait, because we are not yet
+	 * ready to send a batchbuffer at this point */
+	if (ring->id == RCS && !ctx->rcs_initialized &&
+			ctx != ring->default_context) {
+		ret = intel_lr_context_render_state_init(ring, ctx);
+		if (ret) {
+			DRM_ERROR("Init render state failed: %d\n", ret);
+			ctx->engine[ring->id].ringbuf = NULL;
+			ctx->engine[ring->id].state = NULL;
+			intel_destroy_ringbuffer_obj(ringbuf);
+			goto error;
+		}
+		ctx->rcs_initialized = true;
+	}
+
 	return 0;
 
 error:
drivers/gpu/drm/i915/intel_lrc.h +0 -0
index 696e09e..f20c3d2 100644
@@ -43,6 +43,8 @@ static inline void intel_logical_ring_emit(struct

intel_ringbuffer *ringbuf, u32 int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);

/* Logical Ring Contexts */

drivers/gpu/drm/i915/intel_lrc.h +2 -0
+int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+				       struct intel_context *ctx);
 void intel_lr_context_free(struct intel_context *ctx);  int

intel_lr_context_deferred_create(struct intel_context *ctx,
struct intel_engine_cs *ring); diff --git
a/drivers/gpu/drm/i915/intel_renderstate.h b/drivers/gpu/drm/i915/intel_renderstate.h
index fd4f662..6c792d3 100644

drivers/gpu/drm/i915/intel_renderstate.h +1 -8
@@ -24,13 +24,7 @@
 #ifndef _INTEL_RENDERSTATE_H
 #define _INTEL_RENDERSTATE_H
 
-#include <linux/types.h>
-
-struct intel_renderstate_rodata {
-	const u32 *reloc;
-	const u32 *batch;
-	const u32 batch_items;
-};
+#include "i915_drv.h"
 
 extern const struct intel_renderstate_rodata gen6_null_state;  extern
 const struct intel_renderstate_rodata gen7_null_state;
--

1.7.9.5

Quoted 4 lines

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#80 lore raw

Re: [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 51 lines · Thomas
Quoted 43 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 10:25 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 1 line · Thomas Daniel

From: Oscar Mateo <[email protected]>

index 9085ff1..0dc6992 100644

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
@@ -513,8 +513,23 @@ int i915_gem_context_enable(struct

drm_i915_private *dev_priv)

Quoted 4 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -1
 		ppgtt->enable(ppgtt);
 	}
 
-	if (i915.enable_execlists)

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv)

Quoted 10 lines
drivers/gpu/drm/i915/i915_gem_context.c +10 -0
+	if (i915.enable_execlists) {
+		struct intel_context *dctx;
+
+		ring = &dev_priv->ring[RCS];
+		dctx = ring->default_context;
+
+		if (!dctx->rcs_initialized) {
+			ret = intel_lr_context_render_state_init(ring, dctx);
+			if (ret) {
+				DRM_ERROR("Init render state failed: %d\n",

ret);

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv) · line 532

Quoted 7 lines
drivers/gpu/drm/i915/i915_gem_context.c +6 -0
+				return ret;
+			}
+			dctx->rcs_initialized = true;
+		}
+
 		return 0;
+	}

This looks very much like the wrong place. We should init the render state when we create the context, or when we switch to it for the first time. The later is what the legacy contexts currently do in do_switch.

Quoted 1 line

But ctx_enable should do the switch to the default context and that's about

Well, a side-effect of switching to the default context in legacy mode is that the render state gets initialized. I could move the lr render state init call into an enable_execlists branch in i915_switch_context() but that doen't seem like the right place.

How about in i915_gem_init() after calling i915_gem_init_hw()?

Quoted 7 lines
Quoted 5 lines

it. If there's some depency then I guess we should stall the creation of the default context a bit, maybe.

In any case someone needs to explain this better and if there's not other wey this at least needs a bit comment. So I'll punt for now.

When the default context is created the driver is not ready to execute a batch. That is why the render state init can't be done then.

That sounds like the default context is created too early. Essentially I want to avoid needless divergence between the default context and normal contexts, because sooner or later that will means someone will creep in with a _really_ subtle bug.

What about:
- We create the default lrc contexs in context_init, but like with a normal context we don't do any of the deferred setup.
- In context_enable (which since yesterday properly propagates errors to callers) we force the deferred lrc ctx setup for the default contexts on all engines.
- The render state init is done as part of the deferred ctx setup for the render engine in all cases.

Totally off the track or do you see a workable solution somewhere in that direction?

Cheers, Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#81 lore raw

Re: [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 74 lines · Daniel Vetter
Quoted 51 lines · Thomas
Quoted 43 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 10:25 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 1 line · Thomas Daniel

From: Oscar Mateo <[email protected]>

index 9085ff1..0dc6992 100644

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
@@ -513,8 +513,23 @@ int i915_gem_context_enable(struct

drm_i915_private *dev_priv)

Quoted 4 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -1
 		ppgtt->enable(ppgtt);
 	}
 
-	if (i915.enable_execlists)

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv)

Quoted 10 lines
drivers/gpu/drm/i915/i915_gem_context.c +10 -0
+	if (i915.enable_execlists) {
+		struct intel_context *dctx;
+
+		ring = &dev_priv->ring[RCS];
+		dctx = ring->default_context;
+
+		if (!dctx->rcs_initialized) {
+			ret = intel_lr_context_render_state_init(ring, dctx);
+			if (ret) {
+				DRM_ERROR("Init render state failed: %d\n",

ret);

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv) · line 532

Quoted 7 lines
drivers/gpu/drm/i915/i915_gem_context.c +6 -0
+				return ret;
+			}
+			dctx->rcs_initialized = true;
+		}
+
 		return 0;
+	}

This looks very much like the wrong place. We should init the render state when we create the context, or when we switch to it for the first time. The later is what the legacy contexts currently do in do_switch.

Quoted 1 line

But ctx_enable should do the switch to the default context and that's about

Well, a side-effect of switching to the default context in legacy mode is that the render state gets initialized. I could move the lr render state init call into an enable_execlists branch in i915_switch_context() but that doen't seem like the right place.

How about in i915_gem_init() after calling i915_gem_init_hw()?

Quoted 7 lines
Quoted 5 lines

it. If there's some depency then I guess we should stall the creation of the default context a bit, maybe.

In any case someone needs to explain this better and if there's not other wey this at least needs a bit comment. So I'll punt for now.

When the default context is created the driver is not ready to execute a batch. That is why the render state init can't be done then.

That sounds like the default context is created too early. Essentially I want to avoid needless divergence between the default context and normal contexts, because sooner or later that will means someone will creep in with a _really_ subtle bug.

What about:
- We create the default lrc contexs in context_init, but like with a normal context we don't do any of the deferred setup.
- In context_enable (which since yesterday properly propagates errors to callers) we force the deferred lrc ctx setup for the default contexts on all engines.
- The render state init is done as part of the deferred ctx setup for the render engine in all cases.

Quoted 2 lines

Totally off the track or do you see a workable solution somewhere in that direction?

I'd like to discuss this first a bit more, so will punt on this patch for now.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#82 lore raw

Re: [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 90 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Thursday, August 14, 2014 9:00 PM
To: Daniel, Thomas
Cc: Daniel Vetter; [email protected]
Subject: Re: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 20 lines · Daniel Vetter
Quoted 19 lines · Thomas
Quoted 19 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 10:25 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 1 line · Thomas Daniel

From: Oscar Mateo <[email protected]>

index 9085ff1..0dc6992 100644

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
@@ -513,8 +513,23 @@ int i915_gem_context_enable(struct

drm_i915_private *dev_priv)

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 		ppgtt->enable(ppgtt);
 	}
 
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv)

Quoted 9 lines
drivers/gpu/drm/i915/i915_gem_context.c +8 -1
-	if (i915.enable_execlists)
+	if (i915.enable_execlists) {
+		struct intel_context *dctx;
+
+		ring = &dev_priv->ring[RCS];
+		dctx = ring->default_context;
+
+		if (!dctx->rcs_initialized) {
+			ret = intel_lr_context_render_state_init(ring,

dctx);

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct · line 525

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_context.c +2 -0
+			if (ret) {
+				DRM_ERROR("Init render state failed:

%d\n",

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

ret);

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv) · line 532

Quoted 7 lines
drivers/gpu/drm/i915/i915_gem_context.c +6 -0
+				return ret;
+			}
+			dctx->rcs_initialized = true;
+		}
+
 		return 0;
+	}

This looks very much like the wrong place. We should init the render state when we create the context, or when we switch to it for

the first time.

Quoted 33 lines
Quoted 11 lines
Quoted 4 lines

The later is what the legacy contexts currently do in do_switch.

But ctx_enable should do the switch to the default context and that's about

Well, a side-effect of switching to the default context in legacy mode is that the render state gets initialized. I could move the lr render state init call into an enable_execlists branch in i915_switch_context() but that doen't seem like the right place.

How about in i915_gem_init() after calling i915_gem_init_hw()?

Quoted 7 lines
Quoted 5 lines

it. If there's some depency then I guess we should stall the creation of the default context a bit, maybe.

In any case someone needs to explain this better and if there's not other wey this at least needs a bit comment. So I'll punt for now.

When the default context is created the driver is not ready to execute a batch. That is why the render state init can't be done then.

That sounds like the default context is created too early. Essentially I want to avoid needless divergence between the default context and normal contexts, because sooner or later that will means someone will creep in with a _really_ subtle bug.

What about:
- We create the default lrc contexs in context_init, but like with a normal context we don't do any of the deferred setup.
- In context_enable (which since yesterday properly propagates errors to callers) we force the deferred lrc ctx setup for the default contexts on all engines.
- The render state init is done as part of the deferred ctx setup for the render engine in all cases.

Quoted 5 lines
Quoted 2 lines

Totally off the track or do you see a workable solution somewhere in that direction?

I'd like to discuss this first a bit more, so will punt on this patch for now. -Daniel

I think that your proposal will work. I've been having some trouble with my RVP board so haven't had a chance to test it out yet.

Thomas.

Quoted 4 lines

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#83 lore raw

Re: [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

In reply to Daniel Vetter
Quoted 104 lines

-----Original Message-----
From: Daniel, Thomas
Sent: Friday, August 15, 2014 9:44 AM
To: 'Daniel Vetter'
Cc: [email protected]
Subject: RE: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 92 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Thursday, August 14, 2014 9:00 PM
To: Daniel, Thomas
Cc: Daniel Vetter; [email protected]
Subject: Re: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 20 lines · Daniel Vetter
Quoted 19 lines · Thomas
Quoted 19 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 10:25 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 1 line · Thomas Daniel

From: Oscar Mateo <[email protected]>

index 9085ff1..0dc6992 100644

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
@@ -513,8 +513,23 @@ int i915_gem_context_enable(struct

drm_i915_private *dev_priv)

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 		ppgtt->enable(ppgtt);
 	}
 
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv)

Quoted 9 lines
drivers/gpu/drm/i915/i915_gem_context.c +8 -1
-	if (i915.enable_execlists)
+	if (i915.enable_execlists) {
+		struct intel_context *dctx;
+
+		ring = &dev_priv->ring[RCS];
+		dctx = ring->default_context;
+
+		if (!dctx->rcs_initialized) {
+			ret = intel_lr_context_render_state_init(ring,

dctx);

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct · line 525

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_context.c +2 -0
+			if (ret) {
+				DRM_ERROR("Init render state failed:

%d\n",

Quoted 12 lines
Quoted 12 lines
Quoted 12 lines

ret);

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv) · line 532

Quoted 7 lines
drivers/gpu/drm/i915/i915_gem_context.c +6 -0
+				return ret;
+			}
+			dctx->rcs_initialized = true;
+		}
+
 		return 0;
+	}

This looks very much like the wrong place. We should init the render state when we create the context, or when we switch to it for

the first time.

Quoted 35 lines
Quoted 11 lines
Quoted 4 lines

The later is what the legacy contexts currently do in do_switch.

But ctx_enable should do the switch to the default context and that's about

Well, a side-effect of switching to the default context in legacy mode is that the render state gets initialized. I could move the lr render state init call into an enable_execlists branch in i915_switch_context() but that doen't seem like the right place.

How about in i915_gem_init() after calling i915_gem_init_hw()?

Quoted 7 lines
Quoted 5 lines

it. If there's some depency then I guess we should stall the creation of the default context a bit, maybe.

In any case someone needs to explain this better and if there's not other wey this at least needs a bit comment. So I'll punt for now.

When the default context is created the driver is not ready to execute a batch. That is why the render state init can't be done then.

That sounds like the default context is created too early. Essentially I want to avoid needless divergence between the default context and normal contexts, because sooner or later that will means someone will creep in with a _really_ subtle bug.

What about:
- We create the default lrc contexs in context_init, but like with a normal context we don't do any of the deferred setup.
- In context_enable (which since yesterday properly propagates errors to callers) we force the deferred lrc ctx setup for the default contexts on all engines.
- The render state init is done as part of the deferred ctx setup for the render engine in all cases.

Totally off the track or do you see a workable solution somewhere in that direction?

Quoted 6 lines
Quoted 2 lines

I'd like to discuss this first a bit more, so will punt on this patch for now. -Daniel

I think that your proposal will work. I've been having some trouble with my RVP board so haven't had a chance to test it out yet.

Thomas.

I've now tried this out and I don't think it can work without introducing more problems than the original patch. Trouble is that in lrc mode the Hardware Status Page is offset 0 from the context. All contexts use the default context's HWSP for writing seqnos, this is stored in ring->status_page. We can't populate this until the deferred creation of the default context is done, so we can't execute any instructions in the deferred creation (unless we check for default context in the deferred creation which is what we wanted to avoid in the first place).

Thomas.

Quoted 4 lines
Quoted 4 lines

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#84 lore raw

Re: [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 110 lines · Thomas
Quoted 104 lines

-----Original Message-----
From: Daniel, Thomas
Sent: Friday, August 15, 2014 9:44 AM
To: 'Daniel Vetter'
Cc: [email protected]
Subject: RE: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 92 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Thursday, August 14, 2014 9:00 PM
To: Daniel, Thomas
Cc: Daniel Vetter; [email protected]
Subject: Re: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 20 lines · Daniel Vetter
Quoted 19 lines · Thomas
Quoted 19 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Monday, August 11, 2014 10:25 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 27/43] drm/i915/bdw: Render state init for Execlists

Quoted 1 line · Thomas Daniel

From: Oscar Mateo <[email protected]>

index 9085ff1..0dc6992 100644

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
@@ -513,8 +513,23 @@ int i915_gem_context_enable(struct

drm_i915_private *dev_priv)

Quoted 3 lines
drivers/gpu/drm/i915/i915_gem_context.c +0 -0
 		ppgtt->enable(ppgtt);
 	}
 
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv)

Quoted 9 lines
drivers/gpu/drm/i915/i915_gem_context.c +8 -1
-	if (i915.enable_execlists)
+	if (i915.enable_execlists) {
+		struct intel_context *dctx;
+
+		ring = &dev_priv->ring[RCS];
+		dctx = ring->default_context;
+
+		if (!dctx->rcs_initialized) {
+			ret = intel_lr_context_render_state_init(ring,

dctx);

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct · line 525

Quoted 2 lines
drivers/gpu/drm/i915/i915_gem_context.c +2 -0
+			if (ret) {
+				DRM_ERROR("Init render state failed:

%d\n",

Quoted 12 lines
Quoted 12 lines
Quoted 12 lines

ret);

drivers/gpu/drm/i915/i915_gem_context.c int i915_gem_context_enable(struct drm_i915_private *dev_priv) · line 532

Quoted 7 lines
drivers/gpu/drm/i915/i915_gem_context.c +6 -0
+				return ret;
+			}
+			dctx->rcs_initialized = true;
+		}
+
 		return 0;
+	}

This looks very much like the wrong place. We should init the render state when we create the context, or when we switch to it for

the first time.

Quoted 35 lines
Quoted 11 lines
Quoted 4 lines

The later is what the legacy contexts currently do in do_switch.

But ctx_enable should do the switch to the default context and that's about

Well, a side-effect of switching to the default context in legacy mode is that the render state gets initialized. I could move the lr render state init call into an enable_execlists branch in i915_switch_context() but that doen't seem like the right place.

How about in i915_gem_init() after calling i915_gem_init_hw()?

Quoted 7 lines
Quoted 5 lines

it. If there's some depency then I guess we should stall the creation of the default context a bit, maybe.

In any case someone needs to explain this better and if there's not other wey this at least needs a bit comment. So I'll punt for now.

When the default context is created the driver is not ready to execute a batch. That is why the render state init can't be done then.

That sounds like the default context is created too early. Essentially I want to avoid needless divergence between the default context and normal contexts, because sooner or later that will means someone will creep in with a _really_ subtle bug.

What about:
- We create the default lrc contexs in context_init, but like with a normal context we don't do any of the deferred setup.
- In context_enable (which since yesterday properly propagates errors to callers) we force the deferred lrc ctx setup for the default contexts on all engines.
- The render state init is done as part of the deferred ctx setup for the render engine in all cases.

Totally off the track or do you see a workable solution somewhere in that direction?

Quoted 6 lines
Quoted 2 lines

I'd like to discuss this first a bit more, so will punt on this patch for now. -Daniel

I think that your proposal will work. I've been having some trouble with my RVP board so haven't had a chance to test it out yet.

Thomas.

Quoted 8 lines

I've now tried this out and I don't think it can work without introducing more problems than the original patch. Trouble is that in lrc mode the Hardware Status Page is offset 0 from the context. All contexts use the default context's HWSP for writing seqnos, this is stored in ring->status_page. We can't populate this until the deferred creation of the default context is done, so we can't execute any instructions in the deferred creation (unless we check for default context in the deferred creation which is what we wanted to avoid in the first place).

That just sounds like we should either allocate the HWS at engine init time (since it's shared across all rings). Or that we should switch to per-ring/ctx hws, but that's probably only something for when the scheduler shows up.

Or is there some other blocker?

Generally I really don't like to bend over backwards in the init code if we get such initialization ordering constraints wrong - in the past that really has been a fairly awesome source of bugs. What's needed though is a pile of WARN_ON to check that the initialization ordering is done in the right way, in case someone touches the code. That still means runtime testing, but that's still a lot better than silent failures. -Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#85 lore raw

PATCH 1/1 drm/i915/bdw: Render state init for Execlists

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

The batchbuffer that sets the render context state is submitted in a different way, and from different places.

We needed to make both the render state preparation and free functions outside accesible, and namespace accordingly. This mess is so that all LR, LRC and Execlists functionality can go together in intel_lrc.c: we can fix all of this later on, once the interfaces are clear.

v2: Create a separate ctx->rcs_initialized for the Execlists case, as suggested by Chris Wilson.

v3: Setup ring status page in lr_context_deferred_create when the default context is being created. This means that the render state init for the default context is no longer a special case. Execute deferred creation of the default context at the end of logical_ring_init to allow the render state commands to be submitted. Fix style errors reported by checkpatch. Rebased.

---
 drivers/gpu/drm/i915/i915_drv.h              |    4 +-
 drivers/gpu/drm/i915/i915_gem_render_state.c |   40 ++++++++------
 drivers/gpu/drm/i915/i915_gem_render_state.h |   47 +++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.c             |   73 ++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_lrc.h             |    2 +
 drivers/gpu/drm/i915/intel_renderstate.h     |    8 +--
 6 files changed, 135 insertions(+), 39 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/i915_gem_render_state.h
drivers/gpu/drm/i915/i915_drv.h +2 -2
index e449f81..f416e341 100644
@@ -37,6 +37,7 @@
 #include "intel_ringbuffer.h"
 #include "intel_lrc.h"
 #include "i915_gem_gtt.h"
+#include "i915_gem_render_state.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -635,6 +636,7 @@ struct intel_context {
 	} legacy_hw_ctx;
 
 	/* Execlists */
+	bool rcs_initialized;
 	struct {
 		struct drm_i915_gem_object *state;
 		struct intel_ringbuffer *ringbuf;
@@ -2596,8 +2598,6 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 				   struct drm_file *file);
 
-/* i915_gem_render_state.c */
-int i915_gem_render_state_init(struct intel_engine_cs *ring);
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct drm_device *dev,
 					  struct i915_address_space *vm,
drivers/gpu/drm/i915/i915_gem_render_state.c +25 -15
index e60be3f..a9a62d7 100644
@@ -28,13 +28,6 @@
 #include "i915_drv.h"
 #include "intel_renderstate.h"
 
-struct render_state {
-	const struct intel_renderstate_rodata *rodata;
-	struct drm_i915_gem_object *obj;
-	u64 ggtt_offset;
-	int gen;
-};
-
 static const struct intel_renderstate_rodata *
 render_state_get_rodata(struct drm_device *dev, const int gen)
 {
@@ -127,30 +120,47 @@ static int render_state_setup(struct render_state *so)
 	return 0;
 }
 
-static void render_state_fini(struct render_state *so)
+void i915_gem_render_state_fini(struct render_state *so)
 {
 	i915_gem_object_ggtt_unpin(so->obj);
 	drm_gem_object_unreference(&so->obj->base);
 }
 
-int i915_gem_render_state_init(struct intel_engine_cs *ring)
+int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
+				  struct render_state *so)
 {
-	struct render_state so;
 	int ret;
 
 	if (WARN_ON(ring->id != RCS))
 		return -ENOENT;
 
-	ret = render_state_init(&so, ring->dev);
+	ret = render_state_init(so, ring->dev);
 	if (ret)
 		return ret;
 
-	if (so.rodata == NULL)
+	if (so->rodata == NULL)
 		return 0;
 
-	ret = render_state_setup(&so);
+	ret = render_state_setup(so);
+	if (ret) {
+		i915_gem_render_state_fini(so);
+		return ret;
+	}
+
+	return 0;
+}
+
+int i915_gem_render_state_init(struct intel_engine_cs *ring)
+{
+	struct render_state so;
+	int ret;
+
+	ret = i915_gem_render_state_prepare(ring, &so);
 	if (ret)
-		goto out;
+		return ret;
+
+	if (so.rodata == NULL)
+		return 0;
 
 	ret = ring->dispatch_execbuffer(ring,
 					so.ggtt_offset,
@@ -164,6 +174,6 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring)
 	ret = __i915_add_request(ring, NULL, so.obj, NULL);
 	/* __i915_add_request moves object to inactive if it fails */
 out:
-	render_state_fini(&so);
+	i915_gem_render_state_fini(&so);
 	return ret;
 }
drivers/gpu/drm/i915/i915_gem_render_state.h new file +47 -0

47 lines not on this page · raw message

drivers/gpu/drm/i915/intel_lrc.c +58 -15

103 lines not on this page · raw message

drivers/gpu/drm/i915/intel_lrc.h +2 -0
index 991d449..33c3b4b 100644
@@ -62,6 +62,8 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf,
 int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
 
 /* Logical Ring Contexts */
+int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+				       struct intel_context *ctx);
 void intel_lr_context_free(struct intel_context *ctx);
 int intel_lr_context_deferred_create(struct intel_context *ctx,
 				     struct intel_engine_cs *ring);
drivers/gpu/drm/i915/intel_renderstate.h +1 -7
index fd4f662..6c792d3 100644
@@ -24,13 +24,7 @@
 #ifndef _INTEL_RENDERSTATE_H
 #define _INTEL_RENDERSTATE_H
 
-#include <linux/types.h>
-
-struct intel_renderstate_rodata {
-	const u32 *reloc;
-	const u32 *batch;
-	const u32 batch_items;
-};
+#include "i915_drv.h"
 
 extern const struct intel_renderstate_rodata gen6_null_state;
 extern const struct intel_renderstate_rodata gen7_null_state;
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#86 lore raw

Re: [PATCH] drm/i915/bdw: Render state init for Execlists

Quoted 15 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

The batchbuffer that sets the render context state is submitted in a different way, and from different places.

We needed to make both the render state preparation and free functions outside accesible, and namespace accordingly. This mess is so that all LR, LRC and Execlists functionality can go together in intel_lrc.c: we can fix all of this later on, once the interfaces are clear.

v2: Create a separate ctx->rcs_initialized for the Execlists case, as suggested by Chris Wilson.

Quoted 8 lines

v3: Setup ring status page in lr_context_deferred_create when the default context is being created. This means that the render state init for the default context is no longer a special case. Execute deferred creation of the default context at the end of logical_ring_init to allow the render state commands to be submitted. Fix style errors reported by checkpatch. Rebased.

Queued for -next, thanks for the patch.
-Daniel

Quoted 324 lines
---
 drivers/gpu/drm/i915/i915_drv.h              |    4 +-
 drivers/gpu/drm/i915/i915_gem_render_state.c |   40 ++++++++------
 drivers/gpu/drm/i915/i915_gem_render_state.h |   47 +++++++++++++++++
 drivers/gpu/drm/i915/intel_lrc.c             |   73 ++++++++++++++++++++------
 drivers/gpu/drm/i915/intel_lrc.h             |    2 +
 drivers/gpu/drm/i915/intel_renderstate.h     |    8 +--
 6 files changed, 135 insertions(+), 39 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/i915_gem_render_state.h
drivers/gpu/drm/i915/i915_drv.h +2 -2
index e449f81..f416e341 100644
@@ -37,6 +37,7 @@
 #include "intel_ringbuffer.h"
 #include "intel_lrc.h"
 #include "i915_gem_gtt.h"
+#include "i915_gem_render_state.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
@@ -635,6 +636,7 @@ struct intel_context {
 	} legacy_hw_ctx;
 
 	/* Execlists */
+	bool rcs_initialized;
 	struct {
 		struct drm_i915_gem_object *state;
 		struct intel_ringbuffer *ringbuf;
@@ -2596,8 +2598,6 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 				   struct drm_file *file);
 
-/* i915_gem_render_state.c */
-int i915_gem_render_state_init(struct intel_engine_cs *ring);
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct drm_device *dev,
 					  struct i915_address_space *vm,
drivers/gpu/drm/i915/i915_gem_render_state.c +25 -15
index e60be3f..a9a62d7 100644
@@ -28,13 +28,6 @@
 #include "i915_drv.h"
 #include "intel_renderstate.h"
 
-struct render_state {
-	const struct intel_renderstate_rodata *rodata;
-	struct drm_i915_gem_object *obj;
-	u64 ggtt_offset;
-	int gen;
-};
-
 static const struct intel_renderstate_rodata *
 render_state_get_rodata(struct drm_device *dev, const int gen)
 {
@@ -127,30 +120,47 @@ static int render_state_setup(struct render_state *so)
 	return 0;
 }
 
-static void render_state_fini(struct render_state *so)
+void i915_gem_render_state_fini(struct render_state *so)
 {
 	i915_gem_object_ggtt_unpin(so->obj);
 	drm_gem_object_unreference(&so->obj->base);
 }
 
-int i915_gem_render_state_init(struct intel_engine_cs *ring)
+int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
+				  struct render_state *so)
 {
-	struct render_state so;
 	int ret;
 
 	if (WARN_ON(ring->id != RCS))
 		return -ENOENT;
 
-	ret = render_state_init(&so, ring->dev);
+	ret = render_state_init(so, ring->dev);
 	if (ret)
 		return ret;
 
-	if (so.rodata == NULL)
+	if (so->rodata == NULL)
 		return 0;
 
-	ret = render_state_setup(&so);
+	ret = render_state_setup(so);
+	if (ret) {
+		i915_gem_render_state_fini(so);
+		return ret;
+	}
+
+	return 0;
+}
+
+int i915_gem_render_state_init(struct intel_engine_cs *ring)
+{
+	struct render_state so;
+	int ret;
+
+	ret = i915_gem_render_state_prepare(ring, &so);
 	if (ret)
-		goto out;
+		return ret;
+
+	if (so.rodata == NULL)
+		return 0;
 
 	ret = ring->dispatch_execbuffer(ring,
 					so.ggtt_offset,
@@ -164,6 +174,6 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring)
 	ret = __i915_add_request(ring, NULL, so.obj, NULL);
 	/* __i915_add_request moves object to inactive if it fails */
 out:
-	render_state_fini(&so);
+	i915_gem_render_state_fini(&so);
 	return ret;
 }
drivers/gpu/drm/i915/i915_gem_render_state.h new file +47 -0
new file mode 100644
index 0000000..c44961e
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _I915_GEM_RENDER_STATE_H_
+#define _I915_GEM_RENDER_STATE_H_
+
+#include <linux/types.h>
+
+struct intel_renderstate_rodata {
+	const u32 *reloc;
+	const u32 *batch;
+	const u32 batch_items;
+};
+
+struct render_state {
+	const struct intel_renderstate_rodata *rodata;
+	struct drm_i915_gem_object *obj;
+	u64 ggtt_offset;
+	int gen;
+};
+
+int i915_gem_render_state_init(struct intel_engine_cs *ring);
+void i915_gem_render_state_fini(struct render_state *so);
+int i915_gem_render_state_prepare(struct intel_engine_cs *ring,
+				  struct render_state *so);
+
+#endif /* _I915_GEM_RENDER_STATE_H_ */
drivers/gpu/drm/i915/intel_lrc.c +58 -15
index c096b9b..8e51fd0 100644
@@ -1217,8 +1217,6 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
 static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring)
 {
 	int ret;
-	struct intel_context *dctx = ring->default_context;
-	struct drm_i915_gem_object *dctx_obj;
 
 	/* Intentionally left blank. */
 	ring->buffer = NULL;
@@ -1232,18 +1230,6 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
 	spin_lock_init(&ring->execlist_lock);
 	ring->next_context_status_buffer = 0;
 
-	ret = intel_lr_context_deferred_create(dctx, ring);
-	if (ret)
-		return ret;
-
-	/* The status page is offset 0 from the context object in LRCs. */
-	dctx_obj = dctx->engine[ring->id].state;
-	ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(dctx_obj);
-	ring->status_page.page_addr = kmap(sg_page(dctx_obj->pages->sgl));
-	if (ring->status_page.page_addr == NULL)
-		return -ENOMEM;
-	ring->status_page.obj = dctx_obj;
-
 	ret = i915_cmd_parser_init_ring(ring);
 	if (ret)
 		return ret;
@@ -1254,7 +1240,9 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
 			return ret;
 	}
 
-	return 0;
+	ret = intel_lr_context_deferred_create(ring->default_context, ring);
+
+	return ret;
 }
 
 static int logical_render_ring_init(struct drm_device *dev)
@@ -1448,6 +1436,38 @@ cleanup_render_ring:
 	return ret;
 }
 
+int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+				       struct intel_context *ctx)
+{
+	struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+	struct render_state so;
+	struct drm_i915_file_private *file_priv = ctx->file_priv;
+	struct drm_file *file = file_priv ? file_priv->file : NULL;
+	int ret;
+
+	ret = i915_gem_render_state_prepare(ring, &so);
+	if (ret)
+		return ret;
+
+	if (so.rodata == NULL)
+		return 0;
+
+	ret = ring->emit_bb_start(ringbuf,
+			so.ggtt_offset,
+			I915_DISPATCH_SECURE);
+	if (ret)
+		goto out;
+
+	i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
+
+	ret = __i915_add_request(ring, file, so.obj, NULL);
+	/* intel_logical_ring_add_request moves object to inactive if it
+	 * fails */
+out:
+	i915_gem_render_state_fini(&so);
+	return ret;
+}
+
 static int
 populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_obj,
 		    struct intel_engine_cs *ring, struct intel_ringbuffer *ringbuf)
@@ -1687,6 +1707,29 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
 	ctx->engine[ring->id].ringbuf = ringbuf;
 	ctx->engine[ring->id].state = ctx_obj;
 
+	if (ctx == ring->default_context) {
+		/* The status page is offset 0 from the default context object
+		 * in LRC mode. */
+		ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(ctx_obj);
+		ring->status_page.page_addr =
+				kmap(sg_page(ctx_obj->pages->sgl));
+		if (ring->status_page.page_addr == NULL)
+			return -ENOMEM;
+		ring->status_page.obj = ctx_obj;
+	}
+
+	if (ring->id == RCS && !ctx->rcs_initialized) {
+		ret = intel_lr_context_render_state_init(ring, ctx);
+		if (ret) {
+			DRM_ERROR("Init render state failed: %d\n", ret);
+			ctx->engine[ring->id].ringbuf = NULL;
+			ctx->engine[ring->id].state = NULL;
+			intel_destroy_ringbuffer_obj(ringbuf);
+			goto error;
+		}
+		ctx->rcs_initialized = true;
+	}
+
 	return 0;
 
 error:
drivers/gpu/drm/i915/intel_lrc.h +2 -0
index 991d449..33c3b4b 100644
@@ -62,6 +62,8 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf,
 int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
 
 /* Logical Ring Contexts */
+int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
+				       struct intel_context *ctx);
 void intel_lr_context_free(struct intel_context *ctx);
 int intel_lr_context_deferred_create(struct intel_context *ctx,
 				     struct intel_engine_cs *ring);
drivers/gpu/drm/i915/intel_renderstate.h +1 -7
index fd4f662..6c792d3 100644
@@ -24,13 +24,7 @@
 #ifndef _INTEL_RENDERSTATE_H
 #define _INTEL_RENDERSTATE_H
 
-#include <linux/types.h>
-
-struct intel_renderstate_rodata {
-	const u32 *reloc;
-	const u32 *batch;
-	const u32 batch_items;
-};
+#include "i915_drv.h"
 
 extern const struct intel_renderstate_rodata gen6_null_state;
 extern const struct intel_renderstate_rodata gen7_null_state;
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#87 lore raw

PATCH 28/43 drm/i915/bdw: Implement context switching (somewhat)

In reply to Thomas Daniel

From: Ben Widawsky <[email protected]>

A context switch occurs by submitting a context descriptor to the ExecList Submission Port. Given that we can now initialize a context, it's possible to begin implementing the context switch by creating the descriptor and submitting it to ELSP (actually two, since the ELSP has two ports).

The context object must be mapped in the GGTT, which means it must exist in the 0-4GB graphics VA range.

v2: This code has changed quite a lot in various rebases. Of particular importance is that now we use the globally unique Submission ID to send to the hardware. Also, context pages are now pinned unconditionally to GGTT, so there is no need to bind them.

v3: Use LRCA[31:12] as hwCtxId[19:0]. This guarantees that the HW context ID we submit to the ELSP is globally unique and != 0 (Bspec requirements of the software use-only bits of the Context ID in the Context Descriptor Format) without the hassle of the previous submission Id construction. Also, re-add the ELSP porting read (it was dropped somewhere during the rebases).

v4:
- Squash with "drm/i915/bdw: Add forcewake lock around ELSP writes" (BSPEC
says: "SW must set Force Wakeup bit to prevent GT from entering C6 while ELSP writes are in progress") as noted by Thomas Daniel ([email protected]).
- Rename functions and use an execlists/intel_execlists_ namespace.
- The BUG_ON only checked that the LRCA was <32 bits, but it didn't make sure that it was properly aligned. Spotted by Alistair Mcaulay <[email protected]>.

v5:
- Improved source code comments as suggested by Chris Wilson.
- No need to abstract submit_ctx away, as pointed by Brad Volkin.

---
 drivers/gpu/drm/i915/intel_lrc.c |  116 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_lrc.h |    1 +
 2 files changed, 115 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +114 -2
index 4549eec..535ef98 100644
@@ -47,6 +47,7 @@
 #define GEN8_LR_CONTEXT_ALIGN 4096
 
 #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 CTX_LRI_HEADER_0		0x01
@@ -78,6 +79,26 @@
 #define CTX_R_PWR_CLK_STATE		0x42
 #define CTX_GPGPU_CSR_BASE_ADDRESS	0x44
 
+#define GEN8_CTX_VALID (1<<0)
+#define GEN8_CTX_FORCE_PD_RESTORE (1<<1)
+#define GEN8_CTX_FORCE_RESTORE (1<<2)
+#define GEN8_CTX_L3LLC_COHERENT (1<<5)
+#define GEN8_CTX_PRIVILEGE (1<<8)
+enum {
+	ADVANCED_CONTEXT=0,
+	LEGACY_CONTEXT,
+	ADVANCED_AD_CONTEXT,
+	LEGACY_64B_CONTEXT
+};
+#define GEN8_CTX_MODE_SHIFT 3
+enum {
+	FAULT_AND_HANG=0,
+	FAULT_AND_HALT, /* Debug only */
+	FAULT_AND_STREAM,
+	FAULT_AND_CONTINUE /* Unsupported */
+};
+#define GEN8_CTX_ID_SHIFT 32
+
 int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists)
 {
 	if (enable_execlists == 0)
@@ -90,6 +111,93 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
 	return 0;
 }
 
+u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj)
+{
+	u32 lrca = i915_gem_obj_ggtt_offset(ctx_obj);
+
+	/* LRCA is required to be 4K aligned so the more significant 20 bits
+	 * are globally unique */
+	return lrca >> 12;
+}
+
+static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_object *ctx_obj)
+{
+	uint64_t desc;
+	uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj);
+	BUG_ON(lrca & 0xFFFFFFFF00000FFFULL);
+
+	desc = GEN8_CTX_VALID;
+	desc |= LEGACY_CONTEXT << GEN8_CTX_MODE_SHIFT;
+	desc |= GEN8_CTX_L3LLC_COHERENT;
+	desc |= GEN8_CTX_PRIVILEGE;
+	desc |= lrca;
+	desc |= (u64)intel_execlists_ctx_id(ctx_obj) << GEN8_CTX_ID_SHIFT;
+
+	/* TODO: WaDisableLiteRestore when we start using semaphore
+	 * signalling between Command Streamers */
+	/* desc |= GEN8_CTX_FORCE_RESTORE; */
+
+	return desc;
+}
+
+static void execlists_elsp_write(struct intel_engine_cs *ring,
+				 struct drm_i915_gem_object *ctx_obj0,
+				 struct drm_i915_gem_object *ctx_obj1)
+{
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	uint64_t temp = 0;
+	uint32_t desc[4];
+
+	/* XXX: You must always write both descriptors in the order below. */
+	if (ctx_obj1)
+		temp = execlists_ctx_descriptor(ctx_obj1);
+	else
+		temp = 0;
+	desc[1] = (u32)(temp >> 32);
+	desc[0] = (u32)temp;
+
+	temp = execlists_ctx_descriptor(ctx_obj0);
+	desc[3] = (u32)(temp >> 32);
+	desc[2] = (u32)temp;
+
+	/* Set Force Wakeup bit to prevent GT from entering C6 while
+	 * ELSP writes are in progress */
+	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+
+	I915_WRITE(RING_ELSP(ring), desc[1]);
+	I915_WRITE(RING_ELSP(ring), desc[0]);
+	I915_WRITE(RING_ELSP(ring), desc[3]);
+	/* The context is automatically loaded after the following */
+	I915_WRITE(RING_ELSP(ring), desc[2]);
+
+	/* ELSP is a wo register, so use another nearby reg for posting instead */
+	POSTING_READ(RING_EXECLIST_STATUS(ring));
+
+	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+}
+
+static int execlists_submit_context(struct intel_engine_cs *ring,
+				    struct intel_context *to0, u32 tail0,
+				    struct intel_context *to1, u32 tail1)
+{
+	struct drm_i915_gem_object *ctx_obj0;
+	struct drm_i915_gem_object *ctx_obj1 = NULL;
+
+	ctx_obj0 = to0->engine[ring->id].state;
+	BUG_ON(!ctx_obj0);
+	BUG_ON(!i915_gem_obj_is_pinned(ctx_obj0));
+
+	if (to1) {
+		ctx_obj1 = to1->engine[ring->id].state;
+		BUG_ON(!ctx_obj1);
+		BUG_ON(!i915_gem_obj_is_pinned(ctx_obj1));
+	}
+
+	execlists_elsp_write(ring, ctx_obj0, ctx_obj1);
+
+	return 0;
+}
+
 static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
@@ -270,12 +378,16 @@ int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
 
 void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
 {
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct intel_context *ctx = ringbuf->ctx;
+
 	intel_logical_ring_advance(ringbuf);
 
-	if (intel_ring_stopped(ringbuf->ring))
+	if (intel_ring_stopped(ring))
 		return;
 
-	/* TODO: how to submit a context to the ELSP is not here yet */
+	/* FIXME: too cheeky, we don't even check if the ELSP is ready */
+	execlists_submit_context(ring, ctx, ringbuf->tail, NULL, 0);
 }
 
 static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
drivers/gpu/drm/i915/intel_lrc.h +1 -0
index f20c3d2..b59965b 100644
@@ -58,5 +58,6 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
 			       struct list_head *vmas,
 			       struct drm_i915_gem_object *batch_obj,
 			       u64 exec_start, u32 flags);
+u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
 
 #endif /* _INTEL_LRC_H_ */
Signature · 1 line
1.7.9.5
#88 lore raw

Re: [PATCH 28/43] drm/i915/bdw: Implement context switching (somewhat)

Quoted 184 lines · Thomas Daniel

From: Ben Widawsky <[email protected]>

A context switch occurs by submitting a context descriptor to the ExecList Submission Port. Given that we can now initialize a context, it's possible to begin implementing the context switch by creating the descriptor and submitting it to ELSP (actually two, since the ELSP has two ports).

The context object must be mapped in the GGTT, which means it must exist in the 0-4GB graphics VA range.

v2: This code has changed quite a lot in various rebases. Of particular importance is that now we use the globally unique Submission ID to send to the hardware. Also, context pages are now pinned unconditionally to GGTT, so there is no need to bind them.

v3: Use LRCA[31:12] as hwCtxId[19:0]. This guarantees that the HW context ID we submit to the ELSP is globally unique and != 0 (Bspec requirements of the software use-only bits of the Context ID in the Context Descriptor Format) without the hassle of the previous submission Id construction. Also, re-add the ELSP porting read (it was dropped somewhere during the rebases).

v4:
- Squash with "drm/i915/bdw: Add forcewake lock around ELSP writes" (BSPEC
says: "SW must set Force Wakeup bit to prevent GT from entering C6 while ELSP writes are in progress") as noted by Thomas Daniel ([email protected]).
- Rename functions and use an execlists/intel_execlists_ namespace.
- The BUG_ON only checked that the LRCA was <32 bits, but it didn't make sure that it was properly aligned. Spotted by Alistair Mcaulay <[email protected]>.

v5:
- Improved source code comments as suggested by Chris Wilson.
- No need to abstract submit_ctx away, as pointed by Brad Volkin.

---
 drivers/gpu/drm/i915/intel_lrc.c |  116 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_lrc.h |    1 +
 2 files changed, 115 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +110 -0
index 4549eec..535ef98 100644
@@ -47,6 +47,7 @@
 #define GEN8_LR_CONTEXT_ALIGN 4096
 
 #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 CTX_LRI_HEADER_0		0x01
@@ -78,6 +79,26 @@
 #define CTX_R_PWR_CLK_STATE		0x42
 #define CTX_GPGPU_CSR_BASE_ADDRESS	0x44
 
+#define GEN8_CTX_VALID (1<<0)
+#define GEN8_CTX_FORCE_PD_RESTORE (1<<1)
+#define GEN8_CTX_FORCE_RESTORE (1<<2)
+#define GEN8_CTX_L3LLC_COHERENT (1<<5)
+#define GEN8_CTX_PRIVILEGE (1<<8)
+enum {
+	ADVANCED_CONTEXT=0,
+	LEGACY_CONTEXT,
+	ADVANCED_AD_CONTEXT,
+	LEGACY_64B_CONTEXT
+};
+#define GEN8_CTX_MODE_SHIFT 3
+enum {
+	FAULT_AND_HANG=0,
+	FAULT_AND_HALT, /* Debug only */
+	FAULT_AND_STREAM,
+	FAULT_AND_CONTINUE /* Unsupported */
+};
+#define GEN8_CTX_ID_SHIFT 32
+
 int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists)
 {
 	if (enable_execlists == 0)
@@ -90,6 +111,93 @@ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists
 	return 0;
 }
 
+u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj)
+{
+	u32 lrca = i915_gem_obj_ggtt_offset(ctx_obj);
+
+	/* LRCA is required to be 4K aligned so the more significant 20 bits
+	 * are globally unique */
+	return lrca >> 12;
+}
+
+static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_object *ctx_obj)
+{
+	uint64_t desc;
+	uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj);
+	BUG_ON(lrca & 0xFFFFFFFF00000FFFULL);
+
+	desc = GEN8_CTX_VALID;
+	desc |= LEGACY_CONTEXT << GEN8_CTX_MODE_SHIFT;
+	desc |= GEN8_CTX_L3LLC_COHERENT;
+	desc |= GEN8_CTX_PRIVILEGE;
+	desc |= lrca;
+	desc |= (u64)intel_execlists_ctx_id(ctx_obj) << GEN8_CTX_ID_SHIFT;
+
+	/* TODO: WaDisableLiteRestore when we start using semaphore
+	 * signalling between Command Streamers */
+	/* desc |= GEN8_CTX_FORCE_RESTORE; */
+
+	return desc;
+}
+
+static void execlists_elsp_write(struct intel_engine_cs *ring,
+				 struct drm_i915_gem_object *ctx_obj0,
+				 struct drm_i915_gem_object *ctx_obj1)
+{
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	uint64_t temp = 0;
+	uint32_t desc[4];
+
+	/* XXX: You must always write both descriptors in the order below. */
+	if (ctx_obj1)
+		temp = execlists_ctx_descriptor(ctx_obj1);
+	else
+		temp = 0;
+	desc[1] = (u32)(temp >> 32);
+	desc[0] = (u32)temp;
+
+	temp = execlists_ctx_descriptor(ctx_obj0);
+	desc[3] = (u32)(temp >> 32);
+	desc[2] = (u32)temp;
+
+	/* Set Force Wakeup bit to prevent GT from entering C6 while
+	 * ELSP writes are in progress */
+	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+
+	I915_WRITE(RING_ELSP(ring), desc[1]);
+	I915_WRITE(RING_ELSP(ring), desc[0]);
+	I915_WRITE(RING_ELSP(ring), desc[3]);
+	/* The context is automatically loaded after the following */
+	I915_WRITE(RING_ELSP(ring), desc[2]);
+
+	/* ELSP is a wo register, so use another nearby reg for posting instead */
+	POSTING_READ(RING_EXECLIST_STATUS(ring));
+
+	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+}
+
+static int execlists_submit_context(struct intel_engine_cs *ring,
+				    struct intel_context *to0, u32 tail0,
+				    struct intel_context *to1, u32 tail1)
+{
+	struct drm_i915_gem_object *ctx_obj0;
+	struct drm_i915_gem_object *ctx_obj1 = NULL;
+
+	ctx_obj0 = to0->engine[ring->id].state;
+	BUG_ON(!ctx_obj0);
+	BUG_ON(!i915_gem_obj_is_pinned(ctx_obj0));
+
+	if (to1) {
+		ctx_obj1 = to1->engine[ring->id].state;
+		BUG_ON(!ctx_obj1);
+		BUG_ON(!i915_gem_obj_is_pinned(ctx_obj1));
+	}
+
+	execlists_elsp_write(ring, ctx_obj0, ctx_obj1);
+
+	return 0;
+}
+
 static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
@@ -270,12 +378,16 @@ int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
 
 void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
 {
+	struct intel_engine_cs *ring = ringbuf->ring;
+	struct intel_context *ctx = ringbuf->ctx;

drivers/gpu/drm/i915/intel_lrc.c int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf) · line 390

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +4 -2
+
 	intel_logical_ring_advance(ringbuf);
 
-	if (intel_ring_stopped(ringbuf->ring))
+	if (intel_ring_stopped(ring))
 		return;
 
-	/* TODO: how to submit a context to the ELSP is not here yet */
+	/* FIXME: too cheeky, we don't even check if the ELSP is ready */
+	execlists_submit_context(ring, ctx, ringbuf->tail, NULL, 0);

So this is the 2nd user of ringbuf->ctx I've spotted (well gcc did) and imo it shouldn't be here. We should have one ELSP submit for each batch, not one for each ring_advance. Heck even the ring_advance should probably be done just once.

This is one of the reasons why I wanted to have a parallel execlist function hierarchy, so that we could implement such stuff correctly without jumping through hoops (or doing the lazy update trick we do for legacy rings).

Punt on this for now.
-Daniel

Quoted 21 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -0
 }
 
 static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
drivers/gpu/drm/i915/intel_lrc.h +1 -0
index f20c3d2..b59965b 100644
@@ -58,5 +58,6 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
 			       struct list_head *vmas,
 			       struct drm_i915_gem_object *batch_obj,
 			       u64 exec_start, u32 flags);
+u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
 
 #endif /* _INTEL_LRC_H_ */
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#89 lore raw

PATCH 29/43 drm/i915/bdw: Write the tail pointer, LRC style

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

Each logical ring context has the tail pointer in the context object, so update it before submission.

v2: New namespace.

---
 drivers/gpu/drm/i915/intel_lrc.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +19 -0
index 535ef98..5b6f416 100644
@@ -176,6 +176,21 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
 	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 }
 
+static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tail)
+{
+	struct page *page;
+	uint32_t *reg_state;
+
+	page = i915_gem_object_get_page(ctx_obj, 1);
+	reg_state = kmap_atomic(page);
+
+	reg_state[CTX_RING_TAIL+1] = tail;
+
+	kunmap_atomic(reg_state);
+
+	return 0;
+}
+
 static int execlists_submit_context(struct intel_engine_cs *ring,
 				    struct intel_context *to0, u32 tail0,
 				    struct intel_context *to1, u32 tail1)
@@ -187,10 +202,14 @@ static int execlists_submit_context(struct intel_engine_cs *ring,
 	BUG_ON(!ctx_obj0);
 	BUG_ON(!i915_gem_obj_is_pinned(ctx_obj0));
 
+	execlists_ctx_write_tail(ctx_obj0, tail0);
+
 	if (to1) {
 		ctx_obj1 = to1->engine[ring->id].state;
 		BUG_ON(!ctx_obj1);
 		BUG_ON(!i915_gem_obj_is_pinned(ctx_obj1));
+
+		execlists_ctx_write_tail(ctx_obj1, tail1);
 	}
 
 	execlists_elsp_write(ring, ctx_obj0, ctx_obj1);
Signature · 1 line
1.7.9.5
#90 lore raw

Re: [PATCH 29/43] drm/i915/bdw: Write the tail pointer, LRC style

Quoted 6 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Each logical ring context has the tail pointer in the context object, so update it before submission.

v2: New namespace.

I believe we could just leave the context object mapped for its whole lifetime. Something to thing about at a later point.

Signature · 1 line
Damien
Quoted 53 lines
---
 drivers/gpu/drm/i915/intel_lrc.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +19 -0
index 535ef98..5b6f416 100644
@@ -176,6 +176,21 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
 	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 }
 
+static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tail)
+{
+	struct page *page;
+	uint32_t *reg_state;
+
+	page = i915_gem_object_get_page(ctx_obj, 1);
+	reg_state = kmap_atomic(page);
+
+	reg_state[CTX_RING_TAIL+1] = tail;
+
+	kunmap_atomic(reg_state);
+
+	return 0;
+}
+
 static int execlists_submit_context(struct intel_engine_cs *ring,
 				    struct intel_context *to0, u32 tail0,
 				    struct intel_context *to1, u32 tail1)
@@ -187,10 +202,14 @@ static int execlists_submit_context(struct intel_engine_cs *ring,
 	BUG_ON(!ctx_obj0);
 	BUG_ON(!i915_gem_obj_is_pinned(ctx_obj0));
 
+	execlists_ctx_write_tail(ctx_obj0, tail0);
+
 	if (to1) {
 		ctx_obj1 = to1->engine[ring->id].state;
 		BUG_ON(!ctx_obj1);
 		BUG_ON(!i915_gem_obj_is_pinned(ctx_obj1));
+
+		execlists_ctx_write_tail(ctx_obj1, tail1);
 	}
 
 	execlists_elsp_write(ring, ctx_obj0, ctx_obj1);
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#91 lore raw

Re: [PATCH 29/43] drm/i915/bdw: Write the tail pointer, LRC style

In reply to Thomas Daniel
Quoted 40 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

Each logical ring context has the tail pointer in the context object, so update it before submission.

v2: New namespace.

---
 drivers/gpu/drm/i915/intel_lrc.c |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
drivers/gpu/drm/i915/intel_lrc.c +15 -0
index 535ef98..5b6f416 100644
@@ -176,6 +176,21 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
 	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 }
 
+static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tail)
+{
+	struct page *page;
+	uint32_t *reg_state;
+
+	page = i915_gem_object_get_page(ctx_obj, 1);
+	reg_state = kmap_atomic(page);
+
+	reg_state[CTX_RING_TAIL+1] = tail;
+
+	kunmap_atomic(reg_state);
+
+	return 0;
+}
+
 static int execlists_submit_context(struct intel_engine_cs *ring,
 				    struct intel_context *to0, u32 tail0,
 				    struct intel_context *to1, u32 tail1)
@@ -187,10 +202,14 @@ static int execlists_submit_context(struct intel_engine_cs *ring,
 	BUG_ON(!ctx_obj0);

drivers/gpu/drm/i915/intel_lrc.c static int execlists_submit_context(struct intel_engine_cs *ring, · line 212

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +4 -0
 	BUG_ON(!i915_gem_obj_is_pinned(ctx_obj0));
 
+	execlists_ctx_write_tail(ctx_obj0, tail0);
+
 	if (to1) {
 		ctx_obj1 = to1->engine[ring->id].state;
 		BUG_ON(!ctx_obj1);
 		BUG_ON(!i915_gem_obj_is_pinned(ctx_obj1));
+
+		execlists_ctx_write_tail(ctx_obj1, tail1);

Ok, now I'm totally surprised - here's the tail write and elsp submit like excepted. So why do we need the dance in the previous patch?

I'll look at this again tomorrow and will stop merging for today. -Daniel

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +0 -0
 	}
 
 	execlists_elsp_write(ring, ctx_obj0, ctx_obj1);
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#92 lore raw

PATCH 30/43 drm/i915/bdw: Two-stage execlist submit process

In reply to Thomas Daniel

From: Michel Thierry <[email protected]>

Context switch (and execlist submission) should happen only when other contexts are not active, otherwise pre-emption occurs.

To assure this, we place context switch requests in a queue and those request are later consumed when the right context switch interrupt is received (still TODO).

v2: Use a spinlock, do not remove the requests on unqueue (wait for context switch completion).

v3: Several rebases and code changes. Use unique ID.

v4:
- Move the queue/lock init to the late ring initialization.
- Damien's kmalloc review comments: check return, use sizeof(*req), do not cast.

v5:
- Do not reuse drm_i915_gem_request. Instead, create our own.
- New namespace.

---
 drivers/gpu/drm/i915/intel_lrc.c        |   63 ++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_lrc.h        |    8 ++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    2 +
 3 files changed, 71 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +61 -2
index 5b6f416..9e91169 100644
@@ -217,6 +217,63 @@ static int execlists_submit_context(struct intel_engine_cs *ring,
 	return 0;
 }
 
+static void execlists_context_unqueue(struct intel_engine_cs *ring)
+{
+	struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
+	struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL;
+
+	if (list_empty(&ring->execlist_queue))
+		return;
+
+	/* Try to read in pairs */
+	list_for_each_entry_safe(cursor, tmp, &ring->execlist_queue, execlist_link) {
+		if (!req0)
+			req0 = cursor;
+		else if (req0->ctx == cursor->ctx) {
+			/* Same ctx: 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);
+			req0 = cursor;
+		} else {
+			req1 = cursor;
+			break;
+		}
+	}
+
+	BUG_ON(execlists_submit_context(ring, req0->ctx, req0->tail,
+			req1? req1->ctx : NULL, req1? req1->tail : 0));
+}
+
+static int execlists_context_queue(struct intel_engine_cs *ring,
+				   struct intel_context *to,
+				   u32 tail)
+{
+	struct intel_ctx_submit_request *req = NULL;
+	unsigned long flags;
+	bool was_empty;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (req == NULL)
+		return -ENOMEM;
+	req->ctx = to;
+	i915_gem_context_reference(req->ctx);
+	req->ring = ring;
+	req->tail = tail;
+
+	spin_lock_irqsave(&ring->execlist_lock, flags);
+
+	was_empty = list_empty(&ring->execlist_queue);
+	list_add_tail(&req->execlist_link, &ring->execlist_queue);
+	if (was_empty)
+		execlists_context_unqueue(ring);
+
+	spin_unlock_irqrestore(&ring->execlist_lock, flags);
+
+	return 0;
+}
+
 static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
@@ -405,8 +462,7 @@ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
 	if (intel_ring_stopped(ring))
 		return;
 
-	/* FIXME: too cheeky, we don't even check if the ELSP is ready */
-	execlists_submit_context(ring, ctx, ringbuf->tail, NULL, 0);
+	execlists_context_queue(ring, ctx, ringbuf->tail);
 }
 
 static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
@@ -850,6 +906,9 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
 	INIT_LIST_HEAD(&ring->request_list);
 	init_waitqueue_head(&ring->irq_queue);
 
+	INIT_LIST_HEAD(&ring->execlist_queue);
+	spin_lock_init(&ring->execlist_lock);
+
 	ret = intel_lr_context_deferred_create(dctx, ring);
 	if (ret)
 		return ret;
drivers/gpu/drm/i915/intel_lrc.h +8 -0
index b59965b..14492a9 100644
@@ -60,4 +60,12 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
 			       u64 exec_start, u32 flags);
 u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
 
+struct intel_ctx_submit_request {
+	struct intel_context *ctx;
+	struct intel_engine_cs *ring;
+	u32 tail;
+
+	struct list_head execlist_link;
+};
+
 #endif /* _INTEL_LRC_H_ */
drivers/gpu/drm/i915/intel_ringbuffer.h +2 -0
index c885d5c..6358823 100644
@@ -223,6 +223,8 @@ struct  intel_engine_cs {
 	} semaphore;
 
 	/* Execlists */
+	spinlock_t execlist_lock;
+	struct list_head execlist_queue;
 	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
Signature · 1 line
1.7.9.5
#93 lore raw

Re: [PATCH 30/43] drm/i915/bdw: Two-stage execlist submit process

Quoted 58 lines · Thomas Daniel

From: Michel Thierry <[email protected]>

Context switch (and execlist submission) should happen only when other contexts are not active, otherwise pre-emption occurs.

To assure this, we place context switch requests in a queue and those request are later consumed when the right context switch interrupt is received (still TODO).

v2: Use a spinlock, do not remove the requests on unqueue (wait for context switch completion).

v3: Several rebases and code changes. Use unique ID.

v4:
- Move the queue/lock init to the late ring initialization.
- Damien's kmalloc review comments: check return, use sizeof(*req), do not cast.

v5:
- Do not reuse drm_i915_gem_request. Instead, create our own.
- New namespace.

---
 drivers/gpu/drm/i915/intel_lrc.c        |   63 ++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_lrc.h        |    8 ++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    2 +
 3 files changed, 71 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +17 -0
index 5b6f416..9e91169 100644
@@ -217,6 +217,63 @@ static int execlists_submit_context(struct intel_engine_cs *ring,
 	return 0;
 }
 
+static void execlists_context_unqueue(struct intel_engine_cs *ring)
+{
+	struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
+	struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL;
+
+	if (list_empty(&ring->execlist_queue))
+		return;
+
+	/* Try to read in pairs */
+	list_for_each_entry_safe(cursor, tmp, &ring->execlist_queue, execlist_link) {
+		if (!req0)
+			req0 = cursor;
+		else if (req0->ctx == cursor->ctx) {
+			/* Same ctx: 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);

drivers/gpu/drm/i915/intel_lrc.c static int execlists_submit_context(struct intel_engine_cs *ring, · line 246

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +10 -0
+			kfree(req0);
+			req0 = cursor;
+		} else {
+			req1 = cursor;
+			break;
+		}
+	}
+
+	BUG_ON(execlists_submit_context(ring, req0->ctx, req0->tail,
+			req1? req1->ctx : NULL, req1? req1->tail : 0));

You don't get to hard-hang my driver just because you've done a programming mistake. Please remember my commandements ;-)

Also checkpatch ...
-Daniel

Quoted 90 lines
drivers/gpu/drm/i915/intel_lrc.c +34 -2
+}
+
+static int execlists_context_queue(struct intel_engine_cs *ring,
+				   struct intel_context *to,
+				   u32 tail)
+{
+	struct intel_ctx_submit_request *req = NULL;
+	unsigned long flags;
+	bool was_empty;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (req == NULL)
+		return -ENOMEM;
+	req->ctx = to;
+	i915_gem_context_reference(req->ctx);
+	req->ring = ring;
+	req->tail = tail;
+
+	spin_lock_irqsave(&ring->execlist_lock, flags);
+
+	was_empty = list_empty(&ring->execlist_queue);
+	list_add_tail(&req->execlist_link, &ring->execlist_queue);
+	if (was_empty)
+		execlists_context_unqueue(ring);
+
+	spin_unlock_irqrestore(&ring->execlist_lock, flags);
+
+	return 0;
+}
+
 static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
@@ -405,8 +462,7 @@ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
 	if (intel_ring_stopped(ring))
 		return;
 
-	/* FIXME: too cheeky, we don't even check if the ELSP is ready */
-	execlists_submit_context(ring, ctx, ringbuf->tail, NULL, 0);
+	execlists_context_queue(ring, ctx, ringbuf->tail);
 }
 
 static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
@@ -850,6 +906,9 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
 	INIT_LIST_HEAD(&ring->request_list);
 	init_waitqueue_head(&ring->irq_queue);
 
+	INIT_LIST_HEAD(&ring->execlist_queue);
+	spin_lock_init(&ring->execlist_lock);
+
 	ret = intel_lr_context_deferred_create(dctx, ring);
 	if (ret)
 		return ret;
drivers/gpu/drm/i915/intel_lrc.h +8 -0
index b59965b..14492a9 100644
@@ -60,4 +60,12 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
 			       u64 exec_start, u32 flags);
 u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
 
+struct intel_ctx_submit_request {
+	struct intel_context *ctx;
+	struct intel_engine_cs *ring;
+	u32 tail;
+
+	struct list_head execlist_link;
+};
+
 #endif /* _INTEL_LRC_H_ */
drivers/gpu/drm/i915/intel_ringbuffer.h +2 -0
index c885d5c..6358823 100644
@@ -223,6 +223,8 @@ struct  intel_engine_cs {
 	} semaphore;
 
 	/* Execlists */
+	spinlock_t execlist_lock;
+	struct list_head execlist_queue;
 	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#94 lore raw

Re: [PATCH 30/43] drm/i915/bdw: Two-stage execlist submit process

In reply to Thomas Daniel
Quoted 41 lines · Thomas Daniel

From: Michel Thierry <[email protected]>

Context switch (and execlist submission) should happen only when other contexts are not active, otherwise pre-emption occurs.

To assure this, we place context switch requests in a queue and those request are later consumed when the right context switch interrupt is received (still TODO).

v2: Use a spinlock, do not remove the requests on unqueue (wait for context switch completion).

v3: Several rebases and code changes. Use unique ID.

v4:
- Move the queue/lock init to the late ring initialization.
- Damien's kmalloc review comments: check return, use sizeof(*req), do not cast.

v5:
- Do not reuse drm_i915_gem_request. Instead, create our own.
- New namespace.

---
 drivers/gpu/drm/i915/intel_lrc.c        |   63 ++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_lrc.h        |    8 ++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    2 +
 3 files changed, 71 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index 5b6f416..9e91169 100644
@@ -217,6 +217,63 @@ static int execlists_submit_context(struct intel_engine_cs *ring,
 	return 0;
 }
 

drivers/gpu/drm/i915/intel_lrc.c static int execlists_submit_context(struct intel_engine_cs *ring, · line 229

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +10 -0
+static void execlists_context_unqueue(struct intel_engine_cs *ring)
+{
+	struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
+	struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL;
+
+	if (list_empty(&ring->execlist_queue))
+		return;
+
+	/* Try to read in pairs */
+	list_for_each_entry_safe(cursor, tmp, &ring->execlist_queue, execlist_link) {

Ok, because checkpatch I've looked at this. Imo open-coding this would be much easier to read i.e.

	if (!list_empty)
		grab&remove first item;
	if (!list_empty)
		grab&remove 2nd item;

Care to follow up with a patch for that?

Thanks, Daniel

Quoted 107 lines
drivers/gpu/drm/i915/intel_lrc.c +51 -2
+		if (!req0)
+			req0 = cursor;
+		else if (req0->ctx == cursor->ctx) {
+			/* Same ctx: 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);
+			req0 = cursor;
+		} else {
+			req1 = cursor;
+			break;
+		}
+	}
+
+	BUG_ON(execlists_submit_context(ring, req0->ctx, req0->tail,
+			req1? req1->ctx : NULL, req1? req1->tail : 0));
+}
+
+static int execlists_context_queue(struct intel_engine_cs *ring,
+				   struct intel_context *to,
+				   u32 tail)
+{
+	struct intel_ctx_submit_request *req = NULL;
+	unsigned long flags;
+	bool was_empty;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (req == NULL)
+		return -ENOMEM;
+	req->ctx = to;
+	i915_gem_context_reference(req->ctx);
+	req->ring = ring;
+	req->tail = tail;
+
+	spin_lock_irqsave(&ring->execlist_lock, flags);
+
+	was_empty = list_empty(&ring->execlist_queue);
+	list_add_tail(&req->execlist_link, &ring->execlist_queue);
+	if (was_empty)
+		execlists_context_unqueue(ring);
+
+	spin_unlock_irqrestore(&ring->execlist_lock, flags);
+
+	return 0;
+}
+
 static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
 {
 	struct intel_engine_cs *ring = ringbuf->ring;
@@ -405,8 +462,7 @@ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
 	if (intel_ring_stopped(ring))
 		return;
 
-	/* FIXME: too cheeky, we don't even check if the ELSP is ready */
-	execlists_submit_context(ring, ctx, ringbuf->tail, NULL, 0);
+	execlists_context_queue(ring, ctx, ringbuf->tail);
 }
 
 static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
@@ -850,6 +906,9 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
 	INIT_LIST_HEAD(&ring->request_list);
 	init_waitqueue_head(&ring->irq_queue);
 
+	INIT_LIST_HEAD(&ring->execlist_queue);
+	spin_lock_init(&ring->execlist_lock);
+
 	ret = intel_lr_context_deferred_create(dctx, ring);
 	if (ret)
 		return ret;
drivers/gpu/drm/i915/intel_lrc.h +8 -0
index b59965b..14492a9 100644
@@ -60,4 +60,12 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
 			       u64 exec_start, u32 flags);
 u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
 
+struct intel_ctx_submit_request {
+	struct intel_context *ctx;
+	struct intel_engine_cs *ring;
+	u32 tail;
+
+	struct list_head execlist_link;
+};
+
 #endif /* _INTEL_LRC_H_ */
drivers/gpu/drm/i915/intel_ringbuffer.h +2 -0
index c885d5c..6358823 100644
@@ -223,6 +223,8 @@ struct  intel_engine_cs {
 	} semaphore;
 
 	/* Execlists */
+	spinlock_t execlist_lock;
+	struct list_head execlist_queue;
 	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#95 lore raw

Re: [PATCH 30/43] drm/i915/bdw: Two-stage execlist submit process

Quoted 70 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Thursday, August 14, 2014 9:10 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 30/43] drm/i915/bdw: Two-stage execlist submit process

Quoted 21 lines · Thomas Daniel

From: Michel Thierry <[email protected]>

Context switch (and execlist submission) should happen only when other contexts are not active, otherwise pre-emption occurs.

To assure this, we place context switch requests in a queue and those request are later consumed when the right context switch interrupt is received (still TODO).

v2: Use a spinlock, do not remove the requests on unqueue (wait for context switch completion).

v3: Several rebases and code changes. Use unique ID.

v4:
- Move the queue/lock init to the late ring initialization.
- Damien's kmalloc review comments: check return, use sizeof(*req), do not cast.

Quoted 8 lines

v5:
- Do not reuse drm_i915_gem_request. Instead, create our own.
- New namespace.

---
 drivers/gpu/drm/i915/intel_lrc.c        |   63

++++++++++++++++++++++++++++++-

drivers/gpu/drm/i915/intel_lrc.c static int execlists_submit_context(struct

Quoted 10 lines
 drivers/gpu/drm/i915/intel_lrc.h        |    8 ++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    2 +
 3 files changed, 71 insertions(+), 2 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +0 -0
index 5b6f416..9e91169 100644
@@ -217,6 +217,63 @@ static int execlists_submit_context(struct

intel_engine_cs *ring,

drivers/gpu/drm/i915/intel_lrc.c static int execlists_submit_context(struct intel_engine_cs *ring,

Quoted 13 lines
drivers/gpu/drm/i915/intel_lrc.c +10 -0
 	return 0;
 }
 
+static void execlists_context_unqueue(struct intel_engine_cs *ring) {
+	struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
+	struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL;
+
+	if (list_empty(&ring->execlist_queue))
+		return;
+
+	/* Try to read in pairs */
+	list_for_each_entry_safe(cursor, tmp, &ring->execlist_queue,
+execlist_link) {

Ok, because checkpatch I've looked at this. Imo open-coding this would be much easier to read i.e.

Quoted 8 lines
	if (!list_empty)
		grab&remove first item;
	if (!list_empty)
		grab&remove 2nd item;

Care to follow up with a patch for that?

Thanks, Daniel

This needs to be kept as a loop because if there are two consecutive requests for the same context they are squashed. Also the non-squashed requests are not removed here (unfortunately the remove is in the next patch).

Quoted 4 lines

drivers/gpu/drm/i915/intel_lrc.c static int execlists_submit_context(struct intel_engine_cs *ring, · line 232

Quoted 4 lines
drivers/gpu/drm/i915/intel_lrc.c +3 -0
+		if (!req0)
+			req0 = cursor;
+		else if (req0->ctx == cursor->ctx) {

This:

Quoted 114 lines
Quoted 46 lines
drivers/gpu/drm/i915/intel_lrc.c +43 -0
+			/* Same ctx: 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);
+			req0 = cursor;
+		} else {
+			req1 = cursor;
+			break;
+		}
+	}
+
+	BUG_ON(execlists_submit_context(ring, req0->ctx, req0->tail,
+			req1? req1->ctx : NULL, req1? req1->tail : 0)); }
+
+static int execlists_context_queue(struct intel_engine_cs *ring,
+				   struct intel_context *to,
+				   u32 tail)
+{
+	struct intel_ctx_submit_request *req = NULL;
+	unsigned long flags;
+	bool was_empty;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (req == NULL)
+		return -ENOMEM;
+	req->ctx = to;
+	i915_gem_context_reference(req->ctx);
+	req->ring = ring;
+	req->tail = tail;
+
+	spin_lock_irqsave(&ring->execlist_lock, flags);
+
+	was_empty = list_empty(&ring->execlist_queue);
+	list_add_tail(&req->execlist_link, &ring->execlist_queue);
+	if (was_empty)
+		execlists_context_unqueue(ring);
+
+	spin_unlock_irqrestore(&ring->execlist_lock, flags);
+
+	return 0;
+}
+
 static int logical_ring_invalidate_all_caches(struct intel_ringbuffer
 *ringbuf)  {
 	struct intel_engine_cs *ring = ringbuf->ring; @@ -405,8 +462,7 @@
Quoted 1 line

void intel_logical_ring_advance_and_submit(struct intel_ringbuffer

*ringbuf)

drivers/gpu/drm/i915/intel_lrc.c void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +1 -3
 	if (intel_ring_stopped(ring))
 		return;
 
-	/* FIXME: too cheeky, we don't even check if the ELSP is ready */
-	execlists_submit_context(ring, ctx, ringbuf->tail, NULL, 0);
+	execlists_context_queue(ring, ctx, ringbuf->tail);
 }
 
 static int logical_ring_alloc_seqno(struct intel_engine_cs *ring, @@
-850,6 +906,9 @@ static int logical_ring_init(struct drm_device *dev, struct

intel_engine_cs *rin

drivers/gpu/drm/i915/intel_lrc.h int intel_execlists_submission(struct drm_device

Quoted 15 lines
drivers/gpu/drm/i915/intel_lrc.c +3 -0
 	INIT_LIST_HEAD(&ring->request_list);
 	init_waitqueue_head(&ring->irq_queue);
 
+	INIT_LIST_HEAD(&ring->execlist_queue);
+	spin_lock_init(&ring->execlist_lock);
+
 	ret = intel_lr_context_deferred_create(dctx, ring);
 	if (ret)
 		return ret;
drivers/gpu/drm/i915/intel_lrc.h +0 -0
index b59965b..14492a9 100644
@@ -60,4 +60,12 @@ int intel_execlists_submission(struct drm_device

*dev, struct drm_file *file,

Quoted 18 lines
drivers/gpu/drm/i915/intel_lrc.h +8 -0
 			       u64 exec_start, u32 flags);
 u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
 
+struct intel_ctx_submit_request {
+	struct intel_context *ctx;
+	struct intel_engine_cs *ring;
+	u32 tail;
+
+	struct list_head execlist_link;
+};
+
 #endif /* _INTEL_LRC_H_ */
drivers/gpu/drm/i915/intel_ringbuffer.h +0 -0
index c885d5c..6358823 100644

drivers/gpu/drm/i915/intel_ringbuffer.h struct intel_engine_cs { · line 228

Quoted 6 lines
drivers/gpu/drm/i915/intel_ringbuffer.h +2 -0
@@ -223,6 +223,8 @@ struct  intel_engine_cs {
 	} semaphore;
 
 	/* Execlists */
+	spinlock_t execlist_lock;
+	struct list_head execlist_queue;
 	u32             irq_keep_mask; /* bitmask for interrupts that should not

be masked */

Quoted 9 lines
drivers/gpu/drm/i915/intel_ringbuffer.h +0 -1
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
--

1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

#96 lore raw

Re: [PATCH 30/43] drm/i915/bdw: Two-stage execlist submit process

Quoted 29 lines · Thomas
Quoted 29 lines

-----Original Message-----
From: Daniel Vetter [mailto:[email protected]] On Behalf Of Daniel Vetter
Sent: Thursday, August 14, 2014 9:10 PM
To: Daniel, Thomas
Cc: [email protected]
Subject: Re: [Intel-gfx] [PATCH 30/43] drm/i915/bdw: Two-stage execlist submit process

drivers/gpu/drm/i915/intel_lrc.c static int execlists_submit_context(struct intel_engine_cs *ring,

Quoted 11 lines · Thomas Daniel

From: Michel Thierry <[email protected]>

drivers/gpu/drm/i915/intel_lrc.c +10 -0
+static void execlists_context_unqueue(struct intel_engine_cs *ring) {
+	struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
+	struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL;
+
+	if (list_empty(&ring->execlist_queue))
+		return;
+
+	/* Try to read in pairs */
+	list_for_each_entry_safe(cursor, tmp, &ring->execlist_queue,
+execlist_link) {

Ok, because checkpatch I've looked at this. Imo open-coding this would be much easier to read i.e.

	if (!list_empty)
		grab&remove first item;
	if (!list_empty)
		grab&remove 2nd item;
Quoted 7 lines
Quoted 3 lines

Care to follow up with a patch for that?

Thanks, Daniel

This needs to be kept as a loop because if there are two consecutive requests for the same context they are squashed. Also the non-squashed requests are not removed here (unfortunately the remove is in the next patch).

Ok, this sounds like we need to overhaul it anyway for the request tracking then.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#97 lore raw

PATCH 31/43 drm/i915/bdw: Handle context switch events

In reply to Thomas Daniel

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).

We canot call intel_runtime_pm_get() in an interrupt (or with a spinlock grabbed, FWIW), because it might sleep, which is not a nice thing to do. Instead, do the runtime_pm get/put together with the create/destroy request, and handle the forcewake get/put directly.

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.

v3:
- Ack the interrupt inmediately, before trying to handle it (fix for missing interrupts by Bob Beckett <[email protected]>).
- Update the Context Status Buffer Read Pointer, just in case (spotted by Damien Lespiau).

v4: New namespace and multiple rebase changes.

v5: Squash with "drm/i915/bdw: Do not call intel_runtime_pm_get() in an interrupt", as suggested by Daniel.

---
 drivers/gpu/drm/i915/i915_irq.c         |   35 ++++++---
 drivers/gpu/drm/i915/intel_lrc.c        |  129 +++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_lrc.h        |    3 +
 drivers/gpu/drm/i915/intel_ringbuffer.h |    1 +
 4 files changed, 151 insertions(+), 17 deletions(-)
drivers/gpu/drm/i915/i915_irq.c +24 -11
index f77a4ca..e4077d1 100644
@@ -1628,6 +1628,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 				       struct drm_i915_private *dev_priv,
 				       u32 master_ctl)
 {
+	struct intel_engine_cs *ring;
 	u32 rcs, bcs, vcs;
 	uint32_t tmp = 0;
 	irqreturn_t ret = IRQ_NONE;
@@ -1637,14 +1638,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 		if (tmp) {
 			I915_WRITE(GEN8_GT_IIR(0), 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)
+				intel_execlists_handle_ctx_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)
+				intel_execlists_handle_ctx_events(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT0)!\n");
 	}
@@ -1654,16 +1661,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 		if (tmp) {
 			I915_WRITE(GEN8_GT_IIR(1), 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");
+				intel_execlists_handle_ctx_events(ring);
+
 			vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
+			ring = &dev_priv->ring[VCS2];
 			if (vcs & GT_RENDER_USER_INTERRUPT)
-				notify_ring(dev, &dev_priv->ring[VCS2]);
+				notify_ring(dev, ring);
 			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
-				DRM_DEBUG_DRIVER("TODO: Context switch\n");
+				intel_execlists_handle_ctx_events(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT1)!\n");
 	}
@@ -1684,11 +1695,13 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 		if (tmp) {
 			I915_WRITE(GEN8_GT_IIR(3), tmp);
 			ret = IRQ_HANDLED;
+
 			vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
+			ring = &dev_priv->ring[VECS];
 			if (vcs & GT_RENDER_USER_INTERRUPT)
-				notify_ring(dev, &dev_priv->ring[VECS]);
+				notify_ring(dev, ring);
 			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
-				DRM_DEBUG_DRIVER("TODO: Context switch\n");
+				intel_execlists_handle_ctx_events(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT3)!\n");
 	}
drivers/gpu/drm/i915/intel_lrc.c +123 -6

183 lines not on this page · raw message

drivers/gpu/drm/i915/intel_lrc.h +3 -0
index 14492a9..2e8929f 100644
@@ -66,6 +66,9 @@ struct intel_ctx_submit_request {
 	u32 tail;
 
 	struct list_head execlist_link;
+	struct work_struct work;
 };
 
+void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring);
+
 #endif /* _INTEL_LRC_H_ */
drivers/gpu/drm/i915/intel_ringbuffer.h +1 -0
index 6358823..905d1ba 100644
@@ -225,6 +225,7 @@ struct  intel_engine_cs {
 	/* Execlists */
 	spinlock_t execlist_lock;
 	struct list_head execlist_queue;
+	u8 next_context_status_buffer;
 	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
Signature · 1 line
1.7.9.5
#98 lore raw

Re: [PATCH 31/43] drm/i915/bdw: Handle context switch events

Quoted 106 lines · Thomas Daniel

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).

We canot call intel_runtime_pm_get() in an interrupt (or with a spinlock grabbed, FWIW), because it might sleep, which is not a nice thing to do. Instead, do the runtime_pm get/put together with the create/destroy request, and handle the forcewake get/put directly.

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.

v3:
- Ack the interrupt inmediately, before trying to handle it (fix for missing interrupts by Bob Beckett <[email protected]>).
- Update the Context Status Buffer Read Pointer, just in case (spotted by Damien Lespiau).

v4: New namespace and multiple rebase changes.

v5: Squash with "drm/i915/bdw: Do not call intel_runtime_pm_get() in an interrupt", as suggested by Daniel.

---
 drivers/gpu/drm/i915/i915_irq.c         |   35 ++++++---
 drivers/gpu/drm/i915/intel_lrc.c        |  129 +++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_lrc.h        |    3 +
 drivers/gpu/drm/i915/intel_ringbuffer.h |    1 +
 4 files changed, 151 insertions(+), 17 deletions(-)
drivers/gpu/drm/i915/i915_irq.c +21 -9
index f77a4ca..e4077d1 100644
@@ -1628,6 +1628,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 				       struct drm_i915_private *dev_priv,
 				       u32 master_ctl)
 {
+	struct intel_engine_cs *ring;
 	u32 rcs, bcs, vcs;
 	uint32_t tmp = 0;
 	irqreturn_t ret = IRQ_NONE;
@@ -1637,14 +1638,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 		if (tmp) {
 			I915_WRITE(GEN8_GT_IIR(0), 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)
+				intel_execlists_handle_ctx_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)
+				intel_execlists_handle_ctx_events(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT0)!\n");
 	}
@@ -1654,16 +1661,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 		if (tmp) {
 			I915_WRITE(GEN8_GT_IIR(1), 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");
+				intel_execlists_handle_ctx_events(ring);
+
 			vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
+			ring = &dev_priv->ring[VCS2];
 			if (vcs & GT_RENDER_USER_INTERRUPT)
-				notify_ring(dev, &dev_priv->ring[VCS2]);
+				notify_ring(dev, ring);
 			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
-				DRM_DEBUG_DRIVER("TODO: Context switch\n");
+				intel_execlists_handle_ctx_events(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT1)!\n");
 	}
@@ -1684,11 +1695,13 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 		if (tmp) {
 			I915_WRITE(GEN8_GT_IIR(3), tmp);
 			ret = IRQ_HANDLED;
+
 			vcs = tmp >> GEN8_VECS_IRQ_SHIFT;

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, · line 1707

Quoted 10 lines
drivers/gpu/drm/i915/i915_irq.c +3 -2
+			ring = &dev_priv->ring[VECS];
 			if (vcs & GT_RENDER_USER_INTERRUPT)
-				notify_ring(dev, &dev_priv->ring[VECS]);
+				notify_ring(dev, ring);
 			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
-				DRM_DEBUG_DRIVER("TODO: Context switch\n");
+				intel_execlists_handle_ctx_events(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT3)!\n");
 	}

The above stuff is dropping of the left edge a bit. And it's all so super-nicely lead out thanks to the hw engineers, so with a bit of code refactoring we should be able to have one generic ring irq handler and 5 callers for them and rip this all you.

Can you please do that?
-Daniel

Quoted 229 lines
drivers/gpu/drm/i915/intel_lrc.c +123 -6
index 9e91169..65f4f26 100644
@@ -49,6 +49,22 @@
 #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
@@ -147,6 +163,7 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	uint64_t temp = 0;
 	uint32_t desc[4];
+	unsigned long flags;
 
 	/* XXX: You must always write both descriptors in the order below. */
 	if (ctx_obj1)
@@ -160,9 +177,17 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
 	desc[3] = (u32)(temp >> 32);
 	desc[2] = (u32)temp;
 
-	/* Set Force Wakeup bit to prevent GT from entering C6 while
-	 * ELSP writes are in progress */
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+	/* Set Force Wakeup bit to prevent GT from entering C6 while ELSP writes
+	 * are in progress.
+	 *
+	 * The other problem is that we can't just call gen6_gt_force_wake_get()
+	 * because that function calls intel_runtime_pm_get(), which might sleep.
+	 * Instead, we do the runtime_pm_get/put when creating/destroying requests.
+	 */
+	spin_lock_irqsave(&dev_priv->uncore.lock, flags);
+	if (dev_priv->uncore.forcewake_count++ == 0)
+		dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
 
 	I915_WRITE(RING_ELSP(ring), desc[1]);
 	I915_WRITE(RING_ELSP(ring), desc[0]);
@@ -173,7 +198,11 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
 	/* ELSP is a wo register, so use another nearby reg for posting instead */
 	POSTING_READ(RING_EXECLIST_STATUS(ring));
 
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+	/* Release Force Wakeup (see the big comment above). */
+	spin_lock_irqsave(&dev_priv->uncore.lock, flags);
+	if (--dev_priv->uncore.forcewake_count == 0)
+		dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
 }
 
 static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tail)
@@ -221,6 +250,9 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 {
 	struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
 	struct intel_ctx_submit_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;
@@ -233,8 +265,7 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 			/* Same ctx: 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;
@@ -246,6 +277,89 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 			req1? req1->ctx : NULL, req1? req1->tail : 0));
 }
 
+static bool execlists_check_remove_request(struct intel_engine_cs *ring,
+					   u32 request_id)
+{
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	struct intel_ctx_submit_request *head_req;
+
+	assert_spin_locked(&ring->execlist_lock);
+
+	head_req = list_first_entry_or_null(&ring->execlist_queue,
+			struct intel_ctx_submit_request, execlist_link);
+	if (head_req != NULL) {
+		struct drm_i915_gem_object *ctx_obj =
+				head_req->ctx->engine[ring->id].state;
+		if (intel_execlists_ctx_id(ctx_obj) == request_id) {
+			list_del(&head_req->execlist_link);
+			queue_work(dev_priv->wq, &head_req->work);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+void intel_execlists_handle_ctx_events(struct intel_engine_cs *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_COMPLETE) {
+			if (execlists_check_remove_request(ring, status_id))
+				submit_contexts++;
+		}
+	}
+
+	if (submit_contexts != 0)
+		execlists_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;
+
+	I915_WRITE(RING_CONTEXT_STATUS_PTR(ring),
+			((u32)ring->next_context_status_buffer & 0x07) << 8);
+}
+
+static void execlists_free_request_task(struct work_struct *work)
+{
+	struct intel_ctx_submit_request *req =
+			container_of(work, struct intel_ctx_submit_request, work);
+	struct drm_device *dev = req->ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	intel_runtime_pm_put(dev_priv);
+
+	mutex_lock(&dev->struct_mutex);
+	i915_gem_context_unreference(req->ctx);
+	mutex_unlock(&dev->struct_mutex);
+
+	kfree(req);
+}
+
 static int execlists_context_queue(struct intel_engine_cs *ring,
 				   struct intel_context *to,
 				   u32 tail)
@@ -261,6 +375,8 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
 	i915_gem_context_reference(req->ctx);
 	req->ring = ring;
 	req->tail = tail;
+	INIT_WORK(&req->work, execlists_free_request_task);
+	intel_runtime_pm_get(dev_priv);
 
 	spin_lock_irqsave(&ring->execlist_lock, flags);
 
@@ -908,6 +1024,7 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
 
 	INIT_LIST_HEAD(&ring->execlist_queue);
 	spin_lock_init(&ring->execlist_lock);
+	ring->next_context_status_buffer = 0;
 
 	ret = intel_lr_context_deferred_create(dctx, ring);
 	if (ret)
drivers/gpu/drm/i915/intel_lrc.h +3 -0
index 14492a9..2e8929f 100644
@@ -66,6 +66,9 @@ struct intel_ctx_submit_request {
 	u32 tail;
 
 	struct list_head execlist_link;
+	struct work_struct work;
 };
 
+void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring);
+
 #endif /* _INTEL_LRC_H_ */
drivers/gpu/drm/i915/intel_ringbuffer.h +1 -0
index 6358823..905d1ba 100644
@@ -225,6 +225,7 @@ struct  intel_engine_cs {
 	/* Execlists */
 	spinlock_t execlist_lock;
 	struct list_head execlist_queue;
+	u8 next_context_status_buffer;
 	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#99 lore raw

Re: [PATCH 31/43] drm/i915/bdw: Handle context switch events

In reply to Thomas Daniel
Quoted 62 lines · Thomas Daniel

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).

We canot call intel_runtime_pm_get() in an interrupt (or with a spinlock grabbed, FWIW), because it might sleep, which is not a nice thing to do. Instead, do the runtime_pm get/put together with the create/destroy request, and handle the forcewake get/put directly.

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.

v3:
- Ack the interrupt inmediately, before trying to handle it (fix for missing interrupts by Bob Beckett <[email protected]>).
- Update the Context Status Buffer Read Pointer, just in case (spotted by Damien Lespiau).

v4: New namespace and multiple rebase changes.

v5: Squash with "drm/i915/bdw: Do not call intel_runtime_pm_get() in an interrupt", as suggested by Daniel.

---
 drivers/gpu/drm/i915/i915_irq.c         |   35 ++++++---
 drivers/gpu/drm/i915/intel_lrc.c        |  129 +++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_lrc.h        |    3 +
 drivers/gpu/drm/i915/intel_ringbuffer.h |    1 +
 4 files changed, 151 insertions(+), 17 deletions(-)
drivers/gpu/drm/i915/i915_irq.c +6 -2
index f77a4ca..e4077d1 100644
@@ -1628,6 +1628,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 				       struct drm_i915_private *dev_priv,
 				       u32 master_ctl)
 {
+	struct intel_engine_cs *ring;
 	u32 rcs, bcs, vcs;
 	uint32_t tmp = 0;
 	irqreturn_t ret = IRQ_NONE;
@@ -1637,14 +1638,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 		if (tmp) {
 			I915_WRITE(GEN8_GT_IIR(0), 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)
+				intel_execlists_handle_ctx_events(ring);

drivers/gpu/drm/i915/i915_irq.c static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev, · line 1654

Quoted 10 lines
drivers/gpu/drm/i915/i915_irq.c +6 -3
+
+			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)
+				intel_execlists_handle_ctx_events(ring);

Also patch split fail here, the above two cases should have been in an earlier patch that added the basic irq handling.
-Daniel

Quoted 273 lines
drivers/gpu/drm/i915/i915_irq.c +12 -6
 		} else
 			DRM_ERROR("The master control interrupt lied (GT0)!\n");
 	}
@@ -1654,16 +1661,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 		if (tmp) {
 			I915_WRITE(GEN8_GT_IIR(1), 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");
+				intel_execlists_handle_ctx_events(ring);
+
 			vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
+			ring = &dev_priv->ring[VCS2];
 			if (vcs & GT_RENDER_USER_INTERRUPT)
-				notify_ring(dev, &dev_priv->ring[VCS2]);
+				notify_ring(dev, ring);
 			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
-				DRM_DEBUG_DRIVER("TODO: Context switch\n");
+				intel_execlists_handle_ctx_events(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT1)!\n");
 	}
@@ -1684,11 +1695,13 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
 		if (tmp) {
 			I915_WRITE(GEN8_GT_IIR(3), tmp);
 			ret = IRQ_HANDLED;
+
 			vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
+			ring = &dev_priv->ring[VECS];
 			if (vcs & GT_RENDER_USER_INTERRUPT)
-				notify_ring(dev, &dev_priv->ring[VECS]);
+				notify_ring(dev, ring);
 			if (vcs & GEN8_GT_CONTEXT_SWITCH_INTERRUPT)
-				DRM_DEBUG_DRIVER("TODO: Context switch\n");
+				intel_execlists_handle_ctx_events(ring);
 		} else
 			DRM_ERROR("The master control interrupt lied (GT3)!\n");
 	}
drivers/gpu/drm/i915/intel_lrc.c +123 -6
index 9e91169..65f4f26 100644
@@ -49,6 +49,22 @@
 #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
@@ -147,6 +163,7 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	uint64_t temp = 0;
 	uint32_t desc[4];
+	unsigned long flags;
 
 	/* XXX: You must always write both descriptors in the order below. */
 	if (ctx_obj1)
@@ -160,9 +177,17 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
 	desc[3] = (u32)(temp >> 32);
 	desc[2] = (u32)temp;
 
-	/* Set Force Wakeup bit to prevent GT from entering C6 while
-	 * ELSP writes are in progress */
-	gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+	/* Set Force Wakeup bit to prevent GT from entering C6 while ELSP writes
+	 * are in progress.
+	 *
+	 * The other problem is that we can't just call gen6_gt_force_wake_get()
+	 * because that function calls intel_runtime_pm_get(), which might sleep.
+	 * Instead, we do the runtime_pm_get/put when creating/destroying requests.
+	 */
+	spin_lock_irqsave(&dev_priv->uncore.lock, flags);
+	if (dev_priv->uncore.forcewake_count++ == 0)
+		dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
 
 	I915_WRITE(RING_ELSP(ring), desc[1]);
 	I915_WRITE(RING_ELSP(ring), desc[0]);
@@ -173,7 +198,11 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
 	/* ELSP is a wo register, so use another nearby reg for posting instead */
 	POSTING_READ(RING_EXECLIST_STATUS(ring));
 
-	gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+	/* Release Force Wakeup (see the big comment above). */
+	spin_lock_irqsave(&dev_priv->uncore.lock, flags);
+	if (--dev_priv->uncore.forcewake_count == 0)
+		dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
 }
 
 static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tail)
@@ -221,6 +250,9 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 {
 	struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
 	struct intel_ctx_submit_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;
@@ -233,8 +265,7 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 			/* Same ctx: 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;
@@ -246,6 +277,89 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 			req1? req1->ctx : NULL, req1? req1->tail : 0));
 }
 
+static bool execlists_check_remove_request(struct intel_engine_cs *ring,
+					   u32 request_id)
+{
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	struct intel_ctx_submit_request *head_req;
+
+	assert_spin_locked(&ring->execlist_lock);
+
+	head_req = list_first_entry_or_null(&ring->execlist_queue,
+			struct intel_ctx_submit_request, execlist_link);
+	if (head_req != NULL) {
+		struct drm_i915_gem_object *ctx_obj =
+				head_req->ctx->engine[ring->id].state;
+		if (intel_execlists_ctx_id(ctx_obj) == request_id) {
+			list_del(&head_req->execlist_link);
+			queue_work(dev_priv->wq, &head_req->work);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+void intel_execlists_handle_ctx_events(struct intel_engine_cs *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_COMPLETE) {
+			if (execlists_check_remove_request(ring, status_id))
+				submit_contexts++;
+		}
+	}
+
+	if (submit_contexts != 0)
+		execlists_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;
+
+	I915_WRITE(RING_CONTEXT_STATUS_PTR(ring),
+			((u32)ring->next_context_status_buffer & 0x07) << 8);
+}
+
+static void execlists_free_request_task(struct work_struct *work)
+{
+	struct intel_ctx_submit_request *req =
+			container_of(work, struct intel_ctx_submit_request, work);
+	struct drm_device *dev = req->ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	intel_runtime_pm_put(dev_priv);
+
+	mutex_lock(&dev->struct_mutex);
+	i915_gem_context_unreference(req->ctx);
+	mutex_unlock(&dev->struct_mutex);
+
+	kfree(req);
+}
+
 static int execlists_context_queue(struct intel_engine_cs *ring,
 				   struct intel_context *to,
 				   u32 tail)
@@ -261,6 +375,8 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
 	i915_gem_context_reference(req->ctx);
 	req->ring = ring;
 	req->tail = tail;
+	INIT_WORK(&req->work, execlists_free_request_task);
+	intel_runtime_pm_get(dev_priv);
 
 	spin_lock_irqsave(&ring->execlist_lock, flags);
 
@@ -908,6 +1024,7 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
 
 	INIT_LIST_HEAD(&ring->execlist_queue);
 	spin_lock_init(&ring->execlist_lock);
+	ring->next_context_status_buffer = 0;
 
 	ret = intel_lr_context_deferred_create(dctx, ring);
 	if (ret)
drivers/gpu/drm/i915/intel_lrc.h +3 -0
index 14492a9..2e8929f 100644
@@ -66,6 +66,9 @@ struct intel_ctx_submit_request {
 	u32 tail;
 
 	struct list_head execlist_link;
+	struct work_struct work;
 };
 
+void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring);
+
 #endif /* _INTEL_LRC_H_ */
drivers/gpu/drm/i915/intel_ringbuffer.h +1 -0
index 6358823..905d1ba 100644
@@ -225,6 +225,7 @@ struct  intel_engine_cs {
 	/* Execlists */
 	spinlock_t execlist_lock;
 	struct list_head execlist_queue;
+	u8 next_context_status_buffer;
 	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#100 lore raw

Re: [PATCH 31/43] drm/i915/bdw: Handle context switch events

In reply to Thomas Daniel
Quoted 36 lines · Thomas Daniel

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).

We canot call intel_runtime_pm_get() in an interrupt (or with a spinlock grabbed, FWIW), because it might sleep, which is not a nice thing to do. Instead, do the runtime_pm get/put together with the create/destroy request, and handle the forcewake get/put directly.

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.

v3:
- Ack the interrupt inmediately, before trying to handle it (fix for missing interrupts by Bob Beckett <[email protected]>).
- Update the Context Status Buffer Read Pointer, just in case (spotted by Damien Lespiau).

v4: New namespace and multiple rebase changes.

v5: Squash with "drm/i915/bdw: Do not call intel_runtime_pm_get() in an interrupt", as suggested by Daniel.

drivers/gpu/drm/i915/intel_lrc.c +5 -0
+static void execlists_free_request_task(struct work_struct *work)
+{
+	struct intel_ctx_submit_request *req =
+			container_of(work, struct intel_ctx_submit_request, work);
+	struct drm_device *dev = req->ring->dev;

drivers/gpu/drm/i915/intel_lrc.c static void execlists_context_unqueue(struct intel_engine_cs *ring) · line 361

Quoted 10 lines
drivers/gpu/drm/i915/intel_lrc.c +10 -0
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	intel_runtime_pm_put(dev_priv);
+
+	mutex_lock(&dev->struct_mutex);
+	i915_gem_context_unreference(req->ctx);
+	mutex_unlock(&dev->struct_mutex);
+
+	kfree(req);
+}

Latching a work item simply for the unference of the context looks very fishy. The context really can't possible disappear before the last request on it has completed, since the request already holds a reference.

That you have this additional reference here makes it look a bit like the relationship and lifetime rules for the execlist queue item is misshapen.

I'd have expected:
- A given execlist queue item is responsible for a list of requests (one or more)
- Each request already holds onto the context.

The other thing that's strange here is the runtime pm handling. We already keep the device awake as long as it's busy, so I wonder why exactly we need this here in addition.

In any case these kind of cleanup tasks are imo better done in the retire request handler that we already have.

Imo needs some cleanup.
-Daniel

Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#101 lore raw

Re: [PATCH 31/43] drm/i915/bdw: Handle context switch events

In reply to Thomas Daniel
Quoted 24 lines · Thomas Daniel

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).

We canot call intel_runtime_pm_get() in an interrupt (or with a spinlock grabbed, FWIW), because it might sleep, which is not a nice thing to do. Instead, do the runtime_pm get/put together with the create/destroy request, and handle the forcewake get/put directly.

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.

v3:
- Ack the interrupt inmediately, before trying to handle it (fix for missing interrupts by Bob Beckett <[email protected]>).
- Update the Context Status Buffer Read Pointer, just in case (spotted by Damien Lespiau).

Quoted 6 lines

v4: New namespace and multiple rebase changes.

v5: Squash with "drm/i915/bdw: Do not call intel_runtime_pm_get() in an interrupt", as suggested by Daniel.

One more ...

Quoted 1 line

+void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring)

Please rename this to intel_execlist_ctx_events_irq_handler or similar for consistency with all the other irq handler functions in a follow-up patch. That kind of consistency helps a lot when reviewing the locking of irq-save spinlocks.
-Daniel

Quoted 112 lines
drivers/gpu/drm/i915/intel_lrc.c +62 -0
+{
+	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_COMPLETE) {
+			if (execlists_check_remove_request(ring, status_id))
+				submit_contexts++;
+		}
+	}
+
+	if (submit_contexts != 0)
+		execlists_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;
+
+	I915_WRITE(RING_CONTEXT_STATUS_PTR(ring),
+			((u32)ring->next_context_status_buffer & 0x07) << 8);
+}
+
+static void execlists_free_request_task(struct work_struct *work)
+{
+	struct intel_ctx_submit_request *req =
+			container_of(work, struct intel_ctx_submit_request, work);
+	struct drm_device *dev = req->ring->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	intel_runtime_pm_put(dev_priv);
+
+	mutex_lock(&dev->struct_mutex);
+	i915_gem_context_unreference(req->ctx);
+	mutex_unlock(&dev->struct_mutex);
+
+	kfree(req);
+}
+
 static int execlists_context_queue(struct intel_engine_cs *ring,
 				   struct intel_context *to,
 				   u32 tail)
@@ -261,6 +375,8 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
 	i915_gem_context_reference(req->ctx);
 	req->ring = ring;
 	req->tail = tail;
+	INIT_WORK(&req->work, execlists_free_request_task);
+	intel_runtime_pm_get(dev_priv);
 
 	spin_lock_irqsave(&ring->execlist_lock, flags);
 
@@ -908,6 +1024,7 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
 
 	INIT_LIST_HEAD(&ring->execlist_queue);
 	spin_lock_init(&ring->execlist_lock);
+	ring->next_context_status_buffer = 0;
 
 	ret = intel_lr_context_deferred_create(dctx, ring);
 	if (ret)
drivers/gpu/drm/i915/intel_lrc.h +3 -0
index 14492a9..2e8929f 100644
@@ -66,6 +66,9 @@ struct intel_ctx_submit_request {
 	u32 tail;
 
 	struct list_head execlist_link;
+	struct work_struct work;
 };
 
+void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring);
+
 #endif /* _INTEL_LRC_H_ */
drivers/gpu/drm/i915/intel_ringbuffer.h +1 -0
index 6358823..905d1ba 100644
@@ -225,6 +225,7 @@ struct  intel_engine_cs {
 	/* Execlists */
 	spinlock_t execlist_lock;
 	struct list_head execlist_queue;
+	u8 next_context_status_buffer;
 	u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
 	int		(*emit_request)(struct intel_ringbuffer *ringbuf);
 	int		(*emit_flush)(struct intel_ringbuffer *ringbuf,
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#102 lore raw

PATCH 32/43 drm/i915/bdw: Avoid non-lite-restore preemptions

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

In the current Execlists feeding mechanism, full preemption is not supported yet: only lite-restores are allowed (this is: the GPU simply samples a new tail pointer for the context currently in execution).

But we have identified an scenario in which a full preemption occurs:
1) We submit two contexts for execution (A & B).
2) The GPU finishes with the first one (A), switches to the second one
(B) and informs us.
3) We submit B again (hoping to cause a lite restore) together with C, but in the time we spend writing to the ELSP, the GPU finishes B.
4) The GPU start executing B again (since we told it so).
5) We receive a B finished interrupt and, mistakenly, we submit C (again) and D, causing a full preemption of B.

The race is avoided by keeping track of how many times a context has been submitted to the hardware and by better discriminating the received context switch interrupts: in the example, when we have submitted B twice, we won´t submit C and D as soon as we receive the notification that B is completed because we were expecting to get a LITE_RESTORE and we didn´t, so we know a second completion will be received shortly.

Without this explicit checking, somehow, the batch buffer execution order gets messed with. This can be verified with the IGT test I sent together with the series. I don´t know the exact mechanism by which the pre-emption messes with the execution order but, since other people is working on the Scheduler
+ Preemption on Execlists, I didn´t try to fix it. In these series, only Lite Restores are supported (other kind of preemptions WARN).

v2: elsp_submitted belongs in the new intel_ctx_submit_request. Several rebase changes.

v3: Clarify how the race is avoided, as requested by Daniel.

---
 drivers/gpu/drm/i915/intel_lrc.c |   28 ++++++++++++++++++++++++----
 drivers/gpu/drm/i915/intel_lrc.h |    2 ++
 2 files changed, 26 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +24 -4
index 65f4f26..895dbfc 100644
@@ -264,6 +264,7 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 		else if (req0->ctx == cursor->ctx) {
 			/* Same ctx: ignore first request, as second request
 			 * will update tail past first request's workload */
+			cursor->elsp_submitted = req0->elsp_submitted;
 			list_del(&req0->execlist_link);
 			queue_work(dev_priv->wq, &req0->work);
 			req0 = cursor;
@@ -273,8 +274,14 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 		}
 	}
 
+	WARN_ON(req1 && req1->elsp_submitted);
+
 	BUG_ON(execlists_submit_context(ring, req0->ctx, req0->tail,
 			req1? req1->ctx : NULL, req1? req1->tail : 0));
+
+	req0->elsp_submitted++;
+	if (req1)
+		req1->elsp_submitted++;
 }
 
 static bool execlists_check_remove_request(struct intel_engine_cs *ring,
@@ -291,9 +298,13 @@ static bool execlists_check_remove_request(struct intel_engine_cs *ring,
 		struct drm_i915_gem_object *ctx_obj =
 				head_req->ctx->engine[ring->id].state;
 		if (intel_execlists_ctx_id(ctx_obj) == request_id) {
-			list_del(&head_req->execlist_link);
-			queue_work(dev_priv->wq, &head_req->work);
-			return true;
+			WARN(head_req->elsp_submitted == 0,
+					"Never submitted head request\n");
+			if (--head_req->elsp_submitted <= 0) {
+				list_del(&head_req->execlist_link);
+				queue_work(dev_priv->wq, &head_req->work);
+				return true;
+			}
 		}
 	}
 
@@ -326,7 +337,16 @@ void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring)
 		status_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
 				(read_pointer % 6) * 8 + 4);
 
-		if (status & GEN8_CTX_STATUS_COMPLETE) {
+		if (status & GEN8_CTX_STATUS_PREEMPTED) {
+			if (status & GEN8_CTX_STATUS_LITE_RESTORE) {
+				if (execlists_check_remove_request(ring, status_id))
+					WARN(1, "Lite Restored request removed from queue\n");
+			} else
+				WARN(1, "Preemption without Lite Restore\n");
+		}
+
+		 if ((status & GEN8_CTX_STATUS_ACTIVE_IDLE) ||
+		     (status & GEN8_CTX_STATUS_ELEMENT_SWITCH)) {
 			if (execlists_check_remove_request(ring, status_id))
 				submit_contexts++;
 		}
drivers/gpu/drm/i915/intel_lrc.h +2 -0
index 2e8929f..074b44f 100644
@@ -67,6 +67,8 @@ struct intel_ctx_submit_request {
 
 	struct list_head execlist_link;
 	struct work_struct work;
+
+	int elsp_submitted;
 };
 
 void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring);
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
#103 lore raw

Re: [PATCH 32/43] drm/i915/bdw: Avoid non-lite-restore preemptions

Quoted 24 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

In the current Execlists feeding mechanism, full preemption is not supported yet: only lite-restores are allowed (this is: the GPU simply samples a new tail pointer for the context currently in execution).

But we have identified an scenario in which a full preemption occurs:
1) We submit two contexts for execution (A & B).
2) The GPU finishes with the first one (A), switches to the second one
(B) and informs us.
3) We submit B again (hoping to cause a lite restore) together with C, but in the time we spend writing to the ELSP, the GPU finishes B.
4) The GPU start executing B again (since we told it so).
5) We receive a B finished interrupt and, mistakenly, we submit C (again) and D, causing a full preemption of B.

The race is avoided by keeping track of how many times a context has been submitted to the hardware and by better discriminating the received context switch interrupts: in the example, when we have submitted B twice, we won´t submit C and D as soon as we receive the notification that B is completed because we were expecting to get a LITE_RESTORE and we didn´t, so we know a second completion will be received shortly.

Quoted 6 lines

Without this explicit checking, somehow, the batch buffer execution order gets messed with. This can be verified with the IGT test I sent together with the series. I don´t know the exact mechanism by which the pre-emption messes with the execution order but, since other people is working on the Scheduler
+ Preemption on Execlists, I didn´t try to fix it. In these series, only Lite Restores are supported (other kind of preemptions WARN).

Where's this igt patch? The kernel patch here is at least missing the

Testcase: igt/foo

tag. Please supply.
-Daniel

Quoted 94 lines

v2: elsp_submitted belongs in the new intel_ctx_submit_request. Several rebase changes.

v3: Clarify how the race is avoided, as requested by Daniel.

---
 drivers/gpu/drm/i915/intel_lrc.c |   28 ++++++++++++++++++++++++----
 drivers/gpu/drm/i915/intel_lrc.h |    2 ++
 2 files changed, 26 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +24 -4
index 65f4f26..895dbfc 100644
@@ -264,6 +264,7 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 		else if (req0->ctx == cursor->ctx) {
 			/* Same ctx: ignore first request, as second request
 			 * will update tail past first request's workload */
+			cursor->elsp_submitted = req0->elsp_submitted;
 			list_del(&req0->execlist_link);
 			queue_work(dev_priv->wq, &req0->work);
 			req0 = cursor;
@@ -273,8 +274,14 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
 		}
 	}
 
+	WARN_ON(req1 && req1->elsp_submitted);
+
 	BUG_ON(execlists_submit_context(ring, req0->ctx, req0->tail,
 			req1? req1->ctx : NULL, req1? req1->tail : 0));
+
+	req0->elsp_submitted++;
+	if (req1)
+		req1->elsp_submitted++;
 }
 
 static bool execlists_check_remove_request(struct intel_engine_cs *ring,
@@ -291,9 +298,13 @@ static bool execlists_check_remove_request(struct intel_engine_cs *ring,
 		struct drm_i915_gem_object *ctx_obj =
 				head_req->ctx->engine[ring->id].state;
 		if (intel_execlists_ctx_id(ctx_obj) == request_id) {
-			list_del(&head_req->execlist_link);
-			queue_work(dev_priv->wq, &head_req->work);
-			return true;
+			WARN(head_req->elsp_submitted == 0,
+					"Never submitted head request\n");
+			if (--head_req->elsp_submitted <= 0) {
+				list_del(&head_req->execlist_link);
+				queue_work(dev_priv->wq, &head_req->work);
+				return true;
+			}
 		}
 	}
 
@@ -326,7 +337,16 @@ void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring)
 		status_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
 				(read_pointer % 6) * 8 + 4);
 
-		if (status & GEN8_CTX_STATUS_COMPLETE) {
+		if (status & GEN8_CTX_STATUS_PREEMPTED) {
+			if (status & GEN8_CTX_STATUS_LITE_RESTORE) {
+				if (execlists_check_remove_request(ring, status_id))
+					WARN(1, "Lite Restored request removed from queue\n");
+			} else
+				WARN(1, "Preemption without Lite Restore\n");
+		}
+
+		 if ((status & GEN8_CTX_STATUS_ACTIVE_IDLE) ||
+		     (status & GEN8_CTX_STATUS_ELEMENT_SWITCH)) {
 			if (execlists_check_remove_request(ring, status_id))
 				submit_contexts++;
 		}
drivers/gpu/drm/i915/intel_lrc.h +2 -0
index 2e8929f..074b44f 100644
@@ -67,6 +67,8 @@ struct intel_ctx_submit_request {
 
 	struct list_head execlist_link;
 	struct work_struct work;
+
+	int elsp_submitted;
 };
 
 void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring);
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
#104 lore raw

PATCH 33/43 drm/i915/bdw: Help out the ctx switch interrupt handler

In reply to Thomas Daniel

From: Oscar Mateo <[email protected]>

If we receive a storm of requests for the same context (see gem_storedw_loop_*) we might end up iterating over too many elements in interrupt time, looking for contexts to squash together. Instead, share the burden by giving more intelligence to the queue function. At most, the interrupt will iterate over three elements.

---
 drivers/gpu/drm/i915/intel_lrc.c |   26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +22 -4
index 895dbfc..829b15d 100644
@@ -384,9 +384,10 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
 				   struct intel_context *to,
 				   u32 tail)
 {
-	struct intel_ctx_submit_request *req = NULL;
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	struct intel_ctx_submit_request *req = NULL, *cursor;
 	unsigned long flags;
-	bool was_empty;
+	int num_elements = 0;
 
 	req = kzalloc(sizeof(*req), GFP_KERNEL);
 	if (req == NULL)
@@ -400,9 +401,26 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
 
 	spin_lock_irqsave(&ring->execlist_lock, flags);
 
-	was_empty = list_empty(&ring->execlist_queue);
+	list_for_each_entry(cursor, &ring->execlist_queue, execlist_link)
+		if (++num_elements > 2)
+			break;
+
+	if (num_elements > 2) {
+		struct intel_ctx_submit_request *tail_req;
+
+		tail_req = list_last_entry(&ring->execlist_queue,
+					struct intel_ctx_submit_request,
+					execlist_link);
+		if (to == tail_req->ctx) {
+			WARN(tail_req->elsp_submitted != 0,
+					"More than 2 already-submitted reqs queued\n");
+			list_del(&tail_req->execlist_link);
+			queue_work(dev_priv->wq, &tail_req->work);
+		}
+	}
+
 	list_add_tail(&req->execlist_link, &ring->execlist_queue);
-	if (was_empty)
+	if (num_elements == 0)
 		execlists_context_unqueue(ring);
 
 	spin_unlock_irqrestore(&ring->execlist_lock, flags);
Signature · 1 line
1.7.9.5
#105 lore raw

Re: [PATCH 33/43] drm/i915/bdw: Help out the ctx switch interrupt handler

Quoted 9 lines · Thomas Daniel

From: Oscar Mateo <[email protected]>

If we receive a storm of requests for the same context (see gem_storedw_loop_*) we might end up iterating over too many elements in interrupt time, looking for contexts to squash together. Instead, share the burden by giving more intelligence to the queue function. At most, the interrupt will iterate over three elements.

I'll continue merging after this patch tomorrow.
-Daniel

Quoted 57 lines
---
 drivers/gpu/drm/i915/intel_lrc.c |   26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)
drivers/gpu/drm/i915/intel_lrc.c +22 -4
index 895dbfc..829b15d 100644
@@ -384,9 +384,10 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
 				   struct intel_context *to,
 				   u32 tail)
 {
-	struct intel_ctx_submit_request *req = NULL;
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	struct intel_ctx_submit_request *req = NULL, *cursor;
 	unsigned long flags;
-	bool was_empty;
+	int num_elements = 0;
 
 	req = kzalloc(sizeof(*req), GFP_KERNEL);
 	if (req == NULL)
@@ -400,9 +401,26 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
 
 	spin_lock_irqsave(&ring->execlist_lock, flags);
 
-	was_empty = list_empty(&ring->execlist_queue);
+	list_for_each_entry(cursor, &ring->execlist_queue, execlist_link)
+		if (++num_elements > 2)
+			break;
+
+	if (num_elements > 2) {
+		struct intel_ctx_submit_request *tail_req;
+
+		tail_req = list_last_entry(&ring->execlist_queue,
+					struct intel_ctx_submit_request,
+					execlist_link);
+		if (to == tail_req->ctx) {
+			WARN(tail_req->elsp_submitted != 0,
+					"More than 2 already-submitted reqs queued\n");
+			list_del(&tail_req->execlist_link);
+			queue_work(dev_priv->wq, &tail_req->work);
+		}
+	}
+
 	list_add_tail(&req->execlist_link, &ring->execlist_queue);
-	if (was_empty)
+	if (num_elements == 0)
 		execlists_context_unqueue(ring);
 
 	spin_unlock_irqrestore(&ring->execlist_lock, flags);
Signature · 6 lines
1.7.9.5

_______________________________________________
Intel-gfx mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Signature · 3 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch