All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/27] drm/i915/gem: ioctl clean-ups (v5)
@ 2021-05-03 15:57 ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

Overview:
---------

This patch series attempts to clean up some of the IOCTL mess we've created
over the last few years.  The most egregious bit being context mutability.
In summary, this series:

 1. Drops two never-used context params: RINGSIZE and NO_ZEROMAP
 2. Drops the entire CONTEXT_CLONE API
 3. Implements SINGLE_TIMELINE with a syncobj instead of actually sharing
    intel_timeline between engines.
 4. Adds a few sanity restrictions to the balancing/bonding API.
 5. Implements a proto-ctx mechanism so that the engine set and VM can only
    be set early on in the lifetime of a context, before anything ever
    executes on it.  This effectively makes the VM and engine set
    immutable.

This series has been tested with IGT as well as the Iris, ANV, and the
Intel media driver doing an 8K decode (this uses bonding/balancing).  I've
also done quite a bit of git archeology to ensure that nothing in here will
break anything that's already shipped at some point in history.  It's
possible I've missed something, but I've dug quite a bit.


Details and motivation:
-----------------------

In very broad strokes, there's an effort going on right now within Intel to
try and clean up and simplify i915 anywhere we can.  We obviously don't
want to break any shipping userspace but, as can be seen by this series,
there's a lot i915 theoretically supports which userspace doesn't actually
need.  Some of this, like the two context params used here, were simply
oversights where we went through the usual API review process and merged
the i915 bits but the userspace bits never landed for some reason.

Not all are so innocent, however.  For instance, there's an entire context
cloning API which allows one to create a context with certain parameters
"cloned" from some other context.  This entire API has never been used by
any userspace except IGT and there were never patches to any other
userspace to use it.  It never should have landed.  Also, when we added
support for setting explicit engine sets and sharing VMs across contexts,
people decided to do so via SET_CONTEXT_PARAM.  While this allowed them to
re-use existing API, it did so at the cost of making those states mutable
which leads to a plethora of potential race conditions.  There were even
IGT tests merged to cover some of theses:

 - gem_vm_create@async-destroy and gem_vm_create@destroy-race which test
   swapping out the VM on a running context.

 - gem_ctx_persistence@replace* which test whether a client can escape a
   non-persistent context by submitting a hanging batch and then swapping
   out the engine set before the hang is detected.

 - api_intel_bb@bb-with-vm which tests the that intel_bb_assign_vm works
   properly.  This API is never used by any other IGT test.

There is also an entire deferred flush and set state framework in
i915_gem_cotnext.c which exists for safely swapping out the VM while there
is work in-flight on a context.

So, clearly people knew that this API was inherently racy and difficult to
implement but they landed it anyway.  Why?  The best explanation I've been
given is because it makes the API more "unified" or "symmetric" for this
stuff to go through SET_CONTEXT_PARAM.  It's not because any userspace
actually wants to be able to swap out the VM or the set of engines on a
running context.  That would be utterly insane.

This patch series cleans up this particular mess by introducing the concept
of a i915_gem_proto_context data structure which contains context creation
information.  When you initially call GEM_CONTEXT_CREATE, a proto-context
in created instead of an actual context.  Then, the first time something is
done on the context besides SET_CONTEXT_PARAM, an actual context is
created.  This allows us to keep the old drivers which use
SET_CONTEXT_PARAM to set up the engine set (see also media) while ensuring
that, once you have an i915_gem_context, the VM and the engine set are
immutable state.

Eventually, there are more clean-ups I'd like to do on top of this which
should make working with contexts inside i915 simpler and safer:

 1. Move the GEM handle -> vma LUT from i915_gem_context into either
    i915_ppgtt or drm_i915_file_private depending on whether or not the
    hardware has a full PPGTT.

 2. Move the delayed context destruction code into intel_context or a
    per-engine wrapper struct rather than i915_gem_context.

 3. Get rid of the separation between context close and context destroy

 4. Get rid of the RCU on i915_gem_context

However, these should probably be done as a separate patch series as this
one is already starting to get longish, especially if you consider the 89
IGT patches that go along with it.

Test-with: 20210423214853.876911-1-jason@jlekstrand.net

Jason Ekstrand (27):
  drm/i915: Drop I915_CONTEXT_PARAM_RINGSIZE
  drm/i915: Stop storing the ring size in the ring pointer
  drm/i915: Drop I915_CONTEXT_PARAM_NO_ZEROMAP
  drm/i915/gem: Set the watchdog timeout directly in
    intel_context_set_gem (v2)
  drm/i915/gem: Return void from context_apply_all
  drm/i915: Drop the CONTEXT_CLONE API
  drm/i915: Implement SINGLE_TIMELINE with a syncobj (v4)
  drm/i915: Drop getparam support for I915_CONTEXT_PARAM_ENGINES
  drm/i915/gem: Disallow bonding of virtual engines (v3)
  drm/i915/gem: Remove engine auto-magic with FENCE_SUBMIT
  drm/i915/request: Remove the hook from await_execution
  drm/i915/gem: Disallow creating contexts with too many engines
  drm/i915: Stop manually RCU banging in reset_stats_ioctl (v2)
  drm/i915/gem: Add a separate validate_priority helper
  drm/i915: Add gem/i915_gem_context.h to the docs
  drm/i915/gem: Add an intermediate proto_context struct
  drm/i915/gem: Rework error handling in default_engines
  drm/i915/gem: Optionally set SSEU in intel_context_set_gem
  drm/i915/gem: Use the proto-context to handle create parameters
  drm/i915/gem: Return an error ptr from context_lookup
  drm/i915/gt: Drop i915_address_space::file (v2)
  drm/i915/gem: Delay context creation
  drm/i915/gem: Don't allow changing the VM on running contexts
  drm/i915/gem: Don't allow changing the engine set on running contexts
  drm/i915/selftests: Take a VM in kernel_context()
  i915/gem/selftests: Assign the VM at context creation in
    igt_shared_ctx_exec
  drm/i915/gem: Roll all of context creation together

 Documentation/gpu/i915.rst                    |    2 +
 drivers/gpu/drm/i915/Makefile                 |    1 -
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 3015 ++++++++---------
 drivers/gpu/drm/i915/gem/i915_gem_context.h   |    3 +
 .../gpu/drm/i915/gem/i915_gem_context_types.h |  198 +-
 .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |   31 +-
 .../drm/i915/gem/selftests/i915_gem_context.c |  127 +-
 .../gpu/drm/i915/gem/selftests/mock_context.c |   67 +-
 .../gpu/drm/i915/gem/selftests/mock_context.h |    4 +-
 drivers/gpu/drm/i915/gt/intel_context.c       |    3 +-
 drivers/gpu/drm/i915/gt/intel_context.h       |    5 -
 drivers/gpu/drm/i915/gt/intel_context_param.c |   63 -
 drivers/gpu/drm/i915/gt/intel_context_param.h |    6 +-
 drivers/gpu/drm/i915/gt/intel_context_types.h |    1 +
 drivers/gpu/drm/i915/gt/intel_engine_types.h  |    7 -
 .../drm/i915/gt/intel_execlists_submission.c  |  114 -
 .../drm/i915/gt/intel_execlists_submission.h  |    7 -
 drivers/gpu/drm/i915/gt/intel_gtt.h           |   11 -
 drivers/gpu/drm/i915/gt/intel_lrc.c           |    2 +-
 drivers/gpu/drm/i915/gt/selftest_execlists.c  |  251 +-
 drivers/gpu/drm/i915/gt/selftest_hangcheck.c  |    2 +-
 drivers/gpu/drm/i915/gt/selftest_mocs.c       |    2 +-
 drivers/gpu/drm/i915/gt/selftest_timeline.c   |    2 +-
 drivers/gpu/drm/i915/gvt/scheduler.c          |    7 +-
 drivers/gpu/drm/i915/i915_drv.h               |   30 +-
 drivers/gpu/drm/i915/i915_perf.c              |    4 +-
 drivers/gpu/drm/i915/i915_request.c           |   42 +-
 drivers/gpu/drm/i915/i915_request.h           |    4 +-
 .../drm/i915/selftests/i915_mock_selftests.h  |    1 -
 drivers/gpu/drm/i915/selftests/mock_gtt.c     |    1 -
 include/uapi/drm/i915_drm.h                   |   40 +-
 31 files changed, 1655 insertions(+), 2398 deletions(-)
 delete mode 100644 drivers/gpu/drm/i915/gt/intel_context_param.c

-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 00/27] drm/i915/gem: ioctl clean-ups (v5)
@ 2021-05-03 15:57 ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

Overview:
---------

This patch series attempts to clean up some of the IOCTL mess we've created
over the last few years.  The most egregious bit being context mutability.
In summary, this series:

 1. Drops two never-used context params: RINGSIZE and NO_ZEROMAP
 2. Drops the entire CONTEXT_CLONE API
 3. Implements SINGLE_TIMELINE with a syncobj instead of actually sharing
    intel_timeline between engines.
 4. Adds a few sanity restrictions to the balancing/bonding API.
 5. Implements a proto-ctx mechanism so that the engine set and VM can only
    be set early on in the lifetime of a context, before anything ever
    executes on it.  This effectively makes the VM and engine set
    immutable.

This series has been tested with IGT as well as the Iris, ANV, and the
Intel media driver doing an 8K decode (this uses bonding/balancing).  I've
also done quite a bit of git archeology to ensure that nothing in here will
break anything that's already shipped at some point in history.  It's
possible I've missed something, but I've dug quite a bit.


Details and motivation:
-----------------------

In very broad strokes, there's an effort going on right now within Intel to
try and clean up and simplify i915 anywhere we can.  We obviously don't
want to break any shipping userspace but, as can be seen by this series,
there's a lot i915 theoretically supports which userspace doesn't actually
need.  Some of this, like the two context params used here, were simply
oversights where we went through the usual API review process and merged
the i915 bits but the userspace bits never landed for some reason.

Not all are so innocent, however.  For instance, there's an entire context
cloning API which allows one to create a context with certain parameters
"cloned" from some other context.  This entire API has never been used by
any userspace except IGT and there were never patches to any other
userspace to use it.  It never should have landed.  Also, when we added
support for setting explicit engine sets and sharing VMs across contexts,
people decided to do so via SET_CONTEXT_PARAM.  While this allowed them to
re-use existing API, it did so at the cost of making those states mutable
which leads to a plethora of potential race conditions.  There were even
IGT tests merged to cover some of theses:

 - gem_vm_create@async-destroy and gem_vm_create@destroy-race which test
   swapping out the VM on a running context.

 - gem_ctx_persistence@replace* which test whether a client can escape a
   non-persistent context by submitting a hanging batch and then swapping
   out the engine set before the hang is detected.

 - api_intel_bb@bb-with-vm which tests the that intel_bb_assign_vm works
   properly.  This API is never used by any other IGT test.

There is also an entire deferred flush and set state framework in
i915_gem_cotnext.c which exists for safely swapping out the VM while there
is work in-flight on a context.

So, clearly people knew that this API was inherently racy and difficult to
implement but they landed it anyway.  Why?  The best explanation I've been
given is because it makes the API more "unified" or "symmetric" for this
stuff to go through SET_CONTEXT_PARAM.  It's not because any userspace
actually wants to be able to swap out the VM or the set of engines on a
running context.  That would be utterly insane.

This patch series cleans up this particular mess by introducing the concept
of a i915_gem_proto_context data structure which contains context creation
information.  When you initially call GEM_CONTEXT_CREATE, a proto-context
in created instead of an actual context.  Then, the first time something is
done on the context besides SET_CONTEXT_PARAM, an actual context is
created.  This allows us to keep the old drivers which use
SET_CONTEXT_PARAM to set up the engine set (see also media) while ensuring
that, once you have an i915_gem_context, the VM and the engine set are
immutable state.

Eventually, there are more clean-ups I'd like to do on top of this which
should make working with contexts inside i915 simpler and safer:

 1. Move the GEM handle -> vma LUT from i915_gem_context into either
    i915_ppgtt or drm_i915_file_private depending on whether or not the
    hardware has a full PPGTT.

 2. Move the delayed context destruction code into intel_context or a
    per-engine wrapper struct rather than i915_gem_context.

 3. Get rid of the separation between context close and context destroy

 4. Get rid of the RCU on i915_gem_context

However, these should probably be done as a separate patch series as this
one is already starting to get longish, especially if you consider the 89
IGT patches that go along with it.

Test-with: 20210423214853.876911-1-jason@jlekstrand.net

Jason Ekstrand (27):
  drm/i915: Drop I915_CONTEXT_PARAM_RINGSIZE
  drm/i915: Stop storing the ring size in the ring pointer
  drm/i915: Drop I915_CONTEXT_PARAM_NO_ZEROMAP
  drm/i915/gem: Set the watchdog timeout directly in
    intel_context_set_gem (v2)
  drm/i915/gem: Return void from context_apply_all
  drm/i915: Drop the CONTEXT_CLONE API
  drm/i915: Implement SINGLE_TIMELINE with a syncobj (v4)
  drm/i915: Drop getparam support for I915_CONTEXT_PARAM_ENGINES
  drm/i915/gem: Disallow bonding of virtual engines (v3)
  drm/i915/gem: Remove engine auto-magic with FENCE_SUBMIT
  drm/i915/request: Remove the hook from await_execution
  drm/i915/gem: Disallow creating contexts with too many engines
  drm/i915: Stop manually RCU banging in reset_stats_ioctl (v2)
  drm/i915/gem: Add a separate validate_priority helper
  drm/i915: Add gem/i915_gem_context.h to the docs
  drm/i915/gem: Add an intermediate proto_context struct
  drm/i915/gem: Rework error handling in default_engines
  drm/i915/gem: Optionally set SSEU in intel_context_set_gem
  drm/i915/gem: Use the proto-context to handle create parameters
  drm/i915/gem: Return an error ptr from context_lookup
  drm/i915/gt: Drop i915_address_space::file (v2)
  drm/i915/gem: Delay context creation
  drm/i915/gem: Don't allow changing the VM on running contexts
  drm/i915/gem: Don't allow changing the engine set on running contexts
  drm/i915/selftests: Take a VM in kernel_context()
  i915/gem/selftests: Assign the VM at context creation in
    igt_shared_ctx_exec
  drm/i915/gem: Roll all of context creation together

 Documentation/gpu/i915.rst                    |    2 +
 drivers/gpu/drm/i915/Makefile                 |    1 -
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 3015 ++++++++---------
 drivers/gpu/drm/i915/gem/i915_gem_context.h   |    3 +
 .../gpu/drm/i915/gem/i915_gem_context_types.h |  198 +-
 .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |   31 +-
 .../drm/i915/gem/selftests/i915_gem_context.c |  127 +-
 .../gpu/drm/i915/gem/selftests/mock_context.c |   67 +-
 .../gpu/drm/i915/gem/selftests/mock_context.h |    4 +-
 drivers/gpu/drm/i915/gt/intel_context.c       |    3 +-
 drivers/gpu/drm/i915/gt/intel_context.h       |    5 -
 drivers/gpu/drm/i915/gt/intel_context_param.c |   63 -
 drivers/gpu/drm/i915/gt/intel_context_param.h |    6 +-
 drivers/gpu/drm/i915/gt/intel_context_types.h |    1 +
 drivers/gpu/drm/i915/gt/intel_engine_types.h  |    7 -
 .../drm/i915/gt/intel_execlists_submission.c  |  114 -
 .../drm/i915/gt/intel_execlists_submission.h  |    7 -
 drivers/gpu/drm/i915/gt/intel_gtt.h           |   11 -
 drivers/gpu/drm/i915/gt/intel_lrc.c           |    2 +-
 drivers/gpu/drm/i915/gt/selftest_execlists.c  |  251 +-
 drivers/gpu/drm/i915/gt/selftest_hangcheck.c  |    2 +-
 drivers/gpu/drm/i915/gt/selftest_mocs.c       |    2 +-
 drivers/gpu/drm/i915/gt/selftest_timeline.c   |    2 +-
 drivers/gpu/drm/i915/gvt/scheduler.c          |    7 +-
 drivers/gpu/drm/i915/i915_drv.h               |   30 +-
 drivers/gpu/drm/i915/i915_perf.c              |    4 +-
 drivers/gpu/drm/i915/i915_request.c           |   42 +-
 drivers/gpu/drm/i915/i915_request.h           |    4 +-
 .../drm/i915/selftests/i915_mock_selftests.h  |    1 -
 drivers/gpu/drm/i915/selftests/mock_gtt.c     |    1 -
 include/uapi/drm/i915_drm.h                   |   40 +-
 31 files changed, 1655 insertions(+), 2398 deletions(-)
 delete mode 100644 drivers/gpu/drm/i915/gt/intel_context_param.c

-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* [PATCH 01/27] drm/i915: Drop I915_CONTEXT_PARAM_RINGSIZE
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter, Jason Ekstrand

This reverts commit 88be76cdafc7 ("drm/i915: Allow userspace to specify
ringsize on construction").  This API was originally added for OpenCL
but the compute-runtime PR has sat open for a year without action so we
can still pull it out if we want.  I argue we should drop it for three
reasons:

 1. If the compute-runtime PR has sat open for a year, this clearly
    isn't that important.

 2. It's a very leaky API.  Ring size is an implementation detail of the
    current execlist scheduler and really only makes sense there.  It
    can't apply to the older ring-buffer scheduler on pre-execlist
    hardware because that's shared across all contexts and it won't
    apply to the GuC scheduler that's in the pipeline.

 3. Having userspace set a ring size in bytes is a bad solution to the
    problem of having too small a ring.  There is no way that userspace
    has the information to know how to properly set the ring size so
    it's just going to detect the feature and always set it to the
    maximum of 512K.  This is what the compute-runtime PR does.  The
    scheduler in i915, on the other hand, does have the information to
    make an informed choice.  It could detect if the ring size is a
    problem and grow it itself.  Or, if that's too hard, we could just
    increase the default size from 16K to 32K or even 64K instead of
    relying on userspace to do it.

Let's drop this API for now and, if someone decides they really care
about solving this problem, they can do it properly.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/Makefile                 |  1 -
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 85 +------------------
 drivers/gpu/drm/i915/gt/intel_context_param.c | 63 --------------
 drivers/gpu/drm/i915/gt/intel_context_param.h |  3 -
 include/uapi/drm/i915_drm.h                   | 20 +----
 5 files changed, 4 insertions(+), 168 deletions(-)
 delete mode 100644 drivers/gpu/drm/i915/gt/intel_context_param.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index d0d936d9137bc..afa22338fa343 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -88,7 +88,6 @@ gt-y += \
 	gt/gen8_ppgtt.o \
 	gt/intel_breadcrumbs.o \
 	gt/intel_context.o \
-	gt/intel_context_param.o \
 	gt/intel_context_sseu.o \
 	gt/intel_engine_cs.o \
 	gt/intel_engine_heartbeat.o \
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index fd8ee52e17a47..e52b85b8f923d 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1335,63 +1335,6 @@ static int set_ppgtt(struct drm_i915_file_private *file_priv,
 	return err;
 }
 
-static int __apply_ringsize(struct intel_context *ce, void *sz)
-{
-	return intel_context_set_ring_size(ce, (unsigned long)sz);
-}
-
-static int set_ringsize(struct i915_gem_context *ctx,
-			struct drm_i915_gem_context_param *args)
-{
-	if (!HAS_LOGICAL_RING_CONTEXTS(ctx->i915))
-		return -ENODEV;
-
-	if (args->size)
-		return -EINVAL;
-
-	if (!IS_ALIGNED(args->value, I915_GTT_PAGE_SIZE))
-		return -EINVAL;
-
-	if (args->value < I915_GTT_PAGE_SIZE)
-		return -EINVAL;
-
-	if (args->value > 128 * I915_GTT_PAGE_SIZE)
-		return -EINVAL;
-
-	return context_apply_all(ctx,
-				 __apply_ringsize,
-				 __intel_context_ring_size(args->value));
-}
-
-static int __get_ringsize(struct intel_context *ce, void *arg)
-{
-	long sz;
-
-	sz = intel_context_get_ring_size(ce);
-	GEM_BUG_ON(sz > INT_MAX);
-
-	return sz; /* stop on first engine */
-}
-
-static int get_ringsize(struct i915_gem_context *ctx,
-			struct drm_i915_gem_context_param *args)
-{
-	int sz;
-
-	if (!HAS_LOGICAL_RING_CONTEXTS(ctx->i915))
-		return -ENODEV;
-
-	if (args->size)
-		return -EINVAL;
-
-	sz = context_apply_all(ctx, __get_ringsize, NULL);
-	if (sz < 0)
-		return sz;
-
-	args->value = sz;
-	return 0;
-}
-
 int
 i915_gem_user_to_context_sseu(struct intel_gt *gt,
 			      const struct drm_i915_gem_context_param_sseu *user,
@@ -2037,11 +1980,8 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 		ret = set_persistence(ctx, args);
 		break;
 
-	case I915_CONTEXT_PARAM_RINGSIZE:
-		ret = set_ringsize(ctx, args);
-		break;
-
 	case I915_CONTEXT_PARAM_BAN_PERIOD:
+	case I915_CONTEXT_PARAM_RINGSIZE:
 	default:
 		ret = -EINVAL;
 		break;
@@ -2069,18 +2009,6 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
 	return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
 }
 
-static int copy_ring_size(struct intel_context *dst,
-			  struct intel_context *src)
-{
-	long sz;
-
-	sz = intel_context_get_ring_size(src);
-	if (sz < 0)
-		return sz;
-
-	return intel_context_set_ring_size(dst, sz);
-}
-
 static int clone_engines(struct i915_gem_context *dst,
 			 struct i915_gem_context *src)
 {
@@ -2125,12 +2053,6 @@ static int clone_engines(struct i915_gem_context *dst,
 		}
 
 		intel_context_set_gem(clone->engines[n], dst);
-
-		/* Copy across the preferred ringsize */
-		if (copy_ring_size(clone->engines[n], e->engines[n])) {
-			__free_engines(clone, n + 1);
-			goto err_unlock;
-		}
 	}
 	clone->num_engines = n;
 	i915_sw_fence_complete(&e->fence);
@@ -2490,11 +2412,8 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 		args->value = i915_gem_context_is_persistent(ctx);
 		break;
 
-	case I915_CONTEXT_PARAM_RINGSIZE:
-		ret = get_ringsize(ctx, args);
-		break;
-
 	case I915_CONTEXT_PARAM_BAN_PERIOD:
+	case I915_CONTEXT_PARAM_RINGSIZE:
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/drivers/gpu/drm/i915/gt/intel_context_param.c b/drivers/gpu/drm/i915/gt/intel_context_param.c
deleted file mode 100644
index 65dcd090245d6..0000000000000
--- a/drivers/gpu/drm/i915/gt/intel_context_param.c
+++ /dev/null
@@ -1,63 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#include "i915_active.h"
-#include "intel_context.h"
-#include "intel_context_param.h"
-#include "intel_ring.h"
-
-int intel_context_set_ring_size(struct intel_context *ce, long sz)
-{
-	int err;
-
-	if (intel_context_lock_pinned(ce))
-		return -EINTR;
-
-	err = i915_active_wait(&ce->active);
-	if (err < 0)
-		goto unlock;
-
-	if (intel_context_is_pinned(ce)) {
-		err = -EBUSY; /* In active use, come back later! */
-		goto unlock;
-	}
-
-	if (test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
-		struct intel_ring *ring;
-
-		/* Replace the existing ringbuffer */
-		ring = intel_engine_create_ring(ce->engine, sz);
-		if (IS_ERR(ring)) {
-			err = PTR_ERR(ring);
-			goto unlock;
-		}
-
-		intel_ring_put(ce->ring);
-		ce->ring = ring;
-
-		/* Context image will be updated on next pin */
-	} else {
-		ce->ring = __intel_context_ring_size(sz);
-	}
-
-unlock:
-	intel_context_unlock_pinned(ce);
-	return err;
-}
-
-long intel_context_get_ring_size(struct intel_context *ce)
-{
-	long sz = (unsigned long)READ_ONCE(ce->ring);
-
-	if (test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
-		if (intel_context_lock_pinned(ce))
-			return -EINTR;
-
-		sz = ce->ring->size;
-		intel_context_unlock_pinned(ce);
-	}
-
-	return sz;
-}
diff --git a/drivers/gpu/drm/i915/gt/intel_context_param.h b/drivers/gpu/drm/i915/gt/intel_context_param.h
index 3ecacc675f414..dffedd983693d 100644
--- a/drivers/gpu/drm/i915/gt/intel_context_param.h
+++ b/drivers/gpu/drm/i915/gt/intel_context_param.h
@@ -10,9 +10,6 @@
 
 #include "intel_context.h"
 
-int intel_context_set_ring_size(struct intel_context *ce, long sz);
-long intel_context_get_ring_size(struct intel_context *ce);
-
 static inline int
 intel_context_set_watchdog_us(struct intel_context *ce, u64 timeout_us)
 {
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 6a34243a7646a..6eefbc6dec01f 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1721,24 +1721,8 @@ struct drm_i915_gem_context_param {
  */
 #define I915_CONTEXT_PARAM_PERSISTENCE	0xb
 
-/*
- * I915_CONTEXT_PARAM_RINGSIZE:
- *
- * Sets the size of the CS ringbuffer to use for logical ring contexts. This
- * applies a limit of how many batches can be queued to HW before the caller
- * is blocked due to lack of space for more commands.
- *
- * Only reliably possible to be set prior to first use, i.e. during
- * construction. At any later point, the current execution must be flushed as
- * the ring can only be changed while the context is idle. Note, the ringsize
- * can be specified as a constructor property, see
- * I915_CONTEXT_CREATE_EXT_SETPARAM, but can also be set later if required.
- *
- * Only applies to the current set of engine and lost when those engines
- * are replaced by a new mapping (see I915_CONTEXT_PARAM_ENGINES).
- *
- * Must be between 4 - 512 KiB, in intervals of page size [4 KiB].
- * Default is 16 KiB.
+/* This API has been removed.  On the off chance someone somewhere has
+ * attempted to use it, never re-use this context param number.
  */
 #define I915_CONTEXT_PARAM_RINGSIZE	0xc
 /* Must be kept compact -- no holes and well documented */
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 01/27] drm/i915: Drop I915_CONTEXT_PARAM_RINGSIZE
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter

This reverts commit 88be76cdafc7 ("drm/i915: Allow userspace to specify
ringsize on construction").  This API was originally added for OpenCL
but the compute-runtime PR has sat open for a year without action so we
can still pull it out if we want.  I argue we should drop it for three
reasons:

 1. If the compute-runtime PR has sat open for a year, this clearly
    isn't that important.

 2. It's a very leaky API.  Ring size is an implementation detail of the
    current execlist scheduler and really only makes sense there.  It
    can't apply to the older ring-buffer scheduler on pre-execlist
    hardware because that's shared across all contexts and it won't
    apply to the GuC scheduler that's in the pipeline.

 3. Having userspace set a ring size in bytes is a bad solution to the
    problem of having too small a ring.  There is no way that userspace
    has the information to know how to properly set the ring size so
    it's just going to detect the feature and always set it to the
    maximum of 512K.  This is what the compute-runtime PR does.  The
    scheduler in i915, on the other hand, does have the information to
    make an informed choice.  It could detect if the ring size is a
    problem and grow it itself.  Or, if that's too hard, we could just
    increase the default size from 16K to 32K or even 64K instead of
    relying on userspace to do it.

Let's drop this API for now and, if someone decides they really care
about solving this problem, they can do it properly.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/Makefile                 |  1 -
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 85 +------------------
 drivers/gpu/drm/i915/gt/intel_context_param.c | 63 --------------
 drivers/gpu/drm/i915/gt/intel_context_param.h |  3 -
 include/uapi/drm/i915_drm.h                   | 20 +----
 5 files changed, 4 insertions(+), 168 deletions(-)
 delete mode 100644 drivers/gpu/drm/i915/gt/intel_context_param.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index d0d936d9137bc..afa22338fa343 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -88,7 +88,6 @@ gt-y += \
 	gt/gen8_ppgtt.o \
 	gt/intel_breadcrumbs.o \
 	gt/intel_context.o \
-	gt/intel_context_param.o \
 	gt/intel_context_sseu.o \
 	gt/intel_engine_cs.o \
 	gt/intel_engine_heartbeat.o \
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index fd8ee52e17a47..e52b85b8f923d 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1335,63 +1335,6 @@ static int set_ppgtt(struct drm_i915_file_private *file_priv,
 	return err;
 }
 
-static int __apply_ringsize(struct intel_context *ce, void *sz)
-{
-	return intel_context_set_ring_size(ce, (unsigned long)sz);
-}
-
-static int set_ringsize(struct i915_gem_context *ctx,
-			struct drm_i915_gem_context_param *args)
-{
-	if (!HAS_LOGICAL_RING_CONTEXTS(ctx->i915))
-		return -ENODEV;
-
-	if (args->size)
-		return -EINVAL;
-
-	if (!IS_ALIGNED(args->value, I915_GTT_PAGE_SIZE))
-		return -EINVAL;
-
-	if (args->value < I915_GTT_PAGE_SIZE)
-		return -EINVAL;
-
-	if (args->value > 128 * I915_GTT_PAGE_SIZE)
-		return -EINVAL;
-
-	return context_apply_all(ctx,
-				 __apply_ringsize,
-				 __intel_context_ring_size(args->value));
-}
-
-static int __get_ringsize(struct intel_context *ce, void *arg)
-{
-	long sz;
-
-	sz = intel_context_get_ring_size(ce);
-	GEM_BUG_ON(sz > INT_MAX);
-
-	return sz; /* stop on first engine */
-}
-
-static int get_ringsize(struct i915_gem_context *ctx,
-			struct drm_i915_gem_context_param *args)
-{
-	int sz;
-
-	if (!HAS_LOGICAL_RING_CONTEXTS(ctx->i915))
-		return -ENODEV;
-
-	if (args->size)
-		return -EINVAL;
-
-	sz = context_apply_all(ctx, __get_ringsize, NULL);
-	if (sz < 0)
-		return sz;
-
-	args->value = sz;
-	return 0;
-}
-
 int
 i915_gem_user_to_context_sseu(struct intel_gt *gt,
 			      const struct drm_i915_gem_context_param_sseu *user,
@@ -2037,11 +1980,8 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 		ret = set_persistence(ctx, args);
 		break;
 
-	case I915_CONTEXT_PARAM_RINGSIZE:
-		ret = set_ringsize(ctx, args);
-		break;
-
 	case I915_CONTEXT_PARAM_BAN_PERIOD:
+	case I915_CONTEXT_PARAM_RINGSIZE:
 	default:
 		ret = -EINVAL;
 		break;
@@ -2069,18 +2009,6 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
 	return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
 }
 
-static int copy_ring_size(struct intel_context *dst,
-			  struct intel_context *src)
-{
-	long sz;
-
-	sz = intel_context_get_ring_size(src);
-	if (sz < 0)
-		return sz;
-
-	return intel_context_set_ring_size(dst, sz);
-}
-
 static int clone_engines(struct i915_gem_context *dst,
 			 struct i915_gem_context *src)
 {
@@ -2125,12 +2053,6 @@ static int clone_engines(struct i915_gem_context *dst,
 		}
 
 		intel_context_set_gem(clone->engines[n], dst);
-
-		/* Copy across the preferred ringsize */
-		if (copy_ring_size(clone->engines[n], e->engines[n])) {
-			__free_engines(clone, n + 1);
-			goto err_unlock;
-		}
 	}
 	clone->num_engines = n;
 	i915_sw_fence_complete(&e->fence);
@@ -2490,11 +2412,8 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 		args->value = i915_gem_context_is_persistent(ctx);
 		break;
 
-	case I915_CONTEXT_PARAM_RINGSIZE:
-		ret = get_ringsize(ctx, args);
-		break;
-
 	case I915_CONTEXT_PARAM_BAN_PERIOD:
+	case I915_CONTEXT_PARAM_RINGSIZE:
 	default:
 		ret = -EINVAL;
 		break;
diff --git a/drivers/gpu/drm/i915/gt/intel_context_param.c b/drivers/gpu/drm/i915/gt/intel_context_param.c
deleted file mode 100644
index 65dcd090245d6..0000000000000
--- a/drivers/gpu/drm/i915/gt/intel_context_param.c
+++ /dev/null
@@ -1,63 +0,0 @@
-// SPDX-License-Identifier: MIT
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#include "i915_active.h"
-#include "intel_context.h"
-#include "intel_context_param.h"
-#include "intel_ring.h"
-
-int intel_context_set_ring_size(struct intel_context *ce, long sz)
-{
-	int err;
-
-	if (intel_context_lock_pinned(ce))
-		return -EINTR;
-
-	err = i915_active_wait(&ce->active);
-	if (err < 0)
-		goto unlock;
-
-	if (intel_context_is_pinned(ce)) {
-		err = -EBUSY; /* In active use, come back later! */
-		goto unlock;
-	}
-
-	if (test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
-		struct intel_ring *ring;
-
-		/* Replace the existing ringbuffer */
-		ring = intel_engine_create_ring(ce->engine, sz);
-		if (IS_ERR(ring)) {
-			err = PTR_ERR(ring);
-			goto unlock;
-		}
-
-		intel_ring_put(ce->ring);
-		ce->ring = ring;
-
-		/* Context image will be updated on next pin */
-	} else {
-		ce->ring = __intel_context_ring_size(sz);
-	}
-
-unlock:
-	intel_context_unlock_pinned(ce);
-	return err;
-}
-
-long intel_context_get_ring_size(struct intel_context *ce)
-{
-	long sz = (unsigned long)READ_ONCE(ce->ring);
-
-	if (test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
-		if (intel_context_lock_pinned(ce))
-			return -EINTR;
-
-		sz = ce->ring->size;
-		intel_context_unlock_pinned(ce);
-	}
-
-	return sz;
-}
diff --git a/drivers/gpu/drm/i915/gt/intel_context_param.h b/drivers/gpu/drm/i915/gt/intel_context_param.h
index 3ecacc675f414..dffedd983693d 100644
--- a/drivers/gpu/drm/i915/gt/intel_context_param.h
+++ b/drivers/gpu/drm/i915/gt/intel_context_param.h
@@ -10,9 +10,6 @@
 
 #include "intel_context.h"
 
-int intel_context_set_ring_size(struct intel_context *ce, long sz);
-long intel_context_get_ring_size(struct intel_context *ce);
-
 static inline int
 intel_context_set_watchdog_us(struct intel_context *ce, u64 timeout_us)
 {
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 6a34243a7646a..6eefbc6dec01f 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1721,24 +1721,8 @@ struct drm_i915_gem_context_param {
  */
 #define I915_CONTEXT_PARAM_PERSISTENCE	0xb
 
-/*
- * I915_CONTEXT_PARAM_RINGSIZE:
- *
- * Sets the size of the CS ringbuffer to use for logical ring contexts. This
- * applies a limit of how many batches can be queued to HW before the caller
- * is blocked due to lack of space for more commands.
- *
- * Only reliably possible to be set prior to first use, i.e. during
- * construction. At any later point, the current execution must be flushed as
- * the ring can only be changed while the context is idle. Note, the ringsize
- * can be specified as a constructor property, see
- * I915_CONTEXT_CREATE_EXT_SETPARAM, but can also be set later if required.
- *
- * Only applies to the current set of engine and lost when those engines
- * are replaced by a new mapping (see I915_CONTEXT_PARAM_ENGINES).
- *
- * Must be between 4 - 512 KiB, in intervals of page size [4 KiB].
- * Default is 16 KiB.
+/* This API has been removed.  On the off chance someone somewhere has
+ * attempted to use it, never re-use this context param number.
  */
 #define I915_CONTEXT_PARAM_RINGSIZE	0xc
 /* Must be kept compact -- no holes and well documented */
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 02/27] drm/i915: Stop storing the ring size in the ring pointer
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

Previously, we were storing the ring size in the ring pointer before it
was actually allocated.  We would then guard setting the ring size on
checking for CONTEXT_ALLOC_BIT.  This is error-prone at best and really
only saves us a few bytes on something that already burns at least 4K.
Instead, this patch adds a new ring_size field and makes everything use
that.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 3 +--
 drivers/gpu/drm/i915/gt/intel_context.c       | 3 ++-
 drivers/gpu/drm/i915/gt/intel_context.h       | 5 -----
 drivers/gpu/drm/i915/gt/intel_context_types.h | 1 +
 drivers/gpu/drm/i915/gt/intel_lrc.c           | 2 +-
 drivers/gpu/drm/i915/gt/selftest_execlists.c  | 2 +-
 drivers/gpu/drm/i915/gt/selftest_mocs.c       | 2 +-
 drivers/gpu/drm/i915/gt/selftest_timeline.c   | 2 +-
 drivers/gpu/drm/i915/gvt/scheduler.c          | 7 ++-----
 9 files changed, 10 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index e52b85b8f923d..2ba4c7e4011b4 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -211,8 +211,7 @@ static void intel_context_set_gem(struct intel_context *ce,
 	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
 	RCU_INIT_POINTER(ce->gem_context, ctx);
 
-	if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags))
-		ce->ring = __intel_context_ring_size(SZ_16K);
+	ce->ring_size = SZ_16K;
 
 	if (rcu_access_pointer(ctx->vm)) {
 		struct i915_address_space *vm;
diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c
index 17cf2640b082b..342fa7daa08b5 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.c
+++ b/drivers/gpu/drm/i915/gt/intel_context.c
@@ -372,7 +372,8 @@ intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine)
 	ce->engine = engine;
 	ce->ops = engine->cops;
 	ce->sseu = engine->sseu;
-	ce->ring = __intel_context_ring_size(SZ_4K);
+	ce->ring = NULL;
+	ce->ring_size = SZ_4K;
 
 	ewma_runtime_init(&ce->runtime.avg);
 
diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h
index f83a73a2b39fc..b10cbe8fee992 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.h
+++ b/drivers/gpu/drm/i915/gt/intel_context.h
@@ -175,11 +175,6 @@ int intel_context_prepare_remote_request(struct intel_context *ce,
 
 struct i915_request *intel_context_create_request(struct intel_context *ce);
 
-static inline struct intel_ring *__intel_context_ring_size(u64 sz)
-{
-	return u64_to_ptr(struct intel_ring, sz);
-}
-
 static inline bool intel_context_is_barrier(const struct intel_context *ce)
 {
 	return test_bit(CONTEXT_BARRIER_BIT, &ce->flags);
diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
index ed8c447a7346b..90026c1771055 100644
--- a/drivers/gpu/drm/i915/gt/intel_context_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
@@ -82,6 +82,7 @@ struct intel_context {
 	spinlock_t signal_lock; /* protects signals, the list of requests */
 
 	struct i915_vma *state;
+	u32 ring_size;
 	struct intel_ring *ring;
 	struct intel_timeline *timeline;
 
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index e86897cde9846..63193c80fb117 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -845,7 +845,7 @@ int lrc_alloc(struct intel_context *ce, struct intel_engine_cs *engine)
 	if (IS_ERR(vma))
 		return PTR_ERR(vma);
 
-	ring = intel_engine_create_ring(engine, (unsigned long)ce->ring);
+	ring = intel_engine_create_ring(engine, ce->ring_size);
 	if (IS_ERR(ring)) {
 		err = PTR_ERR(ring);
 		goto err_vma;
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index 1081cd36a2bd3..01d9896dd4844 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -2793,7 +2793,7 @@ static int __live_preempt_ring(struct intel_engine_cs *engine,
 			goto err_ce;
 		}
 
-		tmp->ring = __intel_context_ring_size(ring_sz);
+		tmp->ring_size = ring_sz;
 
 		err = intel_context_pin(tmp);
 		if (err) {
diff --git a/drivers/gpu/drm/i915/gt/selftest_mocs.c b/drivers/gpu/drm/i915/gt/selftest_mocs.c
index e55a887d11e2b..f343fa5fd986f 100644
--- a/drivers/gpu/drm/i915/gt/selftest_mocs.c
+++ b/drivers/gpu/drm/i915/gt/selftest_mocs.c
@@ -28,7 +28,7 @@ static struct intel_context *mocs_context_create(struct intel_engine_cs *engine)
 		return ce;
 
 	/* We build large requests to read the registers from the ring */
-	ce->ring = __intel_context_ring_size(SZ_16K);
+	ce->ring_size = SZ_16K;
 
 	return ce;
 }
diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c
index 9adbd9d147bea..7eedecfb86e59 100644
--- a/drivers/gpu/drm/i915/gt/selftest_timeline.c
+++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c
@@ -874,7 +874,7 @@ static int create_watcher(struct hwsp_watcher *w,
 	if (IS_ERR(ce))
 		return PTR_ERR(ce);
 
-	ce->ring = __intel_context_ring_size(ringsz);
+	ce->ring_size = ringsz;
 	w->rq = intel_context_create_request(ce);
 	intel_context_put(ce);
 	if (IS_ERR(w->rq))
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index fc735692f21fb..99bc9fed6fbb6 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -1409,11 +1409,8 @@ int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
 		intel_context_set_single_submission(ce);
 
 		/* Max ring buffer size */
-		if (!intel_uc_wants_guc_submission(&engine->gt->uc)) {
-			const unsigned int ring_size = 512 * SZ_4K;
-
-			ce->ring = __intel_context_ring_size(ring_size);
-		}
+		if (!intel_uc_wants_guc_submission(&engine->gt->uc))
+			ce->ring_size = 512 * SZ_4K;
 
 		s->shadow[i] = ce;
 	}
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 02/27] drm/i915: Stop storing the ring size in the ring pointer
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

Previously, we were storing the ring size in the ring pointer before it
was actually allocated.  We would then guard setting the ring size on
checking for CONTEXT_ALLOC_BIT.  This is error-prone at best and really
only saves us a few bytes on something that already burns at least 4K.
Instead, this patch adds a new ring_size field and makes everything use
that.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 3 +--
 drivers/gpu/drm/i915/gt/intel_context.c       | 3 ++-
 drivers/gpu/drm/i915/gt/intel_context.h       | 5 -----
 drivers/gpu/drm/i915/gt/intel_context_types.h | 1 +
 drivers/gpu/drm/i915/gt/intel_lrc.c           | 2 +-
 drivers/gpu/drm/i915/gt/selftest_execlists.c  | 2 +-
 drivers/gpu/drm/i915/gt/selftest_mocs.c       | 2 +-
 drivers/gpu/drm/i915/gt/selftest_timeline.c   | 2 +-
 drivers/gpu/drm/i915/gvt/scheduler.c          | 7 ++-----
 9 files changed, 10 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index e52b85b8f923d..2ba4c7e4011b4 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -211,8 +211,7 @@ static void intel_context_set_gem(struct intel_context *ce,
 	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
 	RCU_INIT_POINTER(ce->gem_context, ctx);
 
-	if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags))
-		ce->ring = __intel_context_ring_size(SZ_16K);
+	ce->ring_size = SZ_16K;
 
 	if (rcu_access_pointer(ctx->vm)) {
 		struct i915_address_space *vm;
diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c
index 17cf2640b082b..342fa7daa08b5 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.c
+++ b/drivers/gpu/drm/i915/gt/intel_context.c
@@ -372,7 +372,8 @@ intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine)
 	ce->engine = engine;
 	ce->ops = engine->cops;
 	ce->sseu = engine->sseu;
-	ce->ring = __intel_context_ring_size(SZ_4K);
+	ce->ring = NULL;
+	ce->ring_size = SZ_4K;
 
 	ewma_runtime_init(&ce->runtime.avg);
 
diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h
index f83a73a2b39fc..b10cbe8fee992 100644
--- a/drivers/gpu/drm/i915/gt/intel_context.h
+++ b/drivers/gpu/drm/i915/gt/intel_context.h
@@ -175,11 +175,6 @@ int intel_context_prepare_remote_request(struct intel_context *ce,
 
 struct i915_request *intel_context_create_request(struct intel_context *ce);
 
-static inline struct intel_ring *__intel_context_ring_size(u64 sz)
-{
-	return u64_to_ptr(struct intel_ring, sz);
-}
-
 static inline bool intel_context_is_barrier(const struct intel_context *ce)
 {
 	return test_bit(CONTEXT_BARRIER_BIT, &ce->flags);
diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
index ed8c447a7346b..90026c1771055 100644
--- a/drivers/gpu/drm/i915/gt/intel_context_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
@@ -82,6 +82,7 @@ struct intel_context {
 	spinlock_t signal_lock; /* protects signals, the list of requests */
 
 	struct i915_vma *state;
+	u32 ring_size;
 	struct intel_ring *ring;
 	struct intel_timeline *timeline;
 
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index e86897cde9846..63193c80fb117 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -845,7 +845,7 @@ int lrc_alloc(struct intel_context *ce, struct intel_engine_cs *engine)
 	if (IS_ERR(vma))
 		return PTR_ERR(vma);
 
-	ring = intel_engine_create_ring(engine, (unsigned long)ce->ring);
+	ring = intel_engine_create_ring(engine, ce->ring_size);
 	if (IS_ERR(ring)) {
 		err = PTR_ERR(ring);
 		goto err_vma;
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index 1081cd36a2bd3..01d9896dd4844 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -2793,7 +2793,7 @@ static int __live_preempt_ring(struct intel_engine_cs *engine,
 			goto err_ce;
 		}
 
-		tmp->ring = __intel_context_ring_size(ring_sz);
+		tmp->ring_size = ring_sz;
 
 		err = intel_context_pin(tmp);
 		if (err) {
diff --git a/drivers/gpu/drm/i915/gt/selftest_mocs.c b/drivers/gpu/drm/i915/gt/selftest_mocs.c
index e55a887d11e2b..f343fa5fd986f 100644
--- a/drivers/gpu/drm/i915/gt/selftest_mocs.c
+++ b/drivers/gpu/drm/i915/gt/selftest_mocs.c
@@ -28,7 +28,7 @@ static struct intel_context *mocs_context_create(struct intel_engine_cs *engine)
 		return ce;
 
 	/* We build large requests to read the registers from the ring */
-	ce->ring = __intel_context_ring_size(SZ_16K);
+	ce->ring_size = SZ_16K;
 
 	return ce;
 }
diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c
index 9adbd9d147bea..7eedecfb86e59 100644
--- a/drivers/gpu/drm/i915/gt/selftest_timeline.c
+++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c
@@ -874,7 +874,7 @@ static int create_watcher(struct hwsp_watcher *w,
 	if (IS_ERR(ce))
 		return PTR_ERR(ce);
 
-	ce->ring = __intel_context_ring_size(ringsz);
+	ce->ring_size = ringsz;
 	w->rq = intel_context_create_request(ce);
 	intel_context_put(ce);
 	if (IS_ERR(w->rq))
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index fc735692f21fb..99bc9fed6fbb6 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -1409,11 +1409,8 @@ int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
 		intel_context_set_single_submission(ce);
 
 		/* Max ring buffer size */
-		if (!intel_uc_wants_guc_submission(&engine->gt->uc)) {
-			const unsigned int ring_size = 512 * SZ_4K;
-
-			ce->ring = __intel_context_ring_size(ring_size);
-		}
+		if (!intel_uc_wants_guc_submission(&engine->gt->uc))
+			ce->ring_size = 512 * SZ_4K;
 
 		s->shadow[i] = ce;
 	}
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 03/27] drm/i915: Drop I915_CONTEXT_PARAM_NO_ZEROMAP
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

The idea behind this param is to support OpenCL drivers with relocations
because OpenCL reserves 0x0 for NULL and, if we placed memory there, it
would confuse CL kernels.  It was originally sent out as part of a patch
series including libdrm [1] and Beignet [2] support.  However, the
libdrm and Beignet patches never landed in their respective upstream
projects so this API has never been used.  It's never been used in Mesa
or any other driver, either.

Dropping this API allows us to delete a small bit of code.

[1]: https://lists.freedesktop.org/archives/intel-gfx/2015-May/067030.html
[2]: https://lists.freedesktop.org/archives/intel-gfx/2015-May/067031.html

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c      | 16 ++--------------
 .../gpu/drm/i915/gem/i915_gem_context_types.h    |  1 -
 drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c   |  8 --------
 include/uapi/drm/i915_drm.h                      |  4 ++++
 4 files changed, 6 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 2ba4c7e4011b4..44841db04301b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1921,15 +1921,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 	int ret = 0;
 
 	switch (args->param) {
-	case I915_CONTEXT_PARAM_NO_ZEROMAP:
-		if (args->size)
-			ret = -EINVAL;
-		else if (args->value)
-			set_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
-		else
-			clear_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
-		break;
-
 	case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
 		if (args->size)
 			ret = -EINVAL;
@@ -1979,6 +1970,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 		ret = set_persistence(ctx, args);
 		break;
 
+	case I915_CONTEXT_PARAM_NO_ZEROMAP:
 	case I915_CONTEXT_PARAM_BAN_PERIOD:
 	case I915_CONTEXT_PARAM_RINGSIZE:
 	default:
@@ -2359,11 +2351,6 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 		return -ENOENT;
 
 	switch (args->param) {
-	case I915_CONTEXT_PARAM_NO_ZEROMAP:
-		args->size = 0;
-		args->value = test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
-		break;
-
 	case I915_CONTEXT_PARAM_GTT_SIZE:
 		args->size = 0;
 		rcu_read_lock();
@@ -2411,6 +2398,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 		args->value = i915_gem_context_is_persistent(ctx);
 		break;
 
+	case I915_CONTEXT_PARAM_NO_ZEROMAP:
 	case I915_CONTEXT_PARAM_BAN_PERIOD:
 	case I915_CONTEXT_PARAM_RINGSIZE:
 	default:
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 340473aa70de0..5ae71ec936f7c 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -129,7 +129,6 @@ struct i915_gem_context {
 	 * @user_flags: small set of booleans controlled by the user
 	 */
 	unsigned long user_flags;
-#define UCONTEXT_NO_ZEROMAP		0
 #define UCONTEXT_NO_ERROR_CAPTURE	1
 #define UCONTEXT_BANNABLE		2
 #define UCONTEXT_RECOVERABLE		3
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index 297143511f99b..b812f313422a9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -290,7 +290,6 @@ struct i915_execbuffer {
 	struct intel_context *reloc_context;
 
 	u64 invalid_flags; /** Set of execobj.flags that are invalid */
-	u32 context_flags; /** Set of execobj.flags to insert from the ctx */
 
 	u64 batch_len; /** Length of batch within object */
 	u32 batch_start_offset; /** Location within object of batch */
@@ -541,9 +540,6 @@ eb_validate_vma(struct i915_execbuffer *eb,
 			entry->flags |= EXEC_OBJECT_NEEDS_GTT | __EXEC_OBJECT_NEEDS_MAP;
 	}
 
-	if (!(entry->flags & EXEC_OBJECT_PINNED))
-		entry->flags |= eb->context_flags;
-
 	return 0;
 }
 
@@ -750,10 +746,6 @@ static int eb_select_context(struct i915_execbuffer *eb)
 	if (rcu_access_pointer(ctx->vm))
 		eb->invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
 
-	eb->context_flags = 0;
-	if (test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags))
-		eb->context_flags |= __EXEC_OBJECT_NEEDS_BIAS;
-
 	return 0;
 }
 
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 6eefbc6dec01f..a0aaa8298f28d 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1637,6 +1637,10 @@ struct drm_i915_gem_context_param {
 	__u32 size;
 	__u64 param;
 #define I915_CONTEXT_PARAM_BAN_PERIOD	0x1
+/* I915_CONTEXT_PARAM_NO_ZEROMAP has been removed.  On the off chance
+ * someone somewhere has attempted to use it, never re-use this context
+ * param number.
+ */
 #define I915_CONTEXT_PARAM_NO_ZEROMAP	0x2
 #define I915_CONTEXT_PARAM_GTT_SIZE	0x3
 #define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE	0x4
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 03/27] drm/i915: Drop I915_CONTEXT_PARAM_NO_ZEROMAP
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

The idea behind this param is to support OpenCL drivers with relocations
because OpenCL reserves 0x0 for NULL and, if we placed memory there, it
would confuse CL kernels.  It was originally sent out as part of a patch
series including libdrm [1] and Beignet [2] support.  However, the
libdrm and Beignet patches never landed in their respective upstream
projects so this API has never been used.  It's never been used in Mesa
or any other driver, either.

Dropping this API allows us to delete a small bit of code.

[1]: https://lists.freedesktop.org/archives/intel-gfx/2015-May/067030.html
[2]: https://lists.freedesktop.org/archives/intel-gfx/2015-May/067031.html

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c      | 16 ++--------------
 .../gpu/drm/i915/gem/i915_gem_context_types.h    |  1 -
 drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c   |  8 --------
 include/uapi/drm/i915_drm.h                      |  4 ++++
 4 files changed, 6 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 2ba4c7e4011b4..44841db04301b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1921,15 +1921,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 	int ret = 0;
 
 	switch (args->param) {
-	case I915_CONTEXT_PARAM_NO_ZEROMAP:
-		if (args->size)
-			ret = -EINVAL;
-		else if (args->value)
-			set_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
-		else
-			clear_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
-		break;
-
 	case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
 		if (args->size)
 			ret = -EINVAL;
@@ -1979,6 +1970,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 		ret = set_persistence(ctx, args);
 		break;
 
+	case I915_CONTEXT_PARAM_NO_ZEROMAP:
 	case I915_CONTEXT_PARAM_BAN_PERIOD:
 	case I915_CONTEXT_PARAM_RINGSIZE:
 	default:
@@ -2359,11 +2351,6 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 		return -ENOENT;
 
 	switch (args->param) {
-	case I915_CONTEXT_PARAM_NO_ZEROMAP:
-		args->size = 0;
-		args->value = test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
-		break;
-
 	case I915_CONTEXT_PARAM_GTT_SIZE:
 		args->size = 0;
 		rcu_read_lock();
@@ -2411,6 +2398,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 		args->value = i915_gem_context_is_persistent(ctx);
 		break;
 
+	case I915_CONTEXT_PARAM_NO_ZEROMAP:
 	case I915_CONTEXT_PARAM_BAN_PERIOD:
 	case I915_CONTEXT_PARAM_RINGSIZE:
 	default:
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 340473aa70de0..5ae71ec936f7c 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -129,7 +129,6 @@ struct i915_gem_context {
 	 * @user_flags: small set of booleans controlled by the user
 	 */
 	unsigned long user_flags;
-#define UCONTEXT_NO_ZEROMAP		0
 #define UCONTEXT_NO_ERROR_CAPTURE	1
 #define UCONTEXT_BANNABLE		2
 #define UCONTEXT_RECOVERABLE		3
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index 297143511f99b..b812f313422a9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -290,7 +290,6 @@ struct i915_execbuffer {
 	struct intel_context *reloc_context;
 
 	u64 invalid_flags; /** Set of execobj.flags that are invalid */
-	u32 context_flags; /** Set of execobj.flags to insert from the ctx */
 
 	u64 batch_len; /** Length of batch within object */
 	u32 batch_start_offset; /** Location within object of batch */
@@ -541,9 +540,6 @@ eb_validate_vma(struct i915_execbuffer *eb,
 			entry->flags |= EXEC_OBJECT_NEEDS_GTT | __EXEC_OBJECT_NEEDS_MAP;
 	}
 
-	if (!(entry->flags & EXEC_OBJECT_PINNED))
-		entry->flags |= eb->context_flags;
-
 	return 0;
 }
 
@@ -750,10 +746,6 @@ static int eb_select_context(struct i915_execbuffer *eb)
 	if (rcu_access_pointer(ctx->vm))
 		eb->invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
 
-	eb->context_flags = 0;
-	if (test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags))
-		eb->context_flags |= __EXEC_OBJECT_NEEDS_BIAS;
-
 	return 0;
 }
 
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 6eefbc6dec01f..a0aaa8298f28d 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1637,6 +1637,10 @@ struct drm_i915_gem_context_param {
 	__u32 size;
 	__u64 param;
 #define I915_CONTEXT_PARAM_BAN_PERIOD	0x1
+/* I915_CONTEXT_PARAM_NO_ZEROMAP has been removed.  On the off chance
+ * someone somewhere has attempted to use it, never re-use this context
+ * param number.
+ */
 #define I915_CONTEXT_PARAM_NO_ZEROMAP	0x2
 #define I915_CONTEXT_PARAM_GTT_SIZE	0x3
 #define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE	0x4
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 04/27] drm/i915/gem: Set the watchdog timeout directly in intel_context_set_gem (v2)
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter, Jason Ekstrand

Instead of handling it like a context param, unconditionally set it when
intel_contexts are created.  For years we've had the idea of a watchdog
uAPI floating about. The aim was for media, so that they could set very
tight deadlines for their transcodes jobs, so that if you have a corrupt
bitstream (especially for decoding) you don't hang your desktop too
hard.  But it's been stuck in limbo since forever, and this simplifies
things a bit in preparation for the proto-context work.  If we decide to
actually make said uAPI a reality, we can do it through the proto-
context easily enough.

This does mean that we move from reading the request_timeout_ms param
once per engine when engines are created instead of once at context
creation.  If someone changes request_timeout_ms between creating a
context and setting engines, it will mean that they get the new timeout.
If someone races setting request_timeout_ms and context creation, they
can theoretically end up with different timeouts.  However, since both
of these are fairly harmless and require changing kernel params, we
don't care.

v2 (Tvrtko Ursulin):
 - Add a comment about races with request_timeout_ms

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 44 +++----------------
 .../gpu/drm/i915/gem/i915_gem_context_types.h |  4 --
 drivers/gpu/drm/i915/gt/intel_context_param.h |  3 +-
 3 files changed, 7 insertions(+), 44 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 44841db04301b..2207e8ea6f065 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -232,7 +232,12 @@ static void intel_context_set_gem(struct intel_context *ce,
 	    intel_engine_has_timeslices(ce->engine))
 		__set_bit(CONTEXT_USE_SEMAPHORES, &ce->flags);
 
-	intel_context_set_watchdog_us(ce, ctx->watchdog.timeout_us);
+	if (IS_ACTIVE(CONFIG_DRM_I915_REQUEST_TIMEOUT) &&
+	    ctx->i915->params.request_timeout_ms) {
+		unsigned int timeout_ms = ctx->i915->params.request_timeout_ms;
+
+		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
+	}
 }
 
 static void __free_engines(struct i915_gem_engines *e, unsigned int count)
@@ -791,41 +796,6 @@ static void __assign_timeline(struct i915_gem_context *ctx,
 	context_apply_all(ctx, __apply_timeline, timeline);
 }
 
-static int __apply_watchdog(struct intel_context *ce, void *timeout_us)
-{
-	return intel_context_set_watchdog_us(ce, (uintptr_t)timeout_us);
-}
-
-static int
-__set_watchdog(struct i915_gem_context *ctx, unsigned long timeout_us)
-{
-	int ret;
-
-	ret = context_apply_all(ctx, __apply_watchdog,
-				(void *)(uintptr_t)timeout_us);
-	if (!ret)
-		ctx->watchdog.timeout_us = timeout_us;
-
-	return ret;
-}
-
-static void __set_default_fence_expiry(struct i915_gem_context *ctx)
-{
-	struct drm_i915_private *i915 = ctx->i915;
-	int ret;
-
-	if (!IS_ACTIVE(CONFIG_DRM_I915_REQUEST_TIMEOUT) ||
-	    !i915->params.request_timeout_ms)
-		return;
-
-	/* Default expiry for user fences. */
-	ret = __set_watchdog(ctx, i915->params.request_timeout_ms * 1000);
-	if (ret)
-		drm_notice(&i915->drm,
-			   "Failed to configure default fence expiry! (%d)",
-			   ret);
-}
-
 static struct i915_gem_context *
 i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
 {
@@ -870,8 +840,6 @@ i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
 		intel_timeline_put(timeline);
 	}
 
-	__set_default_fence_expiry(ctx);
-
 	trace_i915_context_create(ctx);
 
 	return ctx;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 5ae71ec936f7c..676592e27e7d2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -153,10 +153,6 @@ struct i915_gem_context {
 	 */
 	atomic_t active_count;
 
-	struct {
-		u64 timeout_us;
-	} watchdog;
-
 	/**
 	 * @hang_timestamp: The last time(s) this context caused a GPU hang
 	 */
diff --git a/drivers/gpu/drm/i915/gt/intel_context_param.h b/drivers/gpu/drm/i915/gt/intel_context_param.h
index dffedd983693d..0c69cb42d075c 100644
--- a/drivers/gpu/drm/i915/gt/intel_context_param.h
+++ b/drivers/gpu/drm/i915/gt/intel_context_param.h
@@ -10,11 +10,10 @@
 
 #include "intel_context.h"
 
-static inline int
+static inline void
 intel_context_set_watchdog_us(struct intel_context *ce, u64 timeout_us)
 {
 	ce->watchdog.timeout_us = timeout_us;
-	return 0;
 }
 
 #endif /* INTEL_CONTEXT_PARAM_H */
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 04/27] drm/i915/gem: Set the watchdog timeout directly in intel_context_set_gem (v2)
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter

Instead of handling it like a context param, unconditionally set it when
intel_contexts are created.  For years we've had the idea of a watchdog
uAPI floating about. The aim was for media, so that they could set very
tight deadlines for their transcodes jobs, so that if you have a corrupt
bitstream (especially for decoding) you don't hang your desktop too
hard.  But it's been stuck in limbo since forever, and this simplifies
things a bit in preparation for the proto-context work.  If we decide to
actually make said uAPI a reality, we can do it through the proto-
context easily enough.

This does mean that we move from reading the request_timeout_ms param
once per engine when engines are created instead of once at context
creation.  If someone changes request_timeout_ms between creating a
context and setting engines, it will mean that they get the new timeout.
If someone races setting request_timeout_ms and context creation, they
can theoretically end up with different timeouts.  However, since both
of these are fairly harmless and require changing kernel params, we
don't care.

v2 (Tvrtko Ursulin):
 - Add a comment about races with request_timeout_ms

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 44 +++----------------
 .../gpu/drm/i915/gem/i915_gem_context_types.h |  4 --
 drivers/gpu/drm/i915/gt/intel_context_param.h |  3 +-
 3 files changed, 7 insertions(+), 44 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 44841db04301b..2207e8ea6f065 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -232,7 +232,12 @@ static void intel_context_set_gem(struct intel_context *ce,
 	    intel_engine_has_timeslices(ce->engine))
 		__set_bit(CONTEXT_USE_SEMAPHORES, &ce->flags);
 
-	intel_context_set_watchdog_us(ce, ctx->watchdog.timeout_us);
+	if (IS_ACTIVE(CONFIG_DRM_I915_REQUEST_TIMEOUT) &&
+	    ctx->i915->params.request_timeout_ms) {
+		unsigned int timeout_ms = ctx->i915->params.request_timeout_ms;
+
+		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
+	}
 }
 
 static void __free_engines(struct i915_gem_engines *e, unsigned int count)
@@ -791,41 +796,6 @@ static void __assign_timeline(struct i915_gem_context *ctx,
 	context_apply_all(ctx, __apply_timeline, timeline);
 }
 
-static int __apply_watchdog(struct intel_context *ce, void *timeout_us)
-{
-	return intel_context_set_watchdog_us(ce, (uintptr_t)timeout_us);
-}
-
-static int
-__set_watchdog(struct i915_gem_context *ctx, unsigned long timeout_us)
-{
-	int ret;
-
-	ret = context_apply_all(ctx, __apply_watchdog,
-				(void *)(uintptr_t)timeout_us);
-	if (!ret)
-		ctx->watchdog.timeout_us = timeout_us;
-
-	return ret;
-}
-
-static void __set_default_fence_expiry(struct i915_gem_context *ctx)
-{
-	struct drm_i915_private *i915 = ctx->i915;
-	int ret;
-
-	if (!IS_ACTIVE(CONFIG_DRM_I915_REQUEST_TIMEOUT) ||
-	    !i915->params.request_timeout_ms)
-		return;
-
-	/* Default expiry for user fences. */
-	ret = __set_watchdog(ctx, i915->params.request_timeout_ms * 1000);
-	if (ret)
-		drm_notice(&i915->drm,
-			   "Failed to configure default fence expiry! (%d)",
-			   ret);
-}
-
 static struct i915_gem_context *
 i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
 {
@@ -870,8 +840,6 @@ i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
 		intel_timeline_put(timeline);
 	}
 
-	__set_default_fence_expiry(ctx);
-
 	trace_i915_context_create(ctx);
 
 	return ctx;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 5ae71ec936f7c..676592e27e7d2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -153,10 +153,6 @@ struct i915_gem_context {
 	 */
 	atomic_t active_count;
 
-	struct {
-		u64 timeout_us;
-	} watchdog;
-
 	/**
 	 * @hang_timestamp: The last time(s) this context caused a GPU hang
 	 */
diff --git a/drivers/gpu/drm/i915/gt/intel_context_param.h b/drivers/gpu/drm/i915/gt/intel_context_param.h
index dffedd983693d..0c69cb42d075c 100644
--- a/drivers/gpu/drm/i915/gt/intel_context_param.h
+++ b/drivers/gpu/drm/i915/gt/intel_context_param.h
@@ -10,11 +10,10 @@
 
 #include "intel_context.h"
 
-static inline int
+static inline void
 intel_context_set_watchdog_us(struct intel_context *ce, u64 timeout_us)
 {
 	ce->watchdog.timeout_us = timeout_us;
-	return 0;
 }
 
 #endif /* INTEL_CONTEXT_PARAM_H */
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 05/27] drm/i915/gem: Return void from context_apply_all
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter, Jason Ekstrand

None of the callbacks we use with it return an error code anymore; they
all return 0 unconditionally.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 26 +++++++--------------
 1 file changed, 8 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 2207e8ea6f065..d6f342e605254 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -718,32 +718,25 @@ __context_engines_await(const struct i915_gem_context *ctx,
 	return engines;
 }
 
-static int
+static void
 context_apply_all(struct i915_gem_context *ctx,
-		  int (*fn)(struct intel_context *ce, void *data),
+		  void (*fn)(struct intel_context *ce, void *data),
 		  void *data)
 {
 	struct i915_gem_engines_iter it;
 	struct i915_gem_engines *e;
 	struct intel_context *ce;
-	int err = 0;
 
 	e = __context_engines_await(ctx, NULL);
-	for_each_gem_engine(ce, e, it) {
-		err = fn(ce, data);
-		if (err)
-			break;
-	}
+	for_each_gem_engine(ce, e, it)
+		fn(ce, data);
 	i915_sw_fence_complete(&e->fence);
-
-	return err;
 }
 
-static int __apply_ppgtt(struct intel_context *ce, void *vm)
+static void __apply_ppgtt(struct intel_context *ce, void *vm)
 {
 	i915_vm_put(ce->vm);
 	ce->vm = i915_vm_get(vm);
-	return 0;
 }
 
 static struct i915_address_space *
@@ -783,10 +776,9 @@ static void __set_timeline(struct intel_timeline **dst,
 		intel_timeline_put(old);
 }
 
-static int __apply_timeline(struct intel_context *ce, void *timeline)
+static void __apply_timeline(struct intel_context *ce, void *timeline)
 {
 	__set_timeline(&ce->timeline, timeline);
-	return 0;
 }
 
 static void __assign_timeline(struct i915_gem_context *ctx,
@@ -1842,19 +1834,17 @@ set_persistence(struct i915_gem_context *ctx,
 	return __context_set_persistence(ctx, args->value);
 }
 
-static int __apply_priority(struct intel_context *ce, void *arg)
+static void __apply_priority(struct intel_context *ce, void *arg)
 {
 	struct i915_gem_context *ctx = arg;
 
 	if (!intel_engine_has_timeslices(ce->engine))
-		return 0;
+		return;
 
 	if (ctx->sched.priority >= I915_PRIORITY_NORMAL)
 		intel_context_set_use_semaphores(ce);
 	else
 		intel_context_clear_use_semaphores(ce);
-
-	return 0;
 }
 
 static int set_priority(struct i915_gem_context *ctx,
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 05/27] drm/i915/gem: Return void from context_apply_all
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter

None of the callbacks we use with it return an error code anymore; they
all return 0 unconditionally.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 26 +++++++--------------
 1 file changed, 8 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 2207e8ea6f065..d6f342e605254 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -718,32 +718,25 @@ __context_engines_await(const struct i915_gem_context *ctx,
 	return engines;
 }
 
-static int
+static void
 context_apply_all(struct i915_gem_context *ctx,
-		  int (*fn)(struct intel_context *ce, void *data),
+		  void (*fn)(struct intel_context *ce, void *data),
 		  void *data)
 {
 	struct i915_gem_engines_iter it;
 	struct i915_gem_engines *e;
 	struct intel_context *ce;
-	int err = 0;
 
 	e = __context_engines_await(ctx, NULL);
-	for_each_gem_engine(ce, e, it) {
-		err = fn(ce, data);
-		if (err)
-			break;
-	}
+	for_each_gem_engine(ce, e, it)
+		fn(ce, data);
 	i915_sw_fence_complete(&e->fence);
-
-	return err;
 }
 
-static int __apply_ppgtt(struct intel_context *ce, void *vm)
+static void __apply_ppgtt(struct intel_context *ce, void *vm)
 {
 	i915_vm_put(ce->vm);
 	ce->vm = i915_vm_get(vm);
-	return 0;
 }
 
 static struct i915_address_space *
@@ -783,10 +776,9 @@ static void __set_timeline(struct intel_timeline **dst,
 		intel_timeline_put(old);
 }
 
-static int __apply_timeline(struct intel_context *ce, void *timeline)
+static void __apply_timeline(struct intel_context *ce, void *timeline)
 {
 	__set_timeline(&ce->timeline, timeline);
-	return 0;
 }
 
 static void __assign_timeline(struct i915_gem_context *ctx,
@@ -1842,19 +1834,17 @@ set_persistence(struct i915_gem_context *ctx,
 	return __context_set_persistence(ctx, args->value);
 }
 
-static int __apply_priority(struct intel_context *ce, void *arg)
+static void __apply_priority(struct intel_context *ce, void *arg)
 {
 	struct i915_gem_context *ctx = arg;
 
 	if (!intel_engine_has_timeslices(ce->engine))
-		return 0;
+		return;
 
 	if (ctx->sched.priority >= I915_PRIORITY_NORMAL)
 		intel_context_set_use_semaphores(ce);
 	else
 		intel_context_clear_use_semaphores(ce);
-
-	return 0;
 }
 
 static int set_priority(struct i915_gem_context *ctx,
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 06/27] drm/i915: Drop the CONTEXT_CLONE API
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand, Tvrtko Ursulin

This API allows one context to grab bits out of another context upon
creation.  It can be used as a short-cut for setparam(getparam()) for
things like I915_CONTEXT_PARAM_VM.  However, it's never been used by any
real userspace.  It's used by a few IGT tests and that's it.  Since it
doesn't add any real value (most of the stuff you can CLONE you can copy
in other ways), drop it.

There is one thing that this API allows you to clone which you cannot
clone via getparam/setparam: timelines.  However, timelines are an
implementation detail of i915 and not really something that needs to be
exposed to userspace.  Also, sharing timelines between contexts isn't
obviously useful and supporting it has the potential to complicate i915
internally.  It also doesn't add any functionality that the client can't
get in other ways.  If a client really wants a shared timeline, they can
use a syncobj and set it as an in and out fence on every submit.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 199 +-----------------
 .../drm/i915/gt/intel_execlists_submission.c  |  28 ---
 .../drm/i915/gt/intel_execlists_submission.h  |   3 -
 include/uapi/drm/i915_drm.h                   |  16 +-
 4 files changed, 6 insertions(+), 240 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index d6f342e605254..308a63f778faf 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1958,207 +1958,14 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
 	return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
 }
 
-static int clone_engines(struct i915_gem_context *dst,
-			 struct i915_gem_context *src)
+static int invalid_ext(struct i915_user_extension __user *ext, void *data)
 {
-	struct i915_gem_engines *clone, *e;
-	bool user_engines;
-	unsigned long n;
-
-	e = __context_engines_await(src, &user_engines);
-	if (!e)
-		return -ENOENT;
-
-	clone = alloc_engines(e->num_engines);
-	if (!clone)
-		goto err_unlock;
-
-	for (n = 0; n < e->num_engines; n++) {
-		struct intel_engine_cs *engine;
-
-		if (!e->engines[n]) {
-			clone->engines[n] = NULL;
-			continue;
-		}
-		engine = e->engines[n]->engine;
-
-		/*
-		 * Virtual engines are singletons; they can only exist
-		 * inside a single context, because they embed their
-		 * HW context... As each virtual context implies a single
-		 * timeline (each engine can only dequeue a single request
-		 * at any time), it would be surprising for two contexts
-		 * to use the same engine. So let's create a copy of
-		 * the virtual engine instead.
-		 */
-		if (intel_engine_is_virtual(engine))
-			clone->engines[n] =
-				intel_execlists_clone_virtual(engine);
-		else
-			clone->engines[n] = intel_context_create(engine);
-		if (IS_ERR_OR_NULL(clone->engines[n])) {
-			__free_engines(clone, n);
-			goto err_unlock;
-		}
-
-		intel_context_set_gem(clone->engines[n], dst);
-	}
-	clone->num_engines = n;
-	i915_sw_fence_complete(&e->fence);
-
-	/* Serialised by constructor */
-	engines_idle_release(dst, rcu_replace_pointer(dst->engines, clone, 1));
-	if (user_engines)
-		i915_gem_context_set_user_engines(dst);
-	else
-		i915_gem_context_clear_user_engines(dst);
-	return 0;
-
-err_unlock:
-	i915_sw_fence_complete(&e->fence);
-	return -ENOMEM;
-}
-
-static int clone_flags(struct i915_gem_context *dst,
-		       struct i915_gem_context *src)
-{
-	dst->user_flags = src->user_flags;
-	return 0;
-}
-
-static int clone_schedattr(struct i915_gem_context *dst,
-			   struct i915_gem_context *src)
-{
-	dst->sched = src->sched;
-	return 0;
-}
-
-static int clone_sseu(struct i915_gem_context *dst,
-		      struct i915_gem_context *src)
-{
-	struct i915_gem_engines *e = i915_gem_context_lock_engines(src);
-	struct i915_gem_engines *clone;
-	unsigned long n;
-	int err;
-
-	/* no locking required; sole access under constructor*/
-	clone = __context_engines_static(dst);
-	if (e->num_engines != clone->num_engines) {
-		err = -EINVAL;
-		goto unlock;
-	}
-
-	for (n = 0; n < e->num_engines; n++) {
-		struct intel_context *ce = e->engines[n];
-
-		if (clone->engines[n]->engine->class != ce->engine->class) {
-			/* Must have compatible engine maps! */
-			err = -EINVAL;
-			goto unlock;
-		}
-
-		/* serialises with set_sseu */
-		err = intel_context_lock_pinned(ce);
-		if (err)
-			goto unlock;
-
-		clone->engines[n]->sseu = ce->sseu;
-		intel_context_unlock_pinned(ce);
-	}
-
-	err = 0;
-unlock:
-	i915_gem_context_unlock_engines(src);
-	return err;
-}
-
-static int clone_timeline(struct i915_gem_context *dst,
-			  struct i915_gem_context *src)
-{
-	if (src->timeline)
-		__assign_timeline(dst, src->timeline);
-
-	return 0;
-}
-
-static int clone_vm(struct i915_gem_context *dst,
-		    struct i915_gem_context *src)
-{
-	struct i915_address_space *vm;
-	int err = 0;
-
-	if (!rcu_access_pointer(src->vm))
-		return 0;
-
-	rcu_read_lock();
-	vm = context_get_vm_rcu(src);
-	rcu_read_unlock();
-
-	if (!mutex_lock_interruptible(&dst->mutex)) {
-		__assign_ppgtt(dst, vm);
-		mutex_unlock(&dst->mutex);
-	} else {
-		err = -EINTR;
-	}
-
-	i915_vm_put(vm);
-	return err;
-}
-
-static int create_clone(struct i915_user_extension __user *ext, void *data)
-{
-	static int (* const fn[])(struct i915_gem_context *dst,
-				  struct i915_gem_context *src) = {
-#define MAP(x, y) [ilog2(I915_CONTEXT_CLONE_##x)] = y
-		MAP(ENGINES, clone_engines),
-		MAP(FLAGS, clone_flags),
-		MAP(SCHEDATTR, clone_schedattr),
-		MAP(SSEU, clone_sseu),
-		MAP(TIMELINE, clone_timeline),
-		MAP(VM, clone_vm),
-#undef MAP
-	};
-	struct drm_i915_gem_context_create_ext_clone local;
-	const struct create_ext *arg = data;
-	struct i915_gem_context *dst = arg->ctx;
-	struct i915_gem_context *src;
-	int err, bit;
-
-	if (copy_from_user(&local, ext, sizeof(local)))
-		return -EFAULT;
-
-	BUILD_BUG_ON(GENMASK(BITS_PER_TYPE(local.flags) - 1, ARRAY_SIZE(fn)) !=
-		     I915_CONTEXT_CLONE_UNKNOWN);
-
-	if (local.flags & I915_CONTEXT_CLONE_UNKNOWN)
-		return -EINVAL;
-
-	if (local.rsvd)
-		return -EINVAL;
-
-	rcu_read_lock();
-	src = __i915_gem_context_lookup_rcu(arg->fpriv, local.clone_id);
-	rcu_read_unlock();
-	if (!src)
-		return -ENOENT;
-
-	GEM_BUG_ON(src == dst);
-
-	for (bit = 0; bit < ARRAY_SIZE(fn); bit++) {
-		if (!(local.flags & BIT(bit)))
-			continue;
-
-		err = fn[bit](dst, src);
-		if (err)
-			return err;
-	}
-
-	return 0;
+	return -EINVAL;
 }
 
 static const i915_user_extension_fn create_extensions[] = {
 	[I915_CONTEXT_CREATE_EXT_SETPARAM] = create_setparam,
-	[I915_CONTEXT_CREATE_EXT_CLONE] = create_clone,
+	[I915_CONTEXT_CREATE_EXT_CLONE] = invalid_ext,
 };
 
 static bool client_is_banned(struct drm_i915_file_private *file_priv)
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index de124870af44d..0e8c320927d15 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -3736,34 +3736,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 	return ERR_PTR(err);
 }
 
-struct intel_context *
-intel_execlists_clone_virtual(struct intel_engine_cs *src)
-{
-	struct virtual_engine *se = to_virtual_engine(src);
-	struct intel_context *dst;
-
-	dst = intel_execlists_create_virtual(se->siblings,
-					     se->num_siblings);
-	if (IS_ERR(dst))
-		return dst;
-
-	if (se->num_bonds) {
-		struct virtual_engine *de = to_virtual_engine(dst->engine);
-
-		de->bonds = kmemdup(se->bonds,
-				    sizeof(*se->bonds) * se->num_bonds,
-				    GFP_KERNEL);
-		if (!de->bonds) {
-			intel_context_put(dst);
-			return ERR_PTR(-ENOMEM);
-		}
-
-		de->num_bonds = se->num_bonds;
-	}
-
-	return dst;
-}
-
 int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
 				     const struct intel_engine_cs *master,
 				     const struct intel_engine_cs *sibling)
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
index fd61dae820e9e..bab3d37cf3f98 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
@@ -36,9 +36,6 @@ struct intel_context *
 intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 			       unsigned int count);
 
-struct intel_context *
-intel_execlists_clone_virtual(struct intel_engine_cs *src);
-
 int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
 				     const struct intel_engine_cs *master,
 				     const struct intel_engine_cs *sibling);
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index a0aaa8298f28d..75a71b6756ed8 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1887,20 +1887,10 @@ struct drm_i915_gem_context_create_ext_setparam {
 	struct drm_i915_gem_context_param param;
 };
 
-struct drm_i915_gem_context_create_ext_clone {
+/* This API has been removed.  On the off chance someone somewhere has
+ * attempted to use it, never re-use this extension number.
+ */
 #define I915_CONTEXT_CREATE_EXT_CLONE 1
-	struct i915_user_extension base;
-	__u32 clone_id;
-	__u32 flags;
-#define I915_CONTEXT_CLONE_ENGINES	(1u << 0)
-#define I915_CONTEXT_CLONE_FLAGS	(1u << 1)
-#define I915_CONTEXT_CLONE_SCHEDATTR	(1u << 2)
-#define I915_CONTEXT_CLONE_SSEU		(1u << 3)
-#define I915_CONTEXT_CLONE_TIMELINE	(1u << 4)
-#define I915_CONTEXT_CLONE_VM		(1u << 5)
-#define I915_CONTEXT_CLONE_UNKNOWN -(I915_CONTEXT_CLONE_VM << 1)
-	__u64 rsvd;
-};
 
 struct drm_i915_gem_context_destroy {
 	__u32 ctx_id;
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 06/27] drm/i915: Drop the CONTEXT_CLONE API
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

This API allows one context to grab bits out of another context upon
creation.  It can be used as a short-cut for setparam(getparam()) for
things like I915_CONTEXT_PARAM_VM.  However, it's never been used by any
real userspace.  It's used by a few IGT tests and that's it.  Since it
doesn't add any real value (most of the stuff you can CLONE you can copy
in other ways), drop it.

There is one thing that this API allows you to clone which you cannot
clone via getparam/setparam: timelines.  However, timelines are an
implementation detail of i915 and not really something that needs to be
exposed to userspace.  Also, sharing timelines between contexts isn't
obviously useful and supporting it has the potential to complicate i915
internally.  It also doesn't add any functionality that the client can't
get in other ways.  If a client really wants a shared timeline, they can
use a syncobj and set it as an in and out fence on every submit.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 199 +-----------------
 .../drm/i915/gt/intel_execlists_submission.c  |  28 ---
 .../drm/i915/gt/intel_execlists_submission.h  |   3 -
 include/uapi/drm/i915_drm.h                   |  16 +-
 4 files changed, 6 insertions(+), 240 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index d6f342e605254..308a63f778faf 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1958,207 +1958,14 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
 	return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
 }
 
-static int clone_engines(struct i915_gem_context *dst,
-			 struct i915_gem_context *src)
+static int invalid_ext(struct i915_user_extension __user *ext, void *data)
 {
-	struct i915_gem_engines *clone, *e;
-	bool user_engines;
-	unsigned long n;
-
-	e = __context_engines_await(src, &user_engines);
-	if (!e)
-		return -ENOENT;
-
-	clone = alloc_engines(e->num_engines);
-	if (!clone)
-		goto err_unlock;
-
-	for (n = 0; n < e->num_engines; n++) {
-		struct intel_engine_cs *engine;
-
-		if (!e->engines[n]) {
-			clone->engines[n] = NULL;
-			continue;
-		}
-		engine = e->engines[n]->engine;
-
-		/*
-		 * Virtual engines are singletons; they can only exist
-		 * inside a single context, because they embed their
-		 * HW context... As each virtual context implies a single
-		 * timeline (each engine can only dequeue a single request
-		 * at any time), it would be surprising for two contexts
-		 * to use the same engine. So let's create a copy of
-		 * the virtual engine instead.
-		 */
-		if (intel_engine_is_virtual(engine))
-			clone->engines[n] =
-				intel_execlists_clone_virtual(engine);
-		else
-			clone->engines[n] = intel_context_create(engine);
-		if (IS_ERR_OR_NULL(clone->engines[n])) {
-			__free_engines(clone, n);
-			goto err_unlock;
-		}
-
-		intel_context_set_gem(clone->engines[n], dst);
-	}
-	clone->num_engines = n;
-	i915_sw_fence_complete(&e->fence);
-
-	/* Serialised by constructor */
-	engines_idle_release(dst, rcu_replace_pointer(dst->engines, clone, 1));
-	if (user_engines)
-		i915_gem_context_set_user_engines(dst);
-	else
-		i915_gem_context_clear_user_engines(dst);
-	return 0;
-
-err_unlock:
-	i915_sw_fence_complete(&e->fence);
-	return -ENOMEM;
-}
-
-static int clone_flags(struct i915_gem_context *dst,
-		       struct i915_gem_context *src)
-{
-	dst->user_flags = src->user_flags;
-	return 0;
-}
-
-static int clone_schedattr(struct i915_gem_context *dst,
-			   struct i915_gem_context *src)
-{
-	dst->sched = src->sched;
-	return 0;
-}
-
-static int clone_sseu(struct i915_gem_context *dst,
-		      struct i915_gem_context *src)
-{
-	struct i915_gem_engines *e = i915_gem_context_lock_engines(src);
-	struct i915_gem_engines *clone;
-	unsigned long n;
-	int err;
-
-	/* no locking required; sole access under constructor*/
-	clone = __context_engines_static(dst);
-	if (e->num_engines != clone->num_engines) {
-		err = -EINVAL;
-		goto unlock;
-	}
-
-	for (n = 0; n < e->num_engines; n++) {
-		struct intel_context *ce = e->engines[n];
-
-		if (clone->engines[n]->engine->class != ce->engine->class) {
-			/* Must have compatible engine maps! */
-			err = -EINVAL;
-			goto unlock;
-		}
-
-		/* serialises with set_sseu */
-		err = intel_context_lock_pinned(ce);
-		if (err)
-			goto unlock;
-
-		clone->engines[n]->sseu = ce->sseu;
-		intel_context_unlock_pinned(ce);
-	}
-
-	err = 0;
-unlock:
-	i915_gem_context_unlock_engines(src);
-	return err;
-}
-
-static int clone_timeline(struct i915_gem_context *dst,
-			  struct i915_gem_context *src)
-{
-	if (src->timeline)
-		__assign_timeline(dst, src->timeline);
-
-	return 0;
-}
-
-static int clone_vm(struct i915_gem_context *dst,
-		    struct i915_gem_context *src)
-{
-	struct i915_address_space *vm;
-	int err = 0;
-
-	if (!rcu_access_pointer(src->vm))
-		return 0;
-
-	rcu_read_lock();
-	vm = context_get_vm_rcu(src);
-	rcu_read_unlock();
-
-	if (!mutex_lock_interruptible(&dst->mutex)) {
-		__assign_ppgtt(dst, vm);
-		mutex_unlock(&dst->mutex);
-	} else {
-		err = -EINTR;
-	}
-
-	i915_vm_put(vm);
-	return err;
-}
-
-static int create_clone(struct i915_user_extension __user *ext, void *data)
-{
-	static int (* const fn[])(struct i915_gem_context *dst,
-				  struct i915_gem_context *src) = {
-#define MAP(x, y) [ilog2(I915_CONTEXT_CLONE_##x)] = y
-		MAP(ENGINES, clone_engines),
-		MAP(FLAGS, clone_flags),
-		MAP(SCHEDATTR, clone_schedattr),
-		MAP(SSEU, clone_sseu),
-		MAP(TIMELINE, clone_timeline),
-		MAP(VM, clone_vm),
-#undef MAP
-	};
-	struct drm_i915_gem_context_create_ext_clone local;
-	const struct create_ext *arg = data;
-	struct i915_gem_context *dst = arg->ctx;
-	struct i915_gem_context *src;
-	int err, bit;
-
-	if (copy_from_user(&local, ext, sizeof(local)))
-		return -EFAULT;
-
-	BUILD_BUG_ON(GENMASK(BITS_PER_TYPE(local.flags) - 1, ARRAY_SIZE(fn)) !=
-		     I915_CONTEXT_CLONE_UNKNOWN);
-
-	if (local.flags & I915_CONTEXT_CLONE_UNKNOWN)
-		return -EINVAL;
-
-	if (local.rsvd)
-		return -EINVAL;
-
-	rcu_read_lock();
-	src = __i915_gem_context_lookup_rcu(arg->fpriv, local.clone_id);
-	rcu_read_unlock();
-	if (!src)
-		return -ENOENT;
-
-	GEM_BUG_ON(src == dst);
-
-	for (bit = 0; bit < ARRAY_SIZE(fn); bit++) {
-		if (!(local.flags & BIT(bit)))
-			continue;
-
-		err = fn[bit](dst, src);
-		if (err)
-			return err;
-	}
-
-	return 0;
+	return -EINVAL;
 }
 
 static const i915_user_extension_fn create_extensions[] = {
 	[I915_CONTEXT_CREATE_EXT_SETPARAM] = create_setparam,
-	[I915_CONTEXT_CREATE_EXT_CLONE] = create_clone,
+	[I915_CONTEXT_CREATE_EXT_CLONE] = invalid_ext,
 };
 
 static bool client_is_banned(struct drm_i915_file_private *file_priv)
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index de124870af44d..0e8c320927d15 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -3736,34 +3736,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 	return ERR_PTR(err);
 }
 
-struct intel_context *
-intel_execlists_clone_virtual(struct intel_engine_cs *src)
-{
-	struct virtual_engine *se = to_virtual_engine(src);
-	struct intel_context *dst;
-
-	dst = intel_execlists_create_virtual(se->siblings,
-					     se->num_siblings);
-	if (IS_ERR(dst))
-		return dst;
-
-	if (se->num_bonds) {
-		struct virtual_engine *de = to_virtual_engine(dst->engine);
-
-		de->bonds = kmemdup(se->bonds,
-				    sizeof(*se->bonds) * se->num_bonds,
-				    GFP_KERNEL);
-		if (!de->bonds) {
-			intel_context_put(dst);
-			return ERR_PTR(-ENOMEM);
-		}
-
-		de->num_bonds = se->num_bonds;
-	}
-
-	return dst;
-}
-
 int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
 				     const struct intel_engine_cs *master,
 				     const struct intel_engine_cs *sibling)
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
index fd61dae820e9e..bab3d37cf3f98 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
@@ -36,9 +36,6 @@ struct intel_context *
 intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 			       unsigned int count);
 
-struct intel_context *
-intel_execlists_clone_virtual(struct intel_engine_cs *src);
-
 int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
 				     const struct intel_engine_cs *master,
 				     const struct intel_engine_cs *sibling);
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index a0aaa8298f28d..75a71b6756ed8 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1887,20 +1887,10 @@ struct drm_i915_gem_context_create_ext_setparam {
 	struct drm_i915_gem_context_param param;
 };
 
-struct drm_i915_gem_context_create_ext_clone {
+/* This API has been removed.  On the off chance someone somewhere has
+ * attempted to use it, never re-use this extension number.
+ */
 #define I915_CONTEXT_CREATE_EXT_CLONE 1
-	struct i915_user_extension base;
-	__u32 clone_id;
-	__u32 flags;
-#define I915_CONTEXT_CLONE_ENGINES	(1u << 0)
-#define I915_CONTEXT_CLONE_FLAGS	(1u << 1)
-#define I915_CONTEXT_CLONE_SCHEDATTR	(1u << 2)
-#define I915_CONTEXT_CLONE_SSEU		(1u << 3)
-#define I915_CONTEXT_CLONE_TIMELINE	(1u << 4)
-#define I915_CONTEXT_CLONE_VM		(1u << 5)
-#define I915_CONTEXT_CLONE_UNKNOWN -(I915_CONTEXT_CLONE_VM << 1)
-	__u64 rsvd;
-};
 
 struct drm_i915_gem_context_destroy {
 	__u32 ctx_id;
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 07/27] drm/i915: Implement SINGLE_TIMELINE with a syncobj (v4)
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter, Jason Ekstrand

This API is entirely unnecessary and I'd love to get rid of it.  If
userspace wants a single timeline across multiple contexts, they can
either use implicit synchronization or a syncobj, both of which existed
at the time this feature landed.  The justification given at the time
was that it would help GL drivers which are inherently single-timeline.
However, neither of our GL drivers actually wanted the feature.  i965
was already in maintenance mode at the time and iris uses syncobj for
everything.

Unfortunately, as much as I'd love to get rid of it, it is used by the
media driver so we can't do that.  We can, however, do the next-best
thing which is to embed a syncobj in the context and do exactly what
we'd expect from userspace internally.  This isn't an entirely identical
implementation because it's no longer atomic if userspace races with
itself by calling execbuffer2 twice simultaneously from different
threads.  It won't crash in that case; it just doesn't guarantee any
ordering between those two submits.  It also means that sync files
exported from different engines on a SINGLE_TIMELINE context will have
different fence contexts.  This is visible to userspace if it looks at
the obj_name field of sync_fence_info.

Moving SINGLE_TIMELINE to a syncobj emulation has a couple of technical
advantages beyond mere annoyance.  One is that intel_timeline is no
longer an api-visible object and can remain entirely an implementation
detail.  This may be advantageous as we make scheduler changes going
forward.  Second is that, together with deleting the CLONE_CONTEXT API,
we should now have a 1:1 mapping between intel_context and
intel_timeline which may help us reduce locking.

v2 (Tvrtko Ursulin):
 - Update the comment on i915_gem_context::syncobj to mention that it's
   an emulation and the possible race if userspace calls execbuffer2
   twice on the same context concurrently.
v2 (Jason Ekstrand):
 - Wrap the checks for eb.gem_context->syncobj in unlikely()
 - Drop the dma_fence reference
 - Improved commit message

v3 (Jason Ekstrand):
 - Move the dma_fence_put() to before the error exit

v4 (Tvrtko Ursulin):
 - Add a comment about fence contexts to the commit message

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 49 +++++--------------
 .../gpu/drm/i915/gem/i915_gem_context_types.h | 14 +++++-
 .../gpu/drm/i915/gem/i915_gem_execbuffer.c    | 16 ++++++
 3 files changed, 40 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 308a63f778faf..3f99ef5a72f57 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -67,6 +67,8 @@
 #include <linux/log2.h>
 #include <linux/nospec.h>
 
+#include <drm/drm_syncobj.h>
+
 #include "gt/gen6_ppgtt.h"
 #include "gt/intel_context.h"
 #include "gt/intel_context_param.h"
@@ -224,10 +226,6 @@ static void intel_context_set_gem(struct intel_context *ce,
 		ce->vm = vm;
 	}
 
-	GEM_BUG_ON(ce->timeline);
-	if (ctx->timeline)
-		ce->timeline = intel_timeline_get(ctx->timeline);
-
 	if (ctx->sched.priority >= I915_PRIORITY_NORMAL &&
 	    intel_engine_has_timeslices(ce->engine))
 		__set_bit(CONTEXT_USE_SEMAPHORES, &ce->flags);
@@ -351,9 +349,6 @@ void i915_gem_context_release(struct kref *ref)
 	mutex_destroy(&ctx->engines_mutex);
 	mutex_destroy(&ctx->lut_mutex);
 
-	if (ctx->timeline)
-		intel_timeline_put(ctx->timeline);
-
 	put_pid(ctx->pid);
 	mutex_destroy(&ctx->mutex);
 
@@ -570,6 +565,9 @@ static void context_close(struct i915_gem_context *ctx)
 	if (vm)
 		i915_vm_close(vm);
 
+	if (ctx->syncobj)
+		drm_syncobj_put(ctx->syncobj);
+
 	ctx->file_priv = ERR_PTR(-EBADF);
 
 	/*
@@ -765,33 +763,11 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
 		i915_vm_close(vm);
 }
 
-static void __set_timeline(struct intel_timeline **dst,
-			   struct intel_timeline *src)
-{
-	struct intel_timeline *old = *dst;
-
-	*dst = src ? intel_timeline_get(src) : NULL;
-
-	if (old)
-		intel_timeline_put(old);
-}
-
-static void __apply_timeline(struct intel_context *ce, void *timeline)
-{
-	__set_timeline(&ce->timeline, timeline);
-}
-
-static void __assign_timeline(struct i915_gem_context *ctx,
-			      struct intel_timeline *timeline)
-{
-	__set_timeline(&ctx->timeline, timeline);
-	context_apply_all(ctx, __apply_timeline, timeline);
-}
-
 static struct i915_gem_context *
 i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
 {
 	struct i915_gem_context *ctx;
+	int ret;
 
 	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
 	    !HAS_EXECLISTS(i915))
@@ -820,16 +796,13 @@ i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
 	}
 
 	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
-		struct intel_timeline *timeline;
-
-		timeline = intel_timeline_create(&i915->gt);
-		if (IS_ERR(timeline)) {
+		ret = drm_syncobj_create(&ctx->syncobj,
+					 DRM_SYNCOBJ_CREATE_SIGNALED,
+					 NULL);
+		if (ret) {
 			context_close(ctx);
-			return ERR_CAST(timeline);
+			return ERR_PTR(ret);
 		}
-
-		__assign_timeline(ctx, timeline);
-		intel_timeline_put(timeline);
 	}
 
 	trace_i915_context_create(ctx);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 676592e27e7d2..df76767f0c41b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -83,7 +83,19 @@ struct i915_gem_context {
 	struct i915_gem_engines __rcu *engines;
 	struct mutex engines_mutex; /* guards writes to engines */
 
-	struct intel_timeline *timeline;
+	/**
+	 * @syncobj: Shared timeline syncobj
+	 *
+	 * When the SHARED_TIMELINE flag is set on context creation, we
+	 * emulate a single timeline across all engines using this syncobj.
+	 * For every execbuffer2 call, this syncobj is used as both an in-
+	 * and out-fence.  Unlike the real intel_timeline, this doesn't
+	 * provide perfect atomic in-order guarantees if the client races
+	 * with itself by calling execbuffer2 twice concurrently.  However,
+	 * if userspace races with itself, that's not likely to yield well-
+	 * defined results anyway so we choose to not care.
+	 */
+	struct drm_syncobj *syncobj;
 
 	/**
 	 * @vm: unique address space (GTT)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index b812f313422a9..d640bba6ad9ab 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -3460,6 +3460,16 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 		goto err_vma;
 	}
 
+	if (unlikely(eb.gem_context->syncobj)) {
+		struct dma_fence *fence;
+
+		fence = drm_syncobj_fence_get(eb.gem_context->syncobj);
+		err = i915_request_await_dma_fence(eb.request, fence);
+		dma_fence_put(fence);
+		if (err)
+			goto err_ext;
+	}
+
 	if (in_fence) {
 		if (args->flags & I915_EXEC_FENCE_SUBMIT)
 			err = i915_request_await_execution(eb.request,
@@ -3517,6 +3527,12 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 			fput(out_fence->file);
 		}
 	}
+
+	if (unlikely(eb.gem_context->syncobj)) {
+		drm_syncobj_replace_fence(eb.gem_context->syncobj,
+					  &eb.request->fence);
+	}
+
 	i915_request_put(eb.request);
 
 err_vma:
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 07/27] drm/i915: Implement SINGLE_TIMELINE with a syncobj (v4)
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter

This API is entirely unnecessary and I'd love to get rid of it.  If
userspace wants a single timeline across multiple contexts, they can
either use implicit synchronization or a syncobj, both of which existed
at the time this feature landed.  The justification given at the time
was that it would help GL drivers which are inherently single-timeline.
However, neither of our GL drivers actually wanted the feature.  i965
was already in maintenance mode at the time and iris uses syncobj for
everything.

Unfortunately, as much as I'd love to get rid of it, it is used by the
media driver so we can't do that.  We can, however, do the next-best
thing which is to embed a syncobj in the context and do exactly what
we'd expect from userspace internally.  This isn't an entirely identical
implementation because it's no longer atomic if userspace races with
itself by calling execbuffer2 twice simultaneously from different
threads.  It won't crash in that case; it just doesn't guarantee any
ordering between those two submits.  It also means that sync files
exported from different engines on a SINGLE_TIMELINE context will have
different fence contexts.  This is visible to userspace if it looks at
the obj_name field of sync_fence_info.

Moving SINGLE_TIMELINE to a syncobj emulation has a couple of technical
advantages beyond mere annoyance.  One is that intel_timeline is no
longer an api-visible object and can remain entirely an implementation
detail.  This may be advantageous as we make scheduler changes going
forward.  Second is that, together with deleting the CLONE_CONTEXT API,
we should now have a 1:1 mapping between intel_context and
intel_timeline which may help us reduce locking.

v2 (Tvrtko Ursulin):
 - Update the comment on i915_gem_context::syncobj to mention that it's
   an emulation and the possible race if userspace calls execbuffer2
   twice on the same context concurrently.
v2 (Jason Ekstrand):
 - Wrap the checks for eb.gem_context->syncobj in unlikely()
 - Drop the dma_fence reference
 - Improved commit message

v3 (Jason Ekstrand):
 - Move the dma_fence_put() to before the error exit

v4 (Tvrtko Ursulin):
 - Add a comment about fence contexts to the commit message

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 49 +++++--------------
 .../gpu/drm/i915/gem/i915_gem_context_types.h | 14 +++++-
 .../gpu/drm/i915/gem/i915_gem_execbuffer.c    | 16 ++++++
 3 files changed, 40 insertions(+), 39 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 308a63f778faf..3f99ef5a72f57 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -67,6 +67,8 @@
 #include <linux/log2.h>
 #include <linux/nospec.h>
 
+#include <drm/drm_syncobj.h>
+
 #include "gt/gen6_ppgtt.h"
 #include "gt/intel_context.h"
 #include "gt/intel_context_param.h"
@@ -224,10 +226,6 @@ static void intel_context_set_gem(struct intel_context *ce,
 		ce->vm = vm;
 	}
 
-	GEM_BUG_ON(ce->timeline);
-	if (ctx->timeline)
-		ce->timeline = intel_timeline_get(ctx->timeline);
-
 	if (ctx->sched.priority >= I915_PRIORITY_NORMAL &&
 	    intel_engine_has_timeslices(ce->engine))
 		__set_bit(CONTEXT_USE_SEMAPHORES, &ce->flags);
@@ -351,9 +349,6 @@ void i915_gem_context_release(struct kref *ref)
 	mutex_destroy(&ctx->engines_mutex);
 	mutex_destroy(&ctx->lut_mutex);
 
-	if (ctx->timeline)
-		intel_timeline_put(ctx->timeline);
-
 	put_pid(ctx->pid);
 	mutex_destroy(&ctx->mutex);
 
@@ -570,6 +565,9 @@ static void context_close(struct i915_gem_context *ctx)
 	if (vm)
 		i915_vm_close(vm);
 
+	if (ctx->syncobj)
+		drm_syncobj_put(ctx->syncobj);
+
 	ctx->file_priv = ERR_PTR(-EBADF);
 
 	/*
@@ -765,33 +763,11 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
 		i915_vm_close(vm);
 }
 
-static void __set_timeline(struct intel_timeline **dst,
-			   struct intel_timeline *src)
-{
-	struct intel_timeline *old = *dst;
-
-	*dst = src ? intel_timeline_get(src) : NULL;
-
-	if (old)
-		intel_timeline_put(old);
-}
-
-static void __apply_timeline(struct intel_context *ce, void *timeline)
-{
-	__set_timeline(&ce->timeline, timeline);
-}
-
-static void __assign_timeline(struct i915_gem_context *ctx,
-			      struct intel_timeline *timeline)
-{
-	__set_timeline(&ctx->timeline, timeline);
-	context_apply_all(ctx, __apply_timeline, timeline);
-}
-
 static struct i915_gem_context *
 i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
 {
 	struct i915_gem_context *ctx;
+	int ret;
 
 	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
 	    !HAS_EXECLISTS(i915))
@@ -820,16 +796,13 @@ i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
 	}
 
 	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
-		struct intel_timeline *timeline;
-
-		timeline = intel_timeline_create(&i915->gt);
-		if (IS_ERR(timeline)) {
+		ret = drm_syncobj_create(&ctx->syncobj,
+					 DRM_SYNCOBJ_CREATE_SIGNALED,
+					 NULL);
+		if (ret) {
 			context_close(ctx);
-			return ERR_CAST(timeline);
+			return ERR_PTR(ret);
 		}
-
-		__assign_timeline(ctx, timeline);
-		intel_timeline_put(timeline);
 	}
 
 	trace_i915_context_create(ctx);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 676592e27e7d2..df76767f0c41b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -83,7 +83,19 @@ struct i915_gem_context {
 	struct i915_gem_engines __rcu *engines;
 	struct mutex engines_mutex; /* guards writes to engines */
 
-	struct intel_timeline *timeline;
+	/**
+	 * @syncobj: Shared timeline syncobj
+	 *
+	 * When the SHARED_TIMELINE flag is set on context creation, we
+	 * emulate a single timeline across all engines using this syncobj.
+	 * For every execbuffer2 call, this syncobj is used as both an in-
+	 * and out-fence.  Unlike the real intel_timeline, this doesn't
+	 * provide perfect atomic in-order guarantees if the client races
+	 * with itself by calling execbuffer2 twice concurrently.  However,
+	 * if userspace races with itself, that's not likely to yield well-
+	 * defined results anyway so we choose to not care.
+	 */
+	struct drm_syncobj *syncobj;
 
 	/**
 	 * @vm: unique address space (GTT)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index b812f313422a9..d640bba6ad9ab 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -3460,6 +3460,16 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 		goto err_vma;
 	}
 
+	if (unlikely(eb.gem_context->syncobj)) {
+		struct dma_fence *fence;
+
+		fence = drm_syncobj_fence_get(eb.gem_context->syncobj);
+		err = i915_request_await_dma_fence(eb.request, fence);
+		dma_fence_put(fence);
+		if (err)
+			goto err_ext;
+	}
+
 	if (in_fence) {
 		if (args->flags & I915_EXEC_FENCE_SUBMIT)
 			err = i915_request_await_execution(eb.request,
@@ -3517,6 +3527,12 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 			fput(out_fence->file);
 		}
 	}
+
+	if (unlikely(eb.gem_context->syncobj)) {
+		drm_syncobj_replace_fence(eb.gem_context->syncobj,
+					  &eb.request->fence);
+	}
+
 	i915_request_put(eb.request);
 
 err_vma:
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 08/27] drm/i915: Drop getparam support for I915_CONTEXT_PARAM_ENGINES
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter, Jason Ekstrand

This has never been used by any userspace except IGT and provides no
real functionality beyond parroting back parameters userspace passed in
as part of context creation or via setparam.  If the context is in
legacy mode (where you use I915_EXEC_RENDER and friends), it returns
success with zero data so it's not useful for discovering what engines
are in the context.  It's also not a replacement for the recently
removed I915_CONTEXT_CLONE_ENGINES because it doesn't return any of the
balancing or bonding information.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 77 +--------------------
 1 file changed, 1 insertion(+), 76 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 3f99ef5a72f57..92e55441a7621 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1725,78 +1725,6 @@ set_engines(struct i915_gem_context *ctx,
 	return 0;
 }
 
-static int
-get_engines(struct i915_gem_context *ctx,
-	    struct drm_i915_gem_context_param *args)
-{
-	struct i915_context_param_engines __user *user;
-	struct i915_gem_engines *e;
-	size_t n, count, size;
-	bool user_engines;
-	int err = 0;
-
-	e = __context_engines_await(ctx, &user_engines);
-	if (!e)
-		return -ENOENT;
-
-	if (!user_engines) {
-		i915_sw_fence_complete(&e->fence);
-		args->size = 0;
-		return 0;
-	}
-
-	count = e->num_engines;
-
-	/* Be paranoid in case we have an impedance mismatch */
-	if (!check_struct_size(user, engines, count, &size)) {
-		err = -EINVAL;
-		goto err_free;
-	}
-	if (overflows_type(size, args->size)) {
-		err = -EINVAL;
-		goto err_free;
-	}
-
-	if (!args->size) {
-		args->size = size;
-		goto err_free;
-	}
-
-	if (args->size < size) {
-		err = -EINVAL;
-		goto err_free;
-	}
-
-	user = u64_to_user_ptr(args->value);
-	if (put_user(0, &user->extensions)) {
-		err = -EFAULT;
-		goto err_free;
-	}
-
-	for (n = 0; n < count; n++) {
-		struct i915_engine_class_instance ci = {
-			.engine_class = I915_ENGINE_CLASS_INVALID,
-			.engine_instance = I915_ENGINE_CLASS_INVALID_NONE,
-		};
-
-		if (e->engines[n]) {
-			ci.engine_class = e->engines[n]->engine->uabi_class;
-			ci.engine_instance = e->engines[n]->engine->uabi_instance;
-		}
-
-		if (copy_to_user(&user->engines[n], &ci, sizeof(ci))) {
-			err = -EFAULT;
-			goto err_free;
-		}
-	}
-
-	args->size = size;
-
-err_free:
-	i915_sw_fence_complete(&e->fence);
-	return err;
-}
-
 static int
 set_persistence(struct i915_gem_context *ctx,
 		const struct drm_i915_gem_context_param *args)
@@ -2127,10 +2055,6 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 		ret = get_ppgtt(file_priv, ctx, args);
 		break;
 
-	case I915_CONTEXT_PARAM_ENGINES:
-		ret = get_engines(ctx, args);
-		break;
-
 	case I915_CONTEXT_PARAM_PERSISTENCE:
 		args->size = 0;
 		args->value = i915_gem_context_is_persistent(ctx);
@@ -2138,6 +2062,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 
 	case I915_CONTEXT_PARAM_NO_ZEROMAP:
 	case I915_CONTEXT_PARAM_BAN_PERIOD:
+	case I915_CONTEXT_PARAM_ENGINES:
 	case I915_CONTEXT_PARAM_RINGSIZE:
 	default:
 		ret = -EINVAL;
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 08/27] drm/i915: Drop getparam support for I915_CONTEXT_PARAM_ENGINES
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter

This has never been used by any userspace except IGT and provides no
real functionality beyond parroting back parameters userspace passed in
as part of context creation or via setparam.  If the context is in
legacy mode (where you use I915_EXEC_RENDER and friends), it returns
success with zero data so it's not useful for discovering what engines
are in the context.  It's also not a replacement for the recently
removed I915_CONTEXT_CLONE_ENGINES because it doesn't return any of the
balancing or bonding information.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 77 +--------------------
 1 file changed, 1 insertion(+), 76 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 3f99ef5a72f57..92e55441a7621 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1725,78 +1725,6 @@ set_engines(struct i915_gem_context *ctx,
 	return 0;
 }
 
-static int
-get_engines(struct i915_gem_context *ctx,
-	    struct drm_i915_gem_context_param *args)
-{
-	struct i915_context_param_engines __user *user;
-	struct i915_gem_engines *e;
-	size_t n, count, size;
-	bool user_engines;
-	int err = 0;
-
-	e = __context_engines_await(ctx, &user_engines);
-	if (!e)
-		return -ENOENT;
-
-	if (!user_engines) {
-		i915_sw_fence_complete(&e->fence);
-		args->size = 0;
-		return 0;
-	}
-
-	count = e->num_engines;
-
-	/* Be paranoid in case we have an impedance mismatch */
-	if (!check_struct_size(user, engines, count, &size)) {
-		err = -EINVAL;
-		goto err_free;
-	}
-	if (overflows_type(size, args->size)) {
-		err = -EINVAL;
-		goto err_free;
-	}
-
-	if (!args->size) {
-		args->size = size;
-		goto err_free;
-	}
-
-	if (args->size < size) {
-		err = -EINVAL;
-		goto err_free;
-	}
-
-	user = u64_to_user_ptr(args->value);
-	if (put_user(0, &user->extensions)) {
-		err = -EFAULT;
-		goto err_free;
-	}
-
-	for (n = 0; n < count; n++) {
-		struct i915_engine_class_instance ci = {
-			.engine_class = I915_ENGINE_CLASS_INVALID,
-			.engine_instance = I915_ENGINE_CLASS_INVALID_NONE,
-		};
-
-		if (e->engines[n]) {
-			ci.engine_class = e->engines[n]->engine->uabi_class;
-			ci.engine_instance = e->engines[n]->engine->uabi_instance;
-		}
-
-		if (copy_to_user(&user->engines[n], &ci, sizeof(ci))) {
-			err = -EFAULT;
-			goto err_free;
-		}
-	}
-
-	args->size = size;
-
-err_free:
-	i915_sw_fence_complete(&e->fence);
-	return err;
-}
-
 static int
 set_persistence(struct i915_gem_context *ctx,
 		const struct drm_i915_gem_context_param *args)
@@ -2127,10 +2055,6 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 		ret = get_ppgtt(file_priv, ctx, args);
 		break;
 
-	case I915_CONTEXT_PARAM_ENGINES:
-		ret = get_engines(ctx, args);
-		break;
-
 	case I915_CONTEXT_PARAM_PERSISTENCE:
 		args->size = 0;
 		args->value = i915_gem_context_is_persistent(ctx);
@@ -2138,6 +2062,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 
 	case I915_CONTEXT_PARAM_NO_ZEROMAP:
 	case I915_CONTEXT_PARAM_BAN_PERIOD:
+	case I915_CONTEXT_PARAM_ENGINES:
 	case I915_CONTEXT_PARAM_RINGSIZE:
 	default:
 		ret = -EINVAL;
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 09/27] drm/i915/gem: Disallow bonding of virtual engines (v3)
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

This adds a bunch of complexity which the media driver has never
actually used.  The media driver does technically bond a balanced engine
to another engine but the balanced engine only has one engine in the
sibling set.  This doesn't actually result in a virtual engine.

This functionality was originally added to handle cases where we may
have more than two video engines and media might want to load-balance
their bonded submits by, for instance, submitting to a balanced vcs0-1
as the primary and then vcs2-3 as the secondary.  However, no such
hardware has shipped thus far and, if we ever want to enable such
use-cases in the future, we'll use the up-and-coming parallel submit API
which targets GuC submission.

This makes I915_CONTEXT_ENGINES_EXT_BOND a total no-op.  We leave the
validation code in place in case we ever decide we want to do something
interesting with the bonding information.

v2 (Jason Ekstrand):
 - Don't delete quite as much code.

v3 (Tvrtko Ursulin):
 - Add some history to the commit message

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   |  18 +-
 .../drm/i915/gt/intel_execlists_submission.c  |  69 ------
 .../drm/i915/gt/intel_execlists_submission.h  |   4 -
 drivers/gpu/drm/i915/gt/selftest_execlists.c  | 229 ------------------
 4 files changed, 6 insertions(+), 314 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 92e55441a7621..be42dc918ef6f 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1553,6 +1553,12 @@ set_engines__bond(struct i915_user_extension __user *base, void *data)
 	}
 	virtual = set->engines->engines[idx]->engine;
 
+	if (intel_engine_is_virtual(virtual)) {
+		drm_dbg(&i915->drm,
+			"Bonding with virtual engines not allowed\n");
+		return -EINVAL;
+	}
+
 	err = check_user_mbz(&ext->flags);
 	if (err)
 		return err;
@@ -1593,18 +1599,6 @@ set_engines__bond(struct i915_user_extension __user *base, void *data)
 				n, ci.engine_class, ci.engine_instance);
 			return -EINVAL;
 		}
-
-		/*
-		 * A non-virtual engine has no siblings to choose between; and
-		 * a submit fence will always be directed to the one engine.
-		 */
-		if (intel_engine_is_virtual(virtual)) {
-			err = intel_virtual_engine_attach_bond(virtual,
-							       master,
-							       bond);
-			if (err)
-				return err;
-		}
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index 0e8c320927d15..14378b28169b7 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -181,18 +181,6 @@ struct virtual_engine {
 		int prio;
 	} nodes[I915_NUM_ENGINES];
 
-	/*
-	 * Keep track of bonded pairs -- restrictions upon on our selection
-	 * of physical engines any particular request may be submitted to.
-	 * If we receive a submit-fence from a master engine, we will only
-	 * use one of sibling_mask physical engines.
-	 */
-	struct ve_bond {
-		const struct intel_engine_cs *master;
-		intel_engine_mask_t sibling_mask;
-	} *bonds;
-	unsigned int num_bonds;
-
 	/* And finally, which physical engines this virtual engine maps onto. */
 	unsigned int num_siblings;
 	struct intel_engine_cs *siblings[];
@@ -3307,7 +3295,6 @@ static void rcu_virtual_context_destroy(struct work_struct *wrk)
 	intel_breadcrumbs_free(ve->base.breadcrumbs);
 	intel_engine_free_request_pool(&ve->base);
 
-	kfree(ve->bonds);
 	kfree(ve);
 }
 
@@ -3560,33 +3547,13 @@ static void virtual_submit_request(struct i915_request *rq)
 	spin_unlock_irqrestore(&ve->base.active.lock, flags);
 }
 
-static struct ve_bond *
-virtual_find_bond(struct virtual_engine *ve,
-		  const struct intel_engine_cs *master)
-{
-	int i;
-
-	for (i = 0; i < ve->num_bonds; i++) {
-		if (ve->bonds[i].master == master)
-			return &ve->bonds[i];
-	}
-
-	return NULL;
-}
-
 static void
 virtual_bond_execute(struct i915_request *rq, struct dma_fence *signal)
 {
-	struct virtual_engine *ve = to_virtual_engine(rq->engine);
 	intel_engine_mask_t allowed, exec;
-	struct ve_bond *bond;
 
 	allowed = ~to_request(signal)->engine->mask;
 
-	bond = virtual_find_bond(ve, to_request(signal)->engine);
-	if (bond)
-		allowed &= bond->sibling_mask;
-
 	/* Restrict the bonded request to run on only the available engines */
 	exec = READ_ONCE(rq->execution_mask);
 	while (!try_cmpxchg(&rq->execution_mask, &exec, exec & allowed))
@@ -3736,42 +3703,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 	return ERR_PTR(err);
 }
 
-int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
-				     const struct intel_engine_cs *master,
-				     const struct intel_engine_cs *sibling)
-{
-	struct virtual_engine *ve = to_virtual_engine(engine);
-	struct ve_bond *bond;
-	int n;
-
-	/* Sanity check the sibling is part of the virtual engine */
-	for (n = 0; n < ve->num_siblings; n++)
-		if (sibling == ve->siblings[n])
-			break;
-	if (n == ve->num_siblings)
-		return -EINVAL;
-
-	bond = virtual_find_bond(ve, master);
-	if (bond) {
-		bond->sibling_mask |= sibling->mask;
-		return 0;
-	}
-
-	bond = krealloc(ve->bonds,
-			sizeof(*bond) * (ve->num_bonds + 1),
-			GFP_KERNEL);
-	if (!bond)
-		return -ENOMEM;
-
-	bond[ve->num_bonds].master = master;
-	bond[ve->num_bonds].sibling_mask = sibling->mask;
-
-	ve->bonds = bond;
-	ve->num_bonds++;
-
-	return 0;
-}
-
 void intel_execlists_show_requests(struct intel_engine_cs *engine,
 				   struct drm_printer *m,
 				   void (*show_request)(struct drm_printer *m,
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
index bab3d37cf3f98..ad4f3e1a0fded 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
@@ -36,10 +36,6 @@ struct intel_context *
 intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 			       unsigned int count);
 
-int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
-				     const struct intel_engine_cs *master,
-				     const struct intel_engine_cs *sibling);
-
 bool
 intel_engine_in_execlists_submission_mode(const struct intel_engine_cs *engine);
 
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index 01d9896dd4844..a0e75b71a3374 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -4311,234 +4311,6 @@ static int live_virtual_preserved(void *arg)
 	return 0;
 }
 
-static int bond_virtual_engine(struct intel_gt *gt,
-			       unsigned int class,
-			       struct intel_engine_cs **siblings,
-			       unsigned int nsibling,
-			       unsigned int flags)
-#define BOND_SCHEDULE BIT(0)
-{
-	struct intel_engine_cs *master;
-	struct i915_request *rq[16];
-	enum intel_engine_id id;
-	struct igt_spinner spin;
-	unsigned long n;
-	int err;
-
-	/*
-	 * A set of bonded requests is intended to be run concurrently
-	 * across a number of engines. We use one request per-engine
-	 * and a magic fence to schedule each of the bonded requests
-	 * at the same time. A consequence of our current scheduler is that
-	 * we only move requests to the HW ready queue when the request
-	 * becomes ready, that is when all of its prerequisite fences have
-	 * been signaled. As one of those fences is the master submit fence,
-	 * there is a delay on all secondary fences as the HW may be
-	 * currently busy. Equally, as all the requests are independent,
-	 * they may have other fences that delay individual request
-	 * submission to HW. Ergo, we do not guarantee that all requests are
-	 * immediately submitted to HW at the same time, just that if the
-	 * rules are abided by, they are ready at the same time as the
-	 * first is submitted. Userspace can embed semaphores in its batch
-	 * to ensure parallel execution of its phases as it requires.
-	 * Though naturally it gets requested that perhaps the scheduler should
-	 * take care of parallel execution, even across preemption events on
-	 * different HW. (The proper answer is of course "lalalala".)
-	 *
-	 * With the submit-fence, we have identified three possible phases
-	 * of synchronisation depending on the master fence: queued (not
-	 * ready), executing, and signaled. The first two are quite simple
-	 * and checked below. However, the signaled master fence handling is
-	 * contentious. Currently we do not distinguish between a signaled
-	 * fence and an expired fence, as once signaled it does not convey
-	 * any information about the previous execution. It may even be freed
-	 * and hence checking later it may not exist at all. Ergo we currently
-	 * do not apply the bonding constraint for an already signaled fence,
-	 * as our expectation is that it should not constrain the secondaries
-	 * and is outside of the scope of the bonded request API (i.e. all
-	 * userspace requests are meant to be running in parallel). As
-	 * it imposes no constraint, and is effectively a no-op, we do not
-	 * check below as normal execution flows are checked extensively above.
-	 *
-	 * XXX Is the degenerate handling of signaled submit fences the
-	 * expected behaviour for userpace?
-	 */
-
-	GEM_BUG_ON(nsibling >= ARRAY_SIZE(rq) - 1);
-
-	if (igt_spinner_init(&spin, gt))
-		return -ENOMEM;
-
-	err = 0;
-	rq[0] = ERR_PTR(-ENOMEM);
-	for_each_engine(master, gt, id) {
-		struct i915_sw_fence fence = {};
-		struct intel_context *ce;
-
-		if (master->class == class)
-			continue;
-
-		ce = intel_context_create(master);
-		if (IS_ERR(ce)) {
-			err = PTR_ERR(ce);
-			goto out;
-		}
-
-		memset_p((void *)rq, ERR_PTR(-EINVAL), ARRAY_SIZE(rq));
-
-		rq[0] = igt_spinner_create_request(&spin, ce, MI_NOOP);
-		intel_context_put(ce);
-		if (IS_ERR(rq[0])) {
-			err = PTR_ERR(rq[0]);
-			goto out;
-		}
-		i915_request_get(rq[0]);
-
-		if (flags & BOND_SCHEDULE) {
-			onstack_fence_init(&fence);
-			err = i915_sw_fence_await_sw_fence_gfp(&rq[0]->submit,
-							       &fence,
-							       GFP_KERNEL);
-		}
-
-		i915_request_add(rq[0]);
-		if (err < 0)
-			goto out;
-
-		if (!(flags & BOND_SCHEDULE) &&
-		    !igt_wait_for_spinner(&spin, rq[0])) {
-			err = -EIO;
-			goto out;
-		}
-
-		for (n = 0; n < nsibling; n++) {
-			struct intel_context *ve;
-
-			ve = intel_execlists_create_virtual(siblings, nsibling);
-			if (IS_ERR(ve)) {
-				err = PTR_ERR(ve);
-				onstack_fence_fini(&fence);
-				goto out;
-			}
-
-			err = intel_virtual_engine_attach_bond(ve->engine,
-							       master,
-							       siblings[n]);
-			if (err) {
-				intel_context_put(ve);
-				onstack_fence_fini(&fence);
-				goto out;
-			}
-
-			err = intel_context_pin(ve);
-			intel_context_put(ve);
-			if (err) {
-				onstack_fence_fini(&fence);
-				goto out;
-			}
-
-			rq[n + 1] = i915_request_create(ve);
-			intel_context_unpin(ve);
-			if (IS_ERR(rq[n + 1])) {
-				err = PTR_ERR(rq[n + 1]);
-				onstack_fence_fini(&fence);
-				goto out;
-			}
-			i915_request_get(rq[n + 1]);
-
-			err = i915_request_await_execution(rq[n + 1],
-							   &rq[0]->fence,
-							   ve->engine->bond_execute);
-			i915_request_add(rq[n + 1]);
-			if (err < 0) {
-				onstack_fence_fini(&fence);
-				goto out;
-			}
-		}
-		onstack_fence_fini(&fence);
-		intel_engine_flush_submission(master);
-		igt_spinner_end(&spin);
-
-		if (i915_request_wait(rq[0], 0, HZ / 10) < 0) {
-			pr_err("Master request did not execute (on %s)!\n",
-			       rq[0]->engine->name);
-			err = -EIO;
-			goto out;
-		}
-
-		for (n = 0; n < nsibling; n++) {
-			if (i915_request_wait(rq[n + 1], 0,
-					      MAX_SCHEDULE_TIMEOUT) < 0) {
-				err = -EIO;
-				goto out;
-			}
-
-			if (rq[n + 1]->engine != siblings[n]) {
-				pr_err("Bonded request did not execute on target engine: expected %s, used %s; master was %s\n",
-				       siblings[n]->name,
-				       rq[n + 1]->engine->name,
-				       rq[0]->engine->name);
-				err = -EINVAL;
-				goto out;
-			}
-		}
-
-		for (n = 0; !IS_ERR(rq[n]); n++)
-			i915_request_put(rq[n]);
-		rq[0] = ERR_PTR(-ENOMEM);
-	}
-
-out:
-	for (n = 0; !IS_ERR(rq[n]); n++)
-		i915_request_put(rq[n]);
-	if (igt_flush_test(gt->i915))
-		err = -EIO;
-
-	igt_spinner_fini(&spin);
-	return err;
-}
-
-static int live_virtual_bond(void *arg)
-{
-	static const struct phase {
-		const char *name;
-		unsigned int flags;
-	} phases[] = {
-		{ "", 0 },
-		{ "schedule", BOND_SCHEDULE },
-		{ },
-	};
-	struct intel_gt *gt = arg;
-	struct intel_engine_cs *siblings[MAX_ENGINE_INSTANCE + 1];
-	unsigned int class;
-	int err;
-
-	if (intel_uc_uses_guc_submission(&gt->uc))
-		return 0;
-
-	for (class = 0; class <= MAX_ENGINE_CLASS; class++) {
-		const struct phase *p;
-		int nsibling;
-
-		nsibling = select_siblings(gt, class, siblings);
-		if (nsibling < 2)
-			continue;
-
-		for (p = phases; p->name; p++) {
-			err = bond_virtual_engine(gt,
-						  class, siblings, nsibling,
-						  p->flags);
-			if (err) {
-				pr_err("%s(%s): failed class=%d, nsibling=%d, err=%d\n",
-				       __func__, p->name, class, nsibling, err);
-				return err;
-			}
-		}
-	}
-
-	return 0;
-}
-
 static int reset_virtual_engine(struct intel_gt *gt,
 				struct intel_engine_cs **siblings,
 				unsigned int nsibling)
@@ -4712,7 +4484,6 @@ int intel_execlists_live_selftests(struct drm_i915_private *i915)
 		SUBTEST(live_virtual_mask),
 		SUBTEST(live_virtual_preserved),
 		SUBTEST(live_virtual_slice),
-		SUBTEST(live_virtual_bond),
 		SUBTEST(live_virtual_reset),
 	};
 
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 09/27] drm/i915/gem: Disallow bonding of virtual engines (v3)
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

This adds a bunch of complexity which the media driver has never
actually used.  The media driver does technically bond a balanced engine
to another engine but the balanced engine only has one engine in the
sibling set.  This doesn't actually result in a virtual engine.

This functionality was originally added to handle cases where we may
have more than two video engines and media might want to load-balance
their bonded submits by, for instance, submitting to a balanced vcs0-1
as the primary and then vcs2-3 as the secondary.  However, no such
hardware has shipped thus far and, if we ever want to enable such
use-cases in the future, we'll use the up-and-coming parallel submit API
which targets GuC submission.

This makes I915_CONTEXT_ENGINES_EXT_BOND a total no-op.  We leave the
validation code in place in case we ever decide we want to do something
interesting with the bonding information.

v2 (Jason Ekstrand):
 - Don't delete quite as much code.

v3 (Tvrtko Ursulin):
 - Add some history to the commit message

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   |  18 +-
 .../drm/i915/gt/intel_execlists_submission.c  |  69 ------
 .../drm/i915/gt/intel_execlists_submission.h  |   4 -
 drivers/gpu/drm/i915/gt/selftest_execlists.c  | 229 ------------------
 4 files changed, 6 insertions(+), 314 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 92e55441a7621..be42dc918ef6f 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1553,6 +1553,12 @@ set_engines__bond(struct i915_user_extension __user *base, void *data)
 	}
 	virtual = set->engines->engines[idx]->engine;
 
+	if (intel_engine_is_virtual(virtual)) {
+		drm_dbg(&i915->drm,
+			"Bonding with virtual engines not allowed\n");
+		return -EINVAL;
+	}
+
 	err = check_user_mbz(&ext->flags);
 	if (err)
 		return err;
@@ -1593,18 +1599,6 @@ set_engines__bond(struct i915_user_extension __user *base, void *data)
 				n, ci.engine_class, ci.engine_instance);
 			return -EINVAL;
 		}
-
-		/*
-		 * A non-virtual engine has no siblings to choose between; and
-		 * a submit fence will always be directed to the one engine.
-		 */
-		if (intel_engine_is_virtual(virtual)) {
-			err = intel_virtual_engine_attach_bond(virtual,
-							       master,
-							       bond);
-			if (err)
-				return err;
-		}
 	}
 
 	return 0;
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index 0e8c320927d15..14378b28169b7 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -181,18 +181,6 @@ struct virtual_engine {
 		int prio;
 	} nodes[I915_NUM_ENGINES];
 
-	/*
-	 * Keep track of bonded pairs -- restrictions upon on our selection
-	 * of physical engines any particular request may be submitted to.
-	 * If we receive a submit-fence from a master engine, we will only
-	 * use one of sibling_mask physical engines.
-	 */
-	struct ve_bond {
-		const struct intel_engine_cs *master;
-		intel_engine_mask_t sibling_mask;
-	} *bonds;
-	unsigned int num_bonds;
-
 	/* And finally, which physical engines this virtual engine maps onto. */
 	unsigned int num_siblings;
 	struct intel_engine_cs *siblings[];
@@ -3307,7 +3295,6 @@ static void rcu_virtual_context_destroy(struct work_struct *wrk)
 	intel_breadcrumbs_free(ve->base.breadcrumbs);
 	intel_engine_free_request_pool(&ve->base);
 
-	kfree(ve->bonds);
 	kfree(ve);
 }
 
@@ -3560,33 +3547,13 @@ static void virtual_submit_request(struct i915_request *rq)
 	spin_unlock_irqrestore(&ve->base.active.lock, flags);
 }
 
-static struct ve_bond *
-virtual_find_bond(struct virtual_engine *ve,
-		  const struct intel_engine_cs *master)
-{
-	int i;
-
-	for (i = 0; i < ve->num_bonds; i++) {
-		if (ve->bonds[i].master == master)
-			return &ve->bonds[i];
-	}
-
-	return NULL;
-}
-
 static void
 virtual_bond_execute(struct i915_request *rq, struct dma_fence *signal)
 {
-	struct virtual_engine *ve = to_virtual_engine(rq->engine);
 	intel_engine_mask_t allowed, exec;
-	struct ve_bond *bond;
 
 	allowed = ~to_request(signal)->engine->mask;
 
-	bond = virtual_find_bond(ve, to_request(signal)->engine);
-	if (bond)
-		allowed &= bond->sibling_mask;
-
 	/* Restrict the bonded request to run on only the available engines */
 	exec = READ_ONCE(rq->execution_mask);
 	while (!try_cmpxchg(&rq->execution_mask, &exec, exec & allowed))
@@ -3736,42 +3703,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 	return ERR_PTR(err);
 }
 
-int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
-				     const struct intel_engine_cs *master,
-				     const struct intel_engine_cs *sibling)
-{
-	struct virtual_engine *ve = to_virtual_engine(engine);
-	struct ve_bond *bond;
-	int n;
-
-	/* Sanity check the sibling is part of the virtual engine */
-	for (n = 0; n < ve->num_siblings; n++)
-		if (sibling == ve->siblings[n])
-			break;
-	if (n == ve->num_siblings)
-		return -EINVAL;
-
-	bond = virtual_find_bond(ve, master);
-	if (bond) {
-		bond->sibling_mask |= sibling->mask;
-		return 0;
-	}
-
-	bond = krealloc(ve->bonds,
-			sizeof(*bond) * (ve->num_bonds + 1),
-			GFP_KERNEL);
-	if (!bond)
-		return -ENOMEM;
-
-	bond[ve->num_bonds].master = master;
-	bond[ve->num_bonds].sibling_mask = sibling->mask;
-
-	ve->bonds = bond;
-	ve->num_bonds++;
-
-	return 0;
-}
-
 void intel_execlists_show_requests(struct intel_engine_cs *engine,
 				   struct drm_printer *m,
 				   void (*show_request)(struct drm_printer *m,
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
index bab3d37cf3f98..ad4f3e1a0fded 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
@@ -36,10 +36,6 @@ struct intel_context *
 intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 			       unsigned int count);
 
-int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
-				     const struct intel_engine_cs *master,
-				     const struct intel_engine_cs *sibling);
-
 bool
 intel_engine_in_execlists_submission_mode(const struct intel_engine_cs *engine);
 
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index 01d9896dd4844..a0e75b71a3374 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -4311,234 +4311,6 @@ static int live_virtual_preserved(void *arg)
 	return 0;
 }
 
-static int bond_virtual_engine(struct intel_gt *gt,
-			       unsigned int class,
-			       struct intel_engine_cs **siblings,
-			       unsigned int nsibling,
-			       unsigned int flags)
-#define BOND_SCHEDULE BIT(0)
-{
-	struct intel_engine_cs *master;
-	struct i915_request *rq[16];
-	enum intel_engine_id id;
-	struct igt_spinner spin;
-	unsigned long n;
-	int err;
-
-	/*
-	 * A set of bonded requests is intended to be run concurrently
-	 * across a number of engines. We use one request per-engine
-	 * and a magic fence to schedule each of the bonded requests
-	 * at the same time. A consequence of our current scheduler is that
-	 * we only move requests to the HW ready queue when the request
-	 * becomes ready, that is when all of its prerequisite fences have
-	 * been signaled. As one of those fences is the master submit fence,
-	 * there is a delay on all secondary fences as the HW may be
-	 * currently busy. Equally, as all the requests are independent,
-	 * they may have other fences that delay individual request
-	 * submission to HW. Ergo, we do not guarantee that all requests are
-	 * immediately submitted to HW at the same time, just that if the
-	 * rules are abided by, they are ready at the same time as the
-	 * first is submitted. Userspace can embed semaphores in its batch
-	 * to ensure parallel execution of its phases as it requires.
-	 * Though naturally it gets requested that perhaps the scheduler should
-	 * take care of parallel execution, even across preemption events on
-	 * different HW. (The proper answer is of course "lalalala".)
-	 *
-	 * With the submit-fence, we have identified three possible phases
-	 * of synchronisation depending on the master fence: queued (not
-	 * ready), executing, and signaled. The first two are quite simple
-	 * and checked below. However, the signaled master fence handling is
-	 * contentious. Currently we do not distinguish between a signaled
-	 * fence and an expired fence, as once signaled it does not convey
-	 * any information about the previous execution. It may even be freed
-	 * and hence checking later it may not exist at all. Ergo we currently
-	 * do not apply the bonding constraint for an already signaled fence,
-	 * as our expectation is that it should not constrain the secondaries
-	 * and is outside of the scope of the bonded request API (i.e. all
-	 * userspace requests are meant to be running in parallel). As
-	 * it imposes no constraint, and is effectively a no-op, we do not
-	 * check below as normal execution flows are checked extensively above.
-	 *
-	 * XXX Is the degenerate handling of signaled submit fences the
-	 * expected behaviour for userpace?
-	 */
-
-	GEM_BUG_ON(nsibling >= ARRAY_SIZE(rq) - 1);
-
-	if (igt_spinner_init(&spin, gt))
-		return -ENOMEM;
-
-	err = 0;
-	rq[0] = ERR_PTR(-ENOMEM);
-	for_each_engine(master, gt, id) {
-		struct i915_sw_fence fence = {};
-		struct intel_context *ce;
-
-		if (master->class == class)
-			continue;
-
-		ce = intel_context_create(master);
-		if (IS_ERR(ce)) {
-			err = PTR_ERR(ce);
-			goto out;
-		}
-
-		memset_p((void *)rq, ERR_PTR(-EINVAL), ARRAY_SIZE(rq));
-
-		rq[0] = igt_spinner_create_request(&spin, ce, MI_NOOP);
-		intel_context_put(ce);
-		if (IS_ERR(rq[0])) {
-			err = PTR_ERR(rq[0]);
-			goto out;
-		}
-		i915_request_get(rq[0]);
-
-		if (flags & BOND_SCHEDULE) {
-			onstack_fence_init(&fence);
-			err = i915_sw_fence_await_sw_fence_gfp(&rq[0]->submit,
-							       &fence,
-							       GFP_KERNEL);
-		}
-
-		i915_request_add(rq[0]);
-		if (err < 0)
-			goto out;
-
-		if (!(flags & BOND_SCHEDULE) &&
-		    !igt_wait_for_spinner(&spin, rq[0])) {
-			err = -EIO;
-			goto out;
-		}
-
-		for (n = 0; n < nsibling; n++) {
-			struct intel_context *ve;
-
-			ve = intel_execlists_create_virtual(siblings, nsibling);
-			if (IS_ERR(ve)) {
-				err = PTR_ERR(ve);
-				onstack_fence_fini(&fence);
-				goto out;
-			}
-
-			err = intel_virtual_engine_attach_bond(ve->engine,
-							       master,
-							       siblings[n]);
-			if (err) {
-				intel_context_put(ve);
-				onstack_fence_fini(&fence);
-				goto out;
-			}
-
-			err = intel_context_pin(ve);
-			intel_context_put(ve);
-			if (err) {
-				onstack_fence_fini(&fence);
-				goto out;
-			}
-
-			rq[n + 1] = i915_request_create(ve);
-			intel_context_unpin(ve);
-			if (IS_ERR(rq[n + 1])) {
-				err = PTR_ERR(rq[n + 1]);
-				onstack_fence_fini(&fence);
-				goto out;
-			}
-			i915_request_get(rq[n + 1]);
-
-			err = i915_request_await_execution(rq[n + 1],
-							   &rq[0]->fence,
-							   ve->engine->bond_execute);
-			i915_request_add(rq[n + 1]);
-			if (err < 0) {
-				onstack_fence_fini(&fence);
-				goto out;
-			}
-		}
-		onstack_fence_fini(&fence);
-		intel_engine_flush_submission(master);
-		igt_spinner_end(&spin);
-
-		if (i915_request_wait(rq[0], 0, HZ / 10) < 0) {
-			pr_err("Master request did not execute (on %s)!\n",
-			       rq[0]->engine->name);
-			err = -EIO;
-			goto out;
-		}
-
-		for (n = 0; n < nsibling; n++) {
-			if (i915_request_wait(rq[n + 1], 0,
-					      MAX_SCHEDULE_TIMEOUT) < 0) {
-				err = -EIO;
-				goto out;
-			}
-
-			if (rq[n + 1]->engine != siblings[n]) {
-				pr_err("Bonded request did not execute on target engine: expected %s, used %s; master was %s\n",
-				       siblings[n]->name,
-				       rq[n + 1]->engine->name,
-				       rq[0]->engine->name);
-				err = -EINVAL;
-				goto out;
-			}
-		}
-
-		for (n = 0; !IS_ERR(rq[n]); n++)
-			i915_request_put(rq[n]);
-		rq[0] = ERR_PTR(-ENOMEM);
-	}
-
-out:
-	for (n = 0; !IS_ERR(rq[n]); n++)
-		i915_request_put(rq[n]);
-	if (igt_flush_test(gt->i915))
-		err = -EIO;
-
-	igt_spinner_fini(&spin);
-	return err;
-}
-
-static int live_virtual_bond(void *arg)
-{
-	static const struct phase {
-		const char *name;
-		unsigned int flags;
-	} phases[] = {
-		{ "", 0 },
-		{ "schedule", BOND_SCHEDULE },
-		{ },
-	};
-	struct intel_gt *gt = arg;
-	struct intel_engine_cs *siblings[MAX_ENGINE_INSTANCE + 1];
-	unsigned int class;
-	int err;
-
-	if (intel_uc_uses_guc_submission(&gt->uc))
-		return 0;
-
-	for (class = 0; class <= MAX_ENGINE_CLASS; class++) {
-		const struct phase *p;
-		int nsibling;
-
-		nsibling = select_siblings(gt, class, siblings);
-		if (nsibling < 2)
-			continue;
-
-		for (p = phases; p->name; p++) {
-			err = bond_virtual_engine(gt,
-						  class, siblings, nsibling,
-						  p->flags);
-			if (err) {
-				pr_err("%s(%s): failed class=%d, nsibling=%d, err=%d\n",
-				       __func__, p->name, class, nsibling, err);
-				return err;
-			}
-		}
-	}
-
-	return 0;
-}
-
 static int reset_virtual_engine(struct intel_gt *gt,
 				struct intel_engine_cs **siblings,
 				unsigned int nsibling)
@@ -4712,7 +4484,6 @@ int intel_execlists_live_selftests(struct drm_i915_private *i915)
 		SUBTEST(live_virtual_mask),
 		SUBTEST(live_virtual_preserved),
 		SUBTEST(live_virtual_slice),
-		SUBTEST(live_virtual_bond),
 		SUBTEST(live_virtual_reset),
 	};
 
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 10/27] drm/i915/gem: Remove engine auto-magic with FENCE_SUBMIT
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

Even though FENCE_SUBMIT is only documented to wait until the request in
the in-fence starts instead of waiting until it completes, it has a bit
more magic than that.  If FENCE_SUBMIT is used to submit something to a
balanced engine, we would wait to assign engines until the primary
request was ready to start and then attempt to assign it to a different
engine than the primary.  There is an IGT test which exercises this by
submitting a primary batch to a specific VCS and then using FENCE_SUBMIT
to submit a secondary which can run on any VCS and have i915 figure out
which VCS to run it on such that they can run in parallel.

However, this functionality has never been used in the real world.  The
media driver (the only user of FENCE_SUBMIT) always picks exactly two
physical engines to bond and never asks us to pick which to use.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c  |  2 +-
 drivers/gpu/drm/i915/gt/intel_engine_types.h    |  7 -------
 .../drm/i915/gt/intel_execlists_submission.c    | 17 -----------------
 3 files changed, 1 insertion(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index d640bba6ad9ab..efb2fa3522a42 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -3474,7 +3474,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 		if (args->flags & I915_EXEC_FENCE_SUBMIT)
 			err = i915_request_await_execution(eb.request,
 							   in_fence,
-							   eb.engine->bond_execute);
+							   NULL);
 		else
 			err = i915_request_await_dma_fence(eb.request,
 							   in_fence);
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
index 883bafc449024..68cfe5080325c 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
@@ -446,13 +446,6 @@ struct intel_engine_cs {
 	 */
 	void		(*submit_request)(struct i915_request *rq);
 
-	/*
-	 * Called on signaling of a SUBMIT_FENCE, passing along the signaling
-	 * request down to the bonded pairs.
-	 */
-	void            (*bond_execute)(struct i915_request *rq,
-					struct dma_fence *signal);
-
 	/*
 	 * Call when the priority on a request has changed and it and its
 	 * dependencies may need rescheduling. Note the request itself may
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index 14378b28169b7..635d6d2494d26 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -3547,22 +3547,6 @@ static void virtual_submit_request(struct i915_request *rq)
 	spin_unlock_irqrestore(&ve->base.active.lock, flags);
 }
 
-static void
-virtual_bond_execute(struct i915_request *rq, struct dma_fence *signal)
-{
-	intel_engine_mask_t allowed, exec;
-
-	allowed = ~to_request(signal)->engine->mask;
-
-	/* Restrict the bonded request to run on only the available engines */
-	exec = READ_ONCE(rq->execution_mask);
-	while (!try_cmpxchg(&rq->execution_mask, &exec, exec & allowed))
-		;
-
-	/* Prevent the master from being re-run on the bonded engines */
-	to_request(signal)->execution_mask &= ~allowed;
-}
-
 struct intel_context *
 intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 			       unsigned int count)
@@ -3616,7 +3600,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 
 	ve->base.schedule = i915_schedule;
 	ve->base.submit_request = virtual_submit_request;
-	ve->base.bond_execute = virtual_bond_execute;
 
 	INIT_LIST_HEAD(virtual_queue(ve));
 	ve->base.execlists.queue_priority_hint = INT_MIN;
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 10/27] drm/i915/gem: Remove engine auto-magic with FENCE_SUBMIT
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

Even though FENCE_SUBMIT is only documented to wait until the request in
the in-fence starts instead of waiting until it completes, it has a bit
more magic than that.  If FENCE_SUBMIT is used to submit something to a
balanced engine, we would wait to assign engines until the primary
request was ready to start and then attempt to assign it to a different
engine than the primary.  There is an IGT test which exercises this by
submitting a primary batch to a specific VCS and then using FENCE_SUBMIT
to submit a secondary which can run on any VCS and have i915 figure out
which VCS to run it on such that they can run in parallel.

However, this functionality has never been used in the real world.  The
media driver (the only user of FENCE_SUBMIT) always picks exactly two
physical engines to bond and never asks us to pick which to use.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c  |  2 +-
 drivers/gpu/drm/i915/gt/intel_engine_types.h    |  7 -------
 .../drm/i915/gt/intel_execlists_submission.c    | 17 -----------------
 3 files changed, 1 insertion(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index d640bba6ad9ab..efb2fa3522a42 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -3474,7 +3474,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 		if (args->flags & I915_EXEC_FENCE_SUBMIT)
 			err = i915_request_await_execution(eb.request,
 							   in_fence,
-							   eb.engine->bond_execute);
+							   NULL);
 		else
 			err = i915_request_await_dma_fence(eb.request,
 							   in_fence);
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
index 883bafc449024..68cfe5080325c 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
@@ -446,13 +446,6 @@ struct intel_engine_cs {
 	 */
 	void		(*submit_request)(struct i915_request *rq);
 
-	/*
-	 * Called on signaling of a SUBMIT_FENCE, passing along the signaling
-	 * request down to the bonded pairs.
-	 */
-	void            (*bond_execute)(struct i915_request *rq,
-					struct dma_fence *signal);
-
 	/*
 	 * Call when the priority on a request has changed and it and its
 	 * dependencies may need rescheduling. Note the request itself may
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index 14378b28169b7..635d6d2494d26 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -3547,22 +3547,6 @@ static void virtual_submit_request(struct i915_request *rq)
 	spin_unlock_irqrestore(&ve->base.active.lock, flags);
 }
 
-static void
-virtual_bond_execute(struct i915_request *rq, struct dma_fence *signal)
-{
-	intel_engine_mask_t allowed, exec;
-
-	allowed = ~to_request(signal)->engine->mask;
-
-	/* Restrict the bonded request to run on only the available engines */
-	exec = READ_ONCE(rq->execution_mask);
-	while (!try_cmpxchg(&rq->execution_mask, &exec, exec & allowed))
-		;
-
-	/* Prevent the master from being re-run on the bonded engines */
-	to_request(signal)->execution_mask &= ~allowed;
-}
-
 struct intel_context *
 intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 			       unsigned int count)
@@ -3616,7 +3600,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
 
 	ve->base.schedule = i915_schedule;
 	ve->base.submit_request = virtual_submit_request;
-	ve->base.bond_execute = virtual_bond_execute;
 
 	INIT_LIST_HEAD(virtual_queue(ve));
 	ve->base.execlists.queue_priority_hint = INT_MIN;
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 11/27] drm/i915/request: Remove the hook from await_execution
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

This was only ever used for FENCE_SUBMIT automatic engine selection
which was removed in the previous commit.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |  3 +-
 drivers/gpu/drm/i915/i915_request.c           | 42 ++++---------------
 drivers/gpu/drm/i915/i915_request.h           |  4 +-
 3 files changed, 9 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index efb2fa3522a42..7024adcd5cf15 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -3473,8 +3473,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 	if (in_fence) {
 		if (args->flags & I915_EXEC_FENCE_SUBMIT)
 			err = i915_request_await_execution(eb.request,
-							   in_fence,
-							   NULL);
+							   in_fence);
 		else
 			err = i915_request_await_dma_fence(eb.request,
 							   in_fence);
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index bec9c3652188b..7e00218b8c105 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -49,7 +49,6 @@
 struct execute_cb {
 	struct irq_work work;
 	struct i915_sw_fence *fence;
-	void (*hook)(struct i915_request *rq, struct dma_fence *signal);
 	struct i915_request *signal;
 };
 
@@ -180,17 +179,6 @@ static void irq_execute_cb(struct irq_work *wrk)
 	kmem_cache_free(global.slab_execute_cbs, cb);
 }
 
-static void irq_execute_cb_hook(struct irq_work *wrk)
-{
-	struct execute_cb *cb = container_of(wrk, typeof(*cb), work);
-
-	cb->hook(container_of(cb->fence, struct i915_request, submit),
-		 &cb->signal->fence);
-	i915_request_put(cb->signal);
-
-	irq_execute_cb(wrk);
-}
-
 static __always_inline void
 __notify_execute_cb(struct i915_request *rq, bool (*fn)(struct irq_work *wrk))
 {
@@ -517,17 +505,12 @@ static bool __request_in_flight(const struct i915_request *signal)
 static int
 __await_execution(struct i915_request *rq,
 		  struct i915_request *signal,
-		  void (*hook)(struct i915_request *rq,
-			       struct dma_fence *signal),
 		  gfp_t gfp)
 {
 	struct execute_cb *cb;
 
-	if (i915_request_is_active(signal)) {
-		if (hook)
-			hook(rq, &signal->fence);
+	if (i915_request_is_active(signal))
 		return 0;
-	}
 
 	cb = kmem_cache_alloc(global.slab_execute_cbs, gfp);
 	if (!cb)
@@ -537,12 +520,6 @@ __await_execution(struct i915_request *rq,
 	i915_sw_fence_await(cb->fence);
 	init_irq_work(&cb->work, irq_execute_cb);
 
-	if (hook) {
-		cb->hook = hook;
-		cb->signal = i915_request_get(signal);
-		cb->work.func = irq_execute_cb_hook;
-	}
-
 	/*
 	 * Register the callback first, then see if the signaler is already
 	 * active. This ensures that if we race with the
@@ -1253,7 +1230,7 @@ emit_semaphore_wait(struct i915_request *to,
 		goto await_fence;
 
 	/* Only submit our spinner after the signaler is running! */
-	if (__await_execution(to, from, NULL, gfp))
+	if (__await_execution(to, from, gfp))
 		goto await_fence;
 
 	if (__emit_semaphore_wait(to, from, from->fence.seqno))
@@ -1284,16 +1261,14 @@ static int intel_timeline_sync_set_start(struct intel_timeline *tl,
 
 static int
 __i915_request_await_execution(struct i915_request *to,
-			       struct i915_request *from,
-			       void (*hook)(struct i915_request *rq,
-					    struct dma_fence *signal))
+			       struct i915_request *from)
 {
 	int err;
 
 	GEM_BUG_ON(intel_context_is_barrier(from->context));
 
 	/* Submit both requests at the same time */
-	err = __await_execution(to, from, hook, I915_FENCE_GFP);
+	err = __await_execution(to, from, I915_FENCE_GFP);
 	if (err)
 		return err;
 
@@ -1406,9 +1381,7 @@ i915_request_await_external(struct i915_request *rq, struct dma_fence *fence)
 
 int
 i915_request_await_execution(struct i915_request *rq,
-			     struct dma_fence *fence,
-			     void (*hook)(struct i915_request *rq,
-					  struct dma_fence *signal))
+			     struct dma_fence *fence)
 {
 	struct dma_fence **child = &fence;
 	unsigned int nchild = 1;
@@ -1441,8 +1414,7 @@ i915_request_await_execution(struct i915_request *rq,
 
 		if (dma_fence_is_i915(fence))
 			ret = __i915_request_await_execution(rq,
-							     to_request(fence),
-							     hook);
+							     to_request(fence));
 		else
 			ret = i915_request_await_external(rq, fence);
 		if (ret < 0)
@@ -1468,7 +1440,7 @@ await_request_submit(struct i915_request *to, struct i915_request *from)
 							&from->submit,
 							I915_FENCE_GFP);
 	else
-		return __i915_request_await_execution(to, from, NULL);
+		return __i915_request_await_execution(to, from);
 }
 
 static int
diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h
index 270f6cd37650c..63b087a7f5707 100644
--- a/drivers/gpu/drm/i915/i915_request.h
+++ b/drivers/gpu/drm/i915/i915_request.h
@@ -352,9 +352,7 @@ int i915_request_await_object(struct i915_request *to,
 int i915_request_await_dma_fence(struct i915_request *rq,
 				 struct dma_fence *fence);
 int i915_request_await_execution(struct i915_request *rq,
-				 struct dma_fence *fence,
-				 void (*hook)(struct i915_request *rq,
-					      struct dma_fence *signal));
+				 struct dma_fence *fence);
 
 void i915_request_add(struct i915_request *rq);
 
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 11/27] drm/i915/request: Remove the hook from await_execution
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

This was only ever used for FENCE_SUBMIT automatic engine selection
which was removed in the previous commit.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |  3 +-
 drivers/gpu/drm/i915/i915_request.c           | 42 ++++---------------
 drivers/gpu/drm/i915/i915_request.h           |  4 +-
 3 files changed, 9 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index efb2fa3522a42..7024adcd5cf15 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -3473,8 +3473,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 	if (in_fence) {
 		if (args->flags & I915_EXEC_FENCE_SUBMIT)
 			err = i915_request_await_execution(eb.request,
-							   in_fence,
-							   NULL);
+							   in_fence);
 		else
 			err = i915_request_await_dma_fence(eb.request,
 							   in_fence);
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index bec9c3652188b..7e00218b8c105 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -49,7 +49,6 @@
 struct execute_cb {
 	struct irq_work work;
 	struct i915_sw_fence *fence;
-	void (*hook)(struct i915_request *rq, struct dma_fence *signal);
 	struct i915_request *signal;
 };
 
@@ -180,17 +179,6 @@ static void irq_execute_cb(struct irq_work *wrk)
 	kmem_cache_free(global.slab_execute_cbs, cb);
 }
 
-static void irq_execute_cb_hook(struct irq_work *wrk)
-{
-	struct execute_cb *cb = container_of(wrk, typeof(*cb), work);
-
-	cb->hook(container_of(cb->fence, struct i915_request, submit),
-		 &cb->signal->fence);
-	i915_request_put(cb->signal);
-
-	irq_execute_cb(wrk);
-}
-
 static __always_inline void
 __notify_execute_cb(struct i915_request *rq, bool (*fn)(struct irq_work *wrk))
 {
@@ -517,17 +505,12 @@ static bool __request_in_flight(const struct i915_request *signal)
 static int
 __await_execution(struct i915_request *rq,
 		  struct i915_request *signal,
-		  void (*hook)(struct i915_request *rq,
-			       struct dma_fence *signal),
 		  gfp_t gfp)
 {
 	struct execute_cb *cb;
 
-	if (i915_request_is_active(signal)) {
-		if (hook)
-			hook(rq, &signal->fence);
+	if (i915_request_is_active(signal))
 		return 0;
-	}
 
 	cb = kmem_cache_alloc(global.slab_execute_cbs, gfp);
 	if (!cb)
@@ -537,12 +520,6 @@ __await_execution(struct i915_request *rq,
 	i915_sw_fence_await(cb->fence);
 	init_irq_work(&cb->work, irq_execute_cb);
 
-	if (hook) {
-		cb->hook = hook;
-		cb->signal = i915_request_get(signal);
-		cb->work.func = irq_execute_cb_hook;
-	}
-
 	/*
 	 * Register the callback first, then see if the signaler is already
 	 * active. This ensures that if we race with the
@@ -1253,7 +1230,7 @@ emit_semaphore_wait(struct i915_request *to,
 		goto await_fence;
 
 	/* Only submit our spinner after the signaler is running! */
-	if (__await_execution(to, from, NULL, gfp))
+	if (__await_execution(to, from, gfp))
 		goto await_fence;
 
 	if (__emit_semaphore_wait(to, from, from->fence.seqno))
@@ -1284,16 +1261,14 @@ static int intel_timeline_sync_set_start(struct intel_timeline *tl,
 
 static int
 __i915_request_await_execution(struct i915_request *to,
-			       struct i915_request *from,
-			       void (*hook)(struct i915_request *rq,
-					    struct dma_fence *signal))
+			       struct i915_request *from)
 {
 	int err;
 
 	GEM_BUG_ON(intel_context_is_barrier(from->context));
 
 	/* Submit both requests at the same time */
-	err = __await_execution(to, from, hook, I915_FENCE_GFP);
+	err = __await_execution(to, from, I915_FENCE_GFP);
 	if (err)
 		return err;
 
@@ -1406,9 +1381,7 @@ i915_request_await_external(struct i915_request *rq, struct dma_fence *fence)
 
 int
 i915_request_await_execution(struct i915_request *rq,
-			     struct dma_fence *fence,
-			     void (*hook)(struct i915_request *rq,
-					  struct dma_fence *signal))
+			     struct dma_fence *fence)
 {
 	struct dma_fence **child = &fence;
 	unsigned int nchild = 1;
@@ -1441,8 +1414,7 @@ i915_request_await_execution(struct i915_request *rq,
 
 		if (dma_fence_is_i915(fence))
 			ret = __i915_request_await_execution(rq,
-							     to_request(fence),
-							     hook);
+							     to_request(fence));
 		else
 			ret = i915_request_await_external(rq, fence);
 		if (ret < 0)
@@ -1468,7 +1440,7 @@ await_request_submit(struct i915_request *to, struct i915_request *from)
 							&from->submit,
 							I915_FENCE_GFP);
 	else
-		return __i915_request_await_execution(to, from, NULL);
+		return __i915_request_await_execution(to, from);
 }
 
 static int
diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h
index 270f6cd37650c..63b087a7f5707 100644
--- a/drivers/gpu/drm/i915/i915_request.h
+++ b/drivers/gpu/drm/i915/i915_request.h
@@ -352,9 +352,7 @@ int i915_request_await_object(struct i915_request *to,
 int i915_request_await_dma_fence(struct i915_request *rq,
 				 struct dma_fence *fence);
 int i915_request_await_execution(struct i915_request *rq,
-				 struct dma_fence *fence,
-				 void (*hook)(struct i915_request *rq,
-					      struct dma_fence *signal));
+				 struct dma_fence *fence);
 
 void i915_request_add(struct i915_request *rq);
 
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 12/27] drm/i915/gem: Disallow creating contexts with too many engines
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter, Jason Ekstrand

There's no sense in allowing userspace to create more engines than it
can possibly access via execbuf.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index be42dc918ef6f..8e254d83d65f2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1640,11 +1640,11 @@ set_engines(struct i915_gem_context *ctx,
 		return -EINVAL;
 	}
 
-	/*
-	 * Note that I915_EXEC_RING_MASK limits execbuf to only using the
-	 * first 64 engines defined here.
-	 */
 	num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
+	/* RING_MASK has no shift so we can use it directly here */
+	if (num_engines > I915_EXEC_RING_MASK + 1)
+		return -EINVAL;
+
 	set.engines = alloc_engines(num_engines);
 	if (!set.engines)
 		return -ENOMEM;
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 12/27] drm/i915/gem: Disallow creating contexts with too many engines
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter

There's no sense in allowing userspace to create more engines than it
can possibly access via execbuf.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index be42dc918ef6f..8e254d83d65f2 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1640,11 +1640,11 @@ set_engines(struct i915_gem_context *ctx,
 		return -EINVAL;
 	}
 
-	/*
-	 * Note that I915_EXEC_RING_MASK limits execbuf to only using the
-	 * first 64 engines defined here.
-	 */
 	num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
+	/* RING_MASK has no shift so we can use it directly here */
+	if (num_engines > I915_EXEC_RING_MASK + 1)
+		return -EINVAL;
+
 	set.engines = alloc_engines(num_engines);
 	if (!set.engines)
 		return -ENOMEM;
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 13/27] drm/i915: Stop manually RCU banging in reset_stats_ioctl (v2)
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter, Jason Ekstrand

As far as I can tell, the only real reason for this is to avoid taking a
reference to the i915_gem_context.  The cost of those two atomics
probably pales in comparison to the cost of the ioctl itself so we're
really not buying ourselves anything here.  We're about to make context
lookup a tiny bit more complicated, so let's get rid of the one hand-
rolled case.

Some usermode drivers such as our Vulkan driver call GET_RESET_STATS on
every execbuf so the perf here could theoretically be an issue.  If this
ever does become a performance issue for any such userspace drivers,
they can use set CONTEXT_PARAM_RECOVERABLE to false and look for -EIO
coming from execbuf to check for hangs instead.

v2 (Daniel Vetter):
 - Add a comment in the commit message about recoverable contexts

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 13 ++++---------
 drivers/gpu/drm/i915/i915_drv.h             |  8 +-------
 2 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 8e254d83d65f2..c073d5939482b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -2091,16 +2091,13 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
 	struct drm_i915_private *i915 = to_i915(dev);
 	struct drm_i915_reset_stats *args = data;
 	struct i915_gem_context *ctx;
-	int ret;
 
 	if (args->flags || args->pad)
 		return -EINVAL;
 
-	ret = -ENOENT;
-	rcu_read_lock();
-	ctx = __i915_gem_context_lookup_rcu(file->driver_priv, args->ctx_id);
+	ctx = i915_gem_context_lookup(file->driver_priv, args->ctx_id);
 	if (!ctx)
-		goto out;
+		return -ENOENT;
 
 	/*
 	 * We opt for unserialised reads here. This may result in tearing
@@ -2117,10 +2114,8 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
 	args->batch_active = atomic_read(&ctx->guilty_count);
 	args->batch_pending = atomic_read(&ctx->active_count);
 
-	ret = 0;
-out:
-	rcu_read_unlock();
-	return ret;
+	i915_gem_context_put(ctx);
+	return 0;
 }
 
 /* GEM context-engines iterator: for_each_gem_engine() */
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 0b44333eb7033..8571c5c1509a7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1840,19 +1840,13 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
 
 struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags);
 
-static inline struct i915_gem_context *
-__i915_gem_context_lookup_rcu(struct drm_i915_file_private *file_priv, u32 id)
-{
-	return xa_load(&file_priv->context_xa, id);
-}
-
 static inline struct i915_gem_context *
 i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
 {
 	struct i915_gem_context *ctx;
 
 	rcu_read_lock();
-	ctx = __i915_gem_context_lookup_rcu(file_priv, id);
+	ctx = xa_load(&file_priv->context_xa, id);
 	if (ctx && !kref_get_unless_zero(&ctx->ref))
 		ctx = NULL;
 	rcu_read_unlock();
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 13/27] drm/i915: Stop manually RCU banging in reset_stats_ioctl (v2)
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter

As far as I can tell, the only real reason for this is to avoid taking a
reference to the i915_gem_context.  The cost of those two atomics
probably pales in comparison to the cost of the ioctl itself so we're
really not buying ourselves anything here.  We're about to make context
lookup a tiny bit more complicated, so let's get rid of the one hand-
rolled case.

Some usermode drivers such as our Vulkan driver call GET_RESET_STATS on
every execbuf so the perf here could theoretically be an issue.  If this
ever does become a performance issue for any such userspace drivers,
they can use set CONTEXT_PARAM_RECOVERABLE to false and look for -EIO
coming from execbuf to check for hangs instead.

v2 (Daniel Vetter):
 - Add a comment in the commit message about recoverable contexts

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 13 ++++---------
 drivers/gpu/drm/i915/i915_drv.h             |  8 +-------
 2 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 8e254d83d65f2..c073d5939482b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -2091,16 +2091,13 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
 	struct drm_i915_private *i915 = to_i915(dev);
 	struct drm_i915_reset_stats *args = data;
 	struct i915_gem_context *ctx;
-	int ret;
 
 	if (args->flags || args->pad)
 		return -EINVAL;
 
-	ret = -ENOENT;
-	rcu_read_lock();
-	ctx = __i915_gem_context_lookup_rcu(file->driver_priv, args->ctx_id);
+	ctx = i915_gem_context_lookup(file->driver_priv, args->ctx_id);
 	if (!ctx)
-		goto out;
+		return -ENOENT;
 
 	/*
 	 * We opt for unserialised reads here. This may result in tearing
@@ -2117,10 +2114,8 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
 	args->batch_active = atomic_read(&ctx->guilty_count);
 	args->batch_pending = atomic_read(&ctx->active_count);
 
-	ret = 0;
-out:
-	rcu_read_unlock();
-	return ret;
+	i915_gem_context_put(ctx);
+	return 0;
 }
 
 /* GEM context-engines iterator: for_each_gem_engine() */
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 0b44333eb7033..8571c5c1509a7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1840,19 +1840,13 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
 
 struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags);
 
-static inline struct i915_gem_context *
-__i915_gem_context_lookup_rcu(struct drm_i915_file_private *file_priv, u32 id)
-{
-	return xa_load(&file_priv->context_xa, id);
-}
-
 static inline struct i915_gem_context *
 i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
 {
 	struct i915_gem_context *ctx;
 
 	rcu_read_lock();
-	ctx = __i915_gem_context_lookup_rcu(file_priv, id);
+	ctx = xa_load(&file_priv->context_xa, id);
 	if (ctx && !kref_get_unless_zero(&ctx->ref))
 		ctx = NULL;
 	rcu_read_unlock();
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 14/27] drm/i915/gem: Add a separate validate_priority helper
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter, Jason Ekstrand

With the proto-context stuff added later in this series, we end up
having to duplicate set_priority.  This lets us avoid duplicating the
validation logic.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 42 +++++++++++++--------
 1 file changed, 27 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index c073d5939482b..4835991898ac9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -169,6 +169,28 @@ lookup_user_engine(struct i915_gem_context *ctx,
 	return i915_gem_context_get_engine(ctx, idx);
 }
 
+static int validate_priority(struct drm_i915_private *i915,
+			     const struct drm_i915_gem_context_param *args)
+{
+	s64 priority = args->value;
+
+	if (args->size)
+		return -EINVAL;
+
+	if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PRIORITY))
+		return -ENODEV;
+
+	if (priority > I915_CONTEXT_MAX_USER_PRIORITY ||
+	    priority < I915_CONTEXT_MIN_USER_PRIORITY)
+		return -EINVAL;
+
+	if (priority > I915_CONTEXT_DEFAULT_PRIORITY &&
+	    !capable(CAP_SYS_NICE))
+		return -EPERM;
+
+	return 0;
+}
+
 static struct i915_address_space *
 context_get_vm_rcu(struct i915_gem_context *ctx)
 {
@@ -1745,23 +1767,13 @@ static void __apply_priority(struct intel_context *ce, void *arg)
 static int set_priority(struct i915_gem_context *ctx,
 			const struct drm_i915_gem_context_param *args)
 {
-	s64 priority = args->value;
-
-	if (args->size)
-		return -EINVAL;
-
-	if (!(ctx->i915->caps.scheduler & I915_SCHEDULER_CAP_PRIORITY))
-		return -ENODEV;
-
-	if (priority > I915_CONTEXT_MAX_USER_PRIORITY ||
-	    priority < I915_CONTEXT_MIN_USER_PRIORITY)
-		return -EINVAL;
+	int err;
 
-	if (priority > I915_CONTEXT_DEFAULT_PRIORITY &&
-	    !capable(CAP_SYS_NICE))
-		return -EPERM;
+	err = validate_priority(ctx->i915, args);
+	if (err)
+		return err;
 
-	ctx->sched.priority = priority;
+	ctx->sched.priority = args->value;
 	context_apply_all(ctx, __apply_priority, ctx);
 
 	return 0;
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 14/27] drm/i915/gem: Add a separate validate_priority helper
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter

With the proto-context stuff added later in this series, we end up
having to duplicate set_priority.  This lets us avoid duplicating the
validation logic.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 42 +++++++++++++--------
 1 file changed, 27 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index c073d5939482b..4835991898ac9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -169,6 +169,28 @@ lookup_user_engine(struct i915_gem_context *ctx,
 	return i915_gem_context_get_engine(ctx, idx);
 }
 
+static int validate_priority(struct drm_i915_private *i915,
+			     const struct drm_i915_gem_context_param *args)
+{
+	s64 priority = args->value;
+
+	if (args->size)
+		return -EINVAL;
+
+	if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PRIORITY))
+		return -ENODEV;
+
+	if (priority > I915_CONTEXT_MAX_USER_PRIORITY ||
+	    priority < I915_CONTEXT_MIN_USER_PRIORITY)
+		return -EINVAL;
+
+	if (priority > I915_CONTEXT_DEFAULT_PRIORITY &&
+	    !capable(CAP_SYS_NICE))
+		return -EPERM;
+
+	return 0;
+}
+
 static struct i915_address_space *
 context_get_vm_rcu(struct i915_gem_context *ctx)
 {
@@ -1745,23 +1767,13 @@ static void __apply_priority(struct intel_context *ce, void *arg)
 static int set_priority(struct i915_gem_context *ctx,
 			const struct drm_i915_gem_context_param *args)
 {
-	s64 priority = args->value;
-
-	if (args->size)
-		return -EINVAL;
-
-	if (!(ctx->i915->caps.scheduler & I915_SCHEDULER_CAP_PRIORITY))
-		return -ENODEV;
-
-	if (priority > I915_CONTEXT_MAX_USER_PRIORITY ||
-	    priority < I915_CONTEXT_MIN_USER_PRIORITY)
-		return -EINVAL;
+	int err;
 
-	if (priority > I915_CONTEXT_DEFAULT_PRIORITY &&
-	    !capable(CAP_SYS_NICE))
-		return -EPERM;
+	err = validate_priority(ctx->i915, args);
+	if (err)
+		return err;
 
-	ctx->sched.priority = priority;
+	ctx->sched.priority = args->value;
 	context_apply_all(ctx, __apply_priority, ctx);
 
 	return 0;
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 15/27] drm/i915: Add gem/i915_gem_context.h to the docs
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

In order to prevent kernel doc warnings, also fill out docs for any
missing fields and fix those that forgot the "@".

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 Documentation/gpu/i915.rst                    |  2 +
 .../gpu/drm/i915/gem/i915_gem_context_types.h | 43 ++++++++++++++++---
 2 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst
index 486c720f38907..0529e5183982e 100644
--- a/Documentation/gpu/i915.rst
+++ b/Documentation/gpu/i915.rst
@@ -422,6 +422,8 @@ Batchbuffer Parsing
 User Batchbuffer Execution
 --------------------------
 
+.. kernel-doc:: drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+
 .. kernel-doc:: drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
    :doc: User command execution
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index df76767f0c41b..5f0673a2129f9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -30,19 +30,39 @@ struct i915_address_space;
 struct intel_timeline;
 struct intel_ring;
 
+/**
+ * struct i915_gem_engines - A set of engines
+ */
 struct i915_gem_engines {
 	union {
+		/** @link: Link in i915_gem_context::stale::engines */
 		struct list_head link;
+
+		/** @rcu: RCU to use when freeing */
 		struct rcu_head rcu;
 	};
+
+	/** @fence: Fence used for delayed destruction of engines */
 	struct i915_sw_fence fence;
+
+	/** @ctx: i915_gem_context backpointer */
 	struct i915_gem_context *ctx;
+
+	/** @num_engines: Number of engines in this set */
 	unsigned int num_engines;
+
+	/** @engines: Array of engines */
 	struct intel_context *engines[];
 };
 
+/**
+ * struct i915_gem_engines_iter - Iterator for an i915_gem_engines set
+ */
 struct i915_gem_engines_iter {
+	/** @idx: Index into i915_gem_engines::engines */
 	unsigned int idx;
+
+	/** @engines: Engine set being iterated */
 	const struct i915_gem_engines *engines;
 };
 
@@ -53,10 +73,10 @@ struct i915_gem_engines_iter {
  * logical hardware state for a particular client.
  */
 struct i915_gem_context {
-	/** i915: i915 device backpointer */
+	/** @i915: i915 device backpointer */
 	struct drm_i915_private *i915;
 
-	/** file_priv: owning file descriptor */
+	/** @file_priv: owning file descriptor */
 	struct drm_i915_file_private *file_priv;
 
 	/**
@@ -81,7 +101,9 @@ struct i915_gem_context {
 	 * CONTEXT_USER_ENGINES flag is set).
 	 */
 	struct i915_gem_engines __rcu *engines;
-	struct mutex engines_mutex; /* guards writes to engines */
+
+	/** @engines_mutex: guards writes to engines */
+	struct mutex engines_mutex;
 
 	/**
 	 * @syncobj: Shared timeline syncobj
@@ -118,7 +140,7 @@ struct i915_gem_context {
 	 */
 	struct pid *pid;
 
-	/** link: place with &drm_i915_private.context_list */
+	/** @link: place with &drm_i915_private.context_list */
 	struct list_head link;
 
 	/**
@@ -153,11 +175,13 @@ struct i915_gem_context {
 #define CONTEXT_CLOSED			0
 #define CONTEXT_USER_ENGINES		1
 
+	/** @mutex: guards everything that isn't engines or handles_vma */
 	struct mutex mutex;
 
+	/** @sched: scheduler parameters */
 	struct i915_sched_attr sched;
 
-	/** guilty_count: How many times this context has caused a GPU hang. */
+	/** @guilty_count: How many times this context has caused a GPU hang. */
 	atomic_t guilty_count;
 	/**
 	 * @active_count: How many times this context was active during a GPU
@@ -171,15 +195,17 @@ struct i915_gem_context {
 	unsigned long hang_timestamp[2];
 #define CONTEXT_FAST_HANG_JIFFIES (120 * HZ) /* 3 hangs within 120s? Banned! */
 
-	/** remap_slice: Bitmask of cache lines that need remapping */
+	/** @remap_slice: Bitmask of cache lines that need remapping */
 	u8 remap_slice;
 
 	/**
-	 * handles_vma: rbtree to look up our context specific obj/vma for
+	 * @handles_vma: rbtree to look up our context specific obj/vma for
 	 * the user handle. (user handles are per fd, but the binding is
 	 * per vm, which may be one per context or shared with the global GTT)
 	 */
 	struct radix_tree_root handles_vma;
+
+	/** @lut_mutex: Locks handles_vma */
 	struct mutex lut_mutex;
 
 	/**
@@ -191,8 +217,11 @@ struct i915_gem_context {
 	 */
 	char name[TASK_COMM_LEN + 8];
 
+	/** @stale: tracks stale engines to be destroyed */
 	struct {
+		/** @lock: guards engines */
 		spinlock_t lock;
+		/** @engines: list of stale engines */
 		struct list_head engines;
 	} stale;
 };
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 15/27] drm/i915: Add gem/i915_gem_context.h to the docs
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

In order to prevent kernel doc warnings, also fill out docs for any
missing fields and fix those that forgot the "@".

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 Documentation/gpu/i915.rst                    |  2 +
 .../gpu/drm/i915/gem/i915_gem_context_types.h | 43 ++++++++++++++++---
 2 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst
index 486c720f38907..0529e5183982e 100644
--- a/Documentation/gpu/i915.rst
+++ b/Documentation/gpu/i915.rst
@@ -422,6 +422,8 @@ Batchbuffer Parsing
 User Batchbuffer Execution
 --------------------------
 
+.. kernel-doc:: drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+
 .. kernel-doc:: drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
    :doc: User command execution
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index df76767f0c41b..5f0673a2129f9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -30,19 +30,39 @@ struct i915_address_space;
 struct intel_timeline;
 struct intel_ring;
 
+/**
+ * struct i915_gem_engines - A set of engines
+ */
 struct i915_gem_engines {
 	union {
+		/** @link: Link in i915_gem_context::stale::engines */
 		struct list_head link;
+
+		/** @rcu: RCU to use when freeing */
 		struct rcu_head rcu;
 	};
+
+	/** @fence: Fence used for delayed destruction of engines */
 	struct i915_sw_fence fence;
+
+	/** @ctx: i915_gem_context backpointer */
 	struct i915_gem_context *ctx;
+
+	/** @num_engines: Number of engines in this set */
 	unsigned int num_engines;
+
+	/** @engines: Array of engines */
 	struct intel_context *engines[];
 };
 
+/**
+ * struct i915_gem_engines_iter - Iterator for an i915_gem_engines set
+ */
 struct i915_gem_engines_iter {
+	/** @idx: Index into i915_gem_engines::engines */
 	unsigned int idx;
+
+	/** @engines: Engine set being iterated */
 	const struct i915_gem_engines *engines;
 };
 
@@ -53,10 +73,10 @@ struct i915_gem_engines_iter {
  * logical hardware state for a particular client.
  */
 struct i915_gem_context {
-	/** i915: i915 device backpointer */
+	/** @i915: i915 device backpointer */
 	struct drm_i915_private *i915;
 
-	/** file_priv: owning file descriptor */
+	/** @file_priv: owning file descriptor */
 	struct drm_i915_file_private *file_priv;
 
 	/**
@@ -81,7 +101,9 @@ struct i915_gem_context {
 	 * CONTEXT_USER_ENGINES flag is set).
 	 */
 	struct i915_gem_engines __rcu *engines;
-	struct mutex engines_mutex; /* guards writes to engines */
+
+	/** @engines_mutex: guards writes to engines */
+	struct mutex engines_mutex;
 
 	/**
 	 * @syncobj: Shared timeline syncobj
@@ -118,7 +140,7 @@ struct i915_gem_context {
 	 */
 	struct pid *pid;
 
-	/** link: place with &drm_i915_private.context_list */
+	/** @link: place with &drm_i915_private.context_list */
 	struct list_head link;
 
 	/**
@@ -153,11 +175,13 @@ struct i915_gem_context {
 #define CONTEXT_CLOSED			0
 #define CONTEXT_USER_ENGINES		1
 
+	/** @mutex: guards everything that isn't engines or handles_vma */
 	struct mutex mutex;
 
+	/** @sched: scheduler parameters */
 	struct i915_sched_attr sched;
 
-	/** guilty_count: How many times this context has caused a GPU hang. */
+	/** @guilty_count: How many times this context has caused a GPU hang. */
 	atomic_t guilty_count;
 	/**
 	 * @active_count: How many times this context was active during a GPU
@@ -171,15 +195,17 @@ struct i915_gem_context {
 	unsigned long hang_timestamp[2];
 #define CONTEXT_FAST_HANG_JIFFIES (120 * HZ) /* 3 hangs within 120s? Banned! */
 
-	/** remap_slice: Bitmask of cache lines that need remapping */
+	/** @remap_slice: Bitmask of cache lines that need remapping */
 	u8 remap_slice;
 
 	/**
-	 * handles_vma: rbtree to look up our context specific obj/vma for
+	 * @handles_vma: rbtree to look up our context specific obj/vma for
 	 * the user handle. (user handles are per fd, but the binding is
 	 * per vm, which may be one per context or shared with the global GTT)
 	 */
 	struct radix_tree_root handles_vma;
+
+	/** @lut_mutex: Locks handles_vma */
 	struct mutex lut_mutex;
 
 	/**
@@ -191,8 +217,11 @@ struct i915_gem_context {
 	 */
 	char name[TASK_COMM_LEN + 8];
 
+	/** @stale: tracks stale engines to be destroyed */
 	struct {
+		/** @lock: guards engines */
 		spinlock_t lock;
+		/** @engines: list of stale engines */
 		struct list_head engines;
 	} stale;
 };
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

The current context uAPI allows for two methods of setting context
parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
former is allowed to be called at any time while the later happens as
part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
settable via the other.  While some params are fairly simple and setting
them on a live context is harmless such the context priority, others are
far trickier such as the VM or the set of engines.  In order to swap out
the VM, for instance, we have to delay until all current in-flight work
is complete, swap in the new VM, and then continue.  This leads to a
plethora of potential race conditions we'd really rather avoid.

Unfortunately, both methods of setting the VM and engine set are in
active use today so we can't simply disallow setting the VM or engine
set vial SET_CONTEXT_PARAM.  In order to work around this wart, this
commit adds a proto-context struct which contains all the context create
parameters.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 145 ++++++++++++++----
 .../gpu/drm/i915/gem/i915_gem_context_types.h |  22 +++
 .../gpu/drm/i915/gem/selftests/mock_context.c |  16 +-
 3 files changed, 153 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 4835991898ac9..10bd1b6dd1774 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -191,6 +191,97 @@ static int validate_priority(struct drm_i915_private *i915,
 	return 0;
 }
 
+static void proto_context_close(struct i915_gem_proto_context *pc)
+{
+	if (pc->vm)
+		i915_vm_put(pc->vm);
+	kfree(pc);
+}
+
+static int proto_context_set_persistence(struct drm_i915_private *i915,
+					 struct i915_gem_proto_context *pc,
+					 bool persist)
+{
+	if (persist) {
+		/*
+		 * Only contexts that are short-lived [that will expire or be
+		 * reset] are allowed to survive past termination. We require
+		 * hangcheck to ensure that the persistent requests are healthy.
+		 */
+		if (!i915->params.enable_hangcheck)
+			return -EINVAL;
+
+		__set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
+	} else {
+		/* To cancel a context we use "preempt-to-idle" */
+		if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
+			return -ENODEV;
+
+		/*
+		 * If the cancel fails, we then need to reset, cleanly!
+		 *
+		 * If the per-engine reset fails, all hope is lost! We resort
+		 * to a full GPU reset in that unlikely case, but realistically
+		 * if the engine could not reset, the full reset does not fare
+		 * much better. The damage has been done.
+		 *
+		 * However, if we cannot reset an engine by itself, we cannot
+		 * cleanup a hanging persistent context without causing
+		 * colateral damage, and we should not pretend we can by
+		 * exposing the interface.
+		 */
+		if (!intel_has_reset_engine(&i915->gt))
+			return -ENODEV;
+
+		__clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
+	}
+
+	return 0;
+}
+
+static struct i915_gem_proto_context *
+proto_context_create(struct drm_i915_private *i915, unsigned int flags)
+{
+	struct i915_gem_proto_context *pc, *err;
+
+	pc = kzalloc(sizeof(*pc), GFP_KERNEL);
+	if (!pc)
+		return ERR_PTR(-ENOMEM);
+
+	if (HAS_FULL_PPGTT(i915)) {
+		struct i915_ppgtt *ppgtt;
+
+		ppgtt = i915_ppgtt_create(&i915->gt);
+		if (IS_ERR(ppgtt)) {
+			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
+				PTR_ERR(ppgtt));
+			err = ERR_CAST(ppgtt);
+			goto proto_close;
+		}
+		pc->vm = &ppgtt->vm;
+	}
+
+	pc->user_flags = 0;
+	__set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
+	__set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
+	proto_context_set_persistence(i915, pc, true);
+	pc->sched.priority = I915_PRIORITY_NORMAL;
+
+	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
+		if (!HAS_EXECLISTS(i915)) {
+			err = ERR_PTR(-EINVAL);
+			goto proto_close;
+		}
+		pc->single_timeline = true;
+	}
+
+	return pc;
+
+proto_close:
+	proto_context_close(pc);
+	return err;
+}
+
 static struct i915_address_space *
 context_get_vm_rcu(struct i915_gem_context *ctx)
 {
@@ -660,7 +751,8 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
 }
 
 static struct i915_gem_context *
-__create_context(struct drm_i915_private *i915)
+__create_context(struct drm_i915_private *i915,
+		 const struct i915_gem_proto_context *pc)
 {
 	struct i915_gem_context *ctx;
 	struct i915_gem_engines *e;
@@ -673,7 +765,7 @@ __create_context(struct drm_i915_private *i915)
 
 	kref_init(&ctx->ref);
 	ctx->i915 = i915;
-	ctx->sched.priority = I915_PRIORITY_NORMAL;
+	ctx->sched = pc->sched;
 	mutex_init(&ctx->mutex);
 	INIT_LIST_HEAD(&ctx->link);
 
@@ -696,9 +788,7 @@ __create_context(struct drm_i915_private *i915)
 	 * is no remap info, it will be a NOP. */
 	ctx->remap_slice = ALL_L3_SLICES(i915);
 
-	i915_gem_context_set_bannable(ctx);
-	i915_gem_context_set_recoverable(ctx);
-	__context_set_persistence(ctx, true /* cgroup hook? */);
+	ctx->user_flags = pc->user_flags;
 
 	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
 		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
@@ -786,38 +876,23 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
 }
 
 static struct i915_gem_context *
-i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
+i915_gem_create_context(struct drm_i915_private *i915,
+			const struct i915_gem_proto_context *pc)
 {
 	struct i915_gem_context *ctx;
 	int ret;
 
-	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
-	    !HAS_EXECLISTS(i915))
-		return ERR_PTR(-EINVAL);
-
-	ctx = __create_context(i915);
+	ctx = __create_context(i915, pc);
 	if (IS_ERR(ctx))
 		return ctx;
 
-	if (HAS_FULL_PPGTT(i915)) {
-		struct i915_ppgtt *ppgtt;
-
-		ppgtt = i915_ppgtt_create(&i915->gt);
-		if (IS_ERR(ppgtt)) {
-			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
-				PTR_ERR(ppgtt));
-			context_close(ctx);
-			return ERR_CAST(ppgtt);
-		}
-
+	if (pc->vm) {
 		mutex_lock(&ctx->mutex);
-		__assign_ppgtt(ctx, &ppgtt->vm);
+		__assign_ppgtt(ctx, pc->vm);
 		mutex_unlock(&ctx->mutex);
-
-		i915_vm_put(&ppgtt->vm);
 	}
 
-	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
+	if (pc->single_timeline) {
 		ret = drm_syncobj_create(&ctx->syncobj,
 					 DRM_SYNCOBJ_CREATE_SIGNALED,
 					 NULL);
@@ -883,6 +958,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
 			  struct drm_file *file)
 {
 	struct drm_i915_file_private *file_priv = file->driver_priv;
+	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
 	int err;
 	u32 id;
@@ -892,7 +968,14 @@ int i915_gem_context_open(struct drm_i915_private *i915,
 	/* 0 reserved for invalid/unassigned ppgtt */
 	xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
 
-	ctx = i915_gem_create_context(i915, 0);
+	pc = proto_context_create(i915, 0);
+	if (IS_ERR(pc)) {
+		err = PTR_ERR(pc);
+		goto err;
+	}
+
+	ctx = i915_gem_create_context(i915, pc);
+	proto_context_close(pc);
 	if (IS_ERR(ctx)) {
 		err = PTR_ERR(ctx);
 		goto err;
@@ -1885,6 +1968,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_i915_private *i915 = to_i915(dev);
 	struct drm_i915_gem_context_create_ext *args = data;
+	struct i915_gem_proto_context *pc;
 	struct create_ext ext_data;
 	int ret;
 	u32 id;
@@ -1907,7 +1991,12 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 		return -EIO;
 	}
 
-	ext_data.ctx = i915_gem_create_context(i915, args->flags);
+	pc = proto_context_create(i915, args->flags);
+	if (IS_ERR(pc))
+		return PTR_ERR(pc);
+
+	ext_data.ctx = i915_gem_create_context(i915, pc);
+	proto_context_close(pc);
 	if (IS_ERR(ext_data.ctx))
 		return PTR_ERR(ext_data.ctx);
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 5f0673a2129f9..0bf337b6d89ac 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -66,6 +66,28 @@ struct i915_gem_engines_iter {
 	const struct i915_gem_engines *engines;
 };
 
+/**
+ * struct i915_gem_proto_context - prototype context
+ *
+ * The struct i915_gem_proto_context represents the creation parameters for
+ * an i915_gem_context.  This is used to gather parameters provided either
+ * through creation flags or via SET_CONTEXT_PARAM so that, when we create
+ * the final i915_gem_context, those parameters can be immutable.
+ */
+struct i915_gem_proto_context {
+	/** @vm: See i915_gem_context::vm */
+	struct i915_address_space *vm;
+
+	/** @user_flags: See i915_gem_context::user_flags */
+	unsigned long user_flags;
+
+	/** @sched: See i915_gem_context::sched */
+	struct i915_sched_attr sched;
+
+	/** @single_timeline: See See i915_gem_context::syncobj */
+	bool single_timeline;
+};
+
 /**
  * struct i915_gem_context - client state
  *
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index 51b5a3421b400..e0f512ef7f3c6 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -80,11 +80,17 @@ void mock_init_contexts(struct drm_i915_private *i915)
 struct i915_gem_context *
 live_context(struct drm_i915_private *i915, struct file *file)
 {
+	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
 	int err;
 	u32 id;
 
-	ctx = i915_gem_create_context(i915, 0);
+	pc = proto_context_create(i915, 0);
+	if (IS_ERR(pc))
+		return ERR_CAST(pc);
+
+	ctx = i915_gem_create_context(i915, pc);
+	proto_context_close(pc);
 	if (IS_ERR(ctx))
 		return ctx;
 
@@ -142,8 +148,14 @@ struct i915_gem_context *
 kernel_context(struct drm_i915_private *i915)
 {
 	struct i915_gem_context *ctx;
+	struct i915_gem_proto_context *pc;
+
+	pc = proto_context_create(i915, 0);
+	if (IS_ERR(pc))
+		return ERR_CAST(pc);
 
-	ctx = i915_gem_create_context(i915, 0);
+	ctx = i915_gem_create_context(i915, pc);
+	proto_context_close(pc);
 	if (IS_ERR(ctx))
 		return ctx;
 
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

The current context uAPI allows for two methods of setting context
parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
former is allowed to be called at any time while the later happens as
part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
settable via the other.  While some params are fairly simple and setting
them on a live context is harmless such the context priority, others are
far trickier such as the VM or the set of engines.  In order to swap out
the VM, for instance, we have to delay until all current in-flight work
is complete, swap in the new VM, and then continue.  This leads to a
plethora of potential race conditions we'd really rather avoid.

Unfortunately, both methods of setting the VM and engine set are in
active use today so we can't simply disallow setting the VM or engine
set vial SET_CONTEXT_PARAM.  In order to work around this wart, this
commit adds a proto-context struct which contains all the context create
parameters.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 145 ++++++++++++++----
 .../gpu/drm/i915/gem/i915_gem_context_types.h |  22 +++
 .../gpu/drm/i915/gem/selftests/mock_context.c |  16 +-
 3 files changed, 153 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 4835991898ac9..10bd1b6dd1774 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -191,6 +191,97 @@ static int validate_priority(struct drm_i915_private *i915,
 	return 0;
 }
 
+static void proto_context_close(struct i915_gem_proto_context *pc)
+{
+	if (pc->vm)
+		i915_vm_put(pc->vm);
+	kfree(pc);
+}
+
+static int proto_context_set_persistence(struct drm_i915_private *i915,
+					 struct i915_gem_proto_context *pc,
+					 bool persist)
+{
+	if (persist) {
+		/*
+		 * Only contexts that are short-lived [that will expire or be
+		 * reset] are allowed to survive past termination. We require
+		 * hangcheck to ensure that the persistent requests are healthy.
+		 */
+		if (!i915->params.enable_hangcheck)
+			return -EINVAL;
+
+		__set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
+	} else {
+		/* To cancel a context we use "preempt-to-idle" */
+		if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
+			return -ENODEV;
+
+		/*
+		 * If the cancel fails, we then need to reset, cleanly!
+		 *
+		 * If the per-engine reset fails, all hope is lost! We resort
+		 * to a full GPU reset in that unlikely case, but realistically
+		 * if the engine could not reset, the full reset does not fare
+		 * much better. The damage has been done.
+		 *
+		 * However, if we cannot reset an engine by itself, we cannot
+		 * cleanup a hanging persistent context without causing
+		 * colateral damage, and we should not pretend we can by
+		 * exposing the interface.
+		 */
+		if (!intel_has_reset_engine(&i915->gt))
+			return -ENODEV;
+
+		__clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
+	}
+
+	return 0;
+}
+
+static struct i915_gem_proto_context *
+proto_context_create(struct drm_i915_private *i915, unsigned int flags)
+{
+	struct i915_gem_proto_context *pc, *err;
+
+	pc = kzalloc(sizeof(*pc), GFP_KERNEL);
+	if (!pc)
+		return ERR_PTR(-ENOMEM);
+
+	if (HAS_FULL_PPGTT(i915)) {
+		struct i915_ppgtt *ppgtt;
+
+		ppgtt = i915_ppgtt_create(&i915->gt);
+		if (IS_ERR(ppgtt)) {
+			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
+				PTR_ERR(ppgtt));
+			err = ERR_CAST(ppgtt);
+			goto proto_close;
+		}
+		pc->vm = &ppgtt->vm;
+	}
+
+	pc->user_flags = 0;
+	__set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
+	__set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
+	proto_context_set_persistence(i915, pc, true);
+	pc->sched.priority = I915_PRIORITY_NORMAL;
+
+	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
+		if (!HAS_EXECLISTS(i915)) {
+			err = ERR_PTR(-EINVAL);
+			goto proto_close;
+		}
+		pc->single_timeline = true;
+	}
+
+	return pc;
+
+proto_close:
+	proto_context_close(pc);
+	return err;
+}
+
 static struct i915_address_space *
 context_get_vm_rcu(struct i915_gem_context *ctx)
 {
@@ -660,7 +751,8 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
 }
 
 static struct i915_gem_context *
-__create_context(struct drm_i915_private *i915)
+__create_context(struct drm_i915_private *i915,
+		 const struct i915_gem_proto_context *pc)
 {
 	struct i915_gem_context *ctx;
 	struct i915_gem_engines *e;
@@ -673,7 +765,7 @@ __create_context(struct drm_i915_private *i915)
 
 	kref_init(&ctx->ref);
 	ctx->i915 = i915;
-	ctx->sched.priority = I915_PRIORITY_NORMAL;
+	ctx->sched = pc->sched;
 	mutex_init(&ctx->mutex);
 	INIT_LIST_HEAD(&ctx->link);
 
@@ -696,9 +788,7 @@ __create_context(struct drm_i915_private *i915)
 	 * is no remap info, it will be a NOP. */
 	ctx->remap_slice = ALL_L3_SLICES(i915);
 
-	i915_gem_context_set_bannable(ctx);
-	i915_gem_context_set_recoverable(ctx);
-	__context_set_persistence(ctx, true /* cgroup hook? */);
+	ctx->user_flags = pc->user_flags;
 
 	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
 		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
@@ -786,38 +876,23 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
 }
 
 static struct i915_gem_context *
-i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
+i915_gem_create_context(struct drm_i915_private *i915,
+			const struct i915_gem_proto_context *pc)
 {
 	struct i915_gem_context *ctx;
 	int ret;
 
-	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
-	    !HAS_EXECLISTS(i915))
-		return ERR_PTR(-EINVAL);
-
-	ctx = __create_context(i915);
+	ctx = __create_context(i915, pc);
 	if (IS_ERR(ctx))
 		return ctx;
 
-	if (HAS_FULL_PPGTT(i915)) {
-		struct i915_ppgtt *ppgtt;
-
-		ppgtt = i915_ppgtt_create(&i915->gt);
-		if (IS_ERR(ppgtt)) {
-			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
-				PTR_ERR(ppgtt));
-			context_close(ctx);
-			return ERR_CAST(ppgtt);
-		}
-
+	if (pc->vm) {
 		mutex_lock(&ctx->mutex);
-		__assign_ppgtt(ctx, &ppgtt->vm);
+		__assign_ppgtt(ctx, pc->vm);
 		mutex_unlock(&ctx->mutex);
-
-		i915_vm_put(&ppgtt->vm);
 	}
 
-	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
+	if (pc->single_timeline) {
 		ret = drm_syncobj_create(&ctx->syncobj,
 					 DRM_SYNCOBJ_CREATE_SIGNALED,
 					 NULL);
@@ -883,6 +958,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
 			  struct drm_file *file)
 {
 	struct drm_i915_file_private *file_priv = file->driver_priv;
+	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
 	int err;
 	u32 id;
@@ -892,7 +968,14 @@ int i915_gem_context_open(struct drm_i915_private *i915,
 	/* 0 reserved for invalid/unassigned ppgtt */
 	xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
 
-	ctx = i915_gem_create_context(i915, 0);
+	pc = proto_context_create(i915, 0);
+	if (IS_ERR(pc)) {
+		err = PTR_ERR(pc);
+		goto err;
+	}
+
+	ctx = i915_gem_create_context(i915, pc);
+	proto_context_close(pc);
 	if (IS_ERR(ctx)) {
 		err = PTR_ERR(ctx);
 		goto err;
@@ -1885,6 +1968,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_i915_private *i915 = to_i915(dev);
 	struct drm_i915_gem_context_create_ext *args = data;
+	struct i915_gem_proto_context *pc;
 	struct create_ext ext_data;
 	int ret;
 	u32 id;
@@ -1907,7 +1991,12 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 		return -EIO;
 	}
 
-	ext_data.ctx = i915_gem_create_context(i915, args->flags);
+	pc = proto_context_create(i915, args->flags);
+	if (IS_ERR(pc))
+		return PTR_ERR(pc);
+
+	ext_data.ctx = i915_gem_create_context(i915, pc);
+	proto_context_close(pc);
 	if (IS_ERR(ext_data.ctx))
 		return PTR_ERR(ext_data.ctx);
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 5f0673a2129f9..0bf337b6d89ac 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -66,6 +66,28 @@ struct i915_gem_engines_iter {
 	const struct i915_gem_engines *engines;
 };
 
+/**
+ * struct i915_gem_proto_context - prototype context
+ *
+ * The struct i915_gem_proto_context represents the creation parameters for
+ * an i915_gem_context.  This is used to gather parameters provided either
+ * through creation flags or via SET_CONTEXT_PARAM so that, when we create
+ * the final i915_gem_context, those parameters can be immutable.
+ */
+struct i915_gem_proto_context {
+	/** @vm: See i915_gem_context::vm */
+	struct i915_address_space *vm;
+
+	/** @user_flags: See i915_gem_context::user_flags */
+	unsigned long user_flags;
+
+	/** @sched: See i915_gem_context::sched */
+	struct i915_sched_attr sched;
+
+	/** @single_timeline: See See i915_gem_context::syncobj */
+	bool single_timeline;
+};
+
 /**
  * struct i915_gem_context - client state
  *
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index 51b5a3421b400..e0f512ef7f3c6 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -80,11 +80,17 @@ void mock_init_contexts(struct drm_i915_private *i915)
 struct i915_gem_context *
 live_context(struct drm_i915_private *i915, struct file *file)
 {
+	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
 	int err;
 	u32 id;
 
-	ctx = i915_gem_create_context(i915, 0);
+	pc = proto_context_create(i915, 0);
+	if (IS_ERR(pc))
+		return ERR_CAST(pc);
+
+	ctx = i915_gem_create_context(i915, pc);
+	proto_context_close(pc);
 	if (IS_ERR(ctx))
 		return ctx;
 
@@ -142,8 +148,14 @@ struct i915_gem_context *
 kernel_context(struct drm_i915_private *i915)
 {
 	struct i915_gem_context *ctx;
+	struct i915_gem_proto_context *pc;
+
+	pc = proto_context_create(i915, 0);
+	if (IS_ERR(pc))
+		return ERR_CAST(pc);
 
-	ctx = i915_gem_create_context(i915, 0);
+	ctx = i915_gem_create_context(i915, pc);
+	proto_context_close(pc);
 	if (IS_ERR(ctx))
 		return ctx;
 
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 17/27] drm/i915/gem: Rework error handling in default_engines
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

Since free_engines works for partially constructed engine sets, we can
use the usual goto pattern.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 10bd1b6dd1774..ce729e640bbf7 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -420,7 +420,7 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
 {
 	const struct intel_gt *gt = &ctx->i915->gt;
 	struct intel_engine_cs *engine;
-	struct i915_gem_engines *e;
+	struct i915_gem_engines *e, *err;
 	enum intel_engine_id id;
 
 	e = alloc_engines(I915_NUM_ENGINES);
@@ -438,18 +438,21 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
 
 		ce = intel_context_create(engine);
 		if (IS_ERR(ce)) {
-			__free_engines(e, e->num_engines + 1);
-			return ERR_CAST(ce);
+			err = ERR_CAST(ce);
+			goto free_engines;
 		}
 
 		intel_context_set_gem(ce, ctx);
 
 		e->engines[engine->legacy_idx] = ce;
-		e->num_engines = max(e->num_engines, engine->legacy_idx);
+		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
 	}
-	e->num_engines++;
 
 	return e;
+
+free_engines:
+	free_engines(e);
+	return err;
 }
 
 void i915_gem_context_release(struct kref *ref)
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 17/27] drm/i915/gem: Rework error handling in default_engines
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

Since free_engines works for partially constructed engine sets, we can
use the usual goto pattern.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 10bd1b6dd1774..ce729e640bbf7 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -420,7 +420,7 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
 {
 	const struct intel_gt *gt = &ctx->i915->gt;
 	struct intel_engine_cs *engine;
-	struct i915_gem_engines *e;
+	struct i915_gem_engines *e, *err;
 	enum intel_engine_id id;
 
 	e = alloc_engines(I915_NUM_ENGINES);
@@ -438,18 +438,21 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
 
 		ce = intel_context_create(engine);
 		if (IS_ERR(ce)) {
-			__free_engines(e, e->num_engines + 1);
-			return ERR_CAST(ce);
+			err = ERR_CAST(ce);
+			goto free_engines;
 		}
 
 		intel_context_set_gem(ce, ctx);
 
 		e->engines[engine->legacy_idx] = ce;
-		e->num_engines = max(e->num_engines, engine->legacy_idx);
+		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
 	}
-	e->num_engines++;
 
 	return e;
+
+free_engines:
+	free_engines(e);
+	return err;
 }
 
 void i915_gem_context_release(struct kref *ref)
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

For now this is a no-op because everyone passes in a null SSEU but it
lets us get some of the error handling and selftest refactoring plumbed
through.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 41 +++++++++++++++----
 .../gpu/drm/i915/gem/selftests/mock_context.c |  6 ++-
 2 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index ce729e640bbf7..6dd50d669c5b9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -320,9 +320,12 @@ context_get_vm_rcu(struct i915_gem_context *ctx)
 	} while (1);
 }
 
-static void intel_context_set_gem(struct intel_context *ce,
-				  struct i915_gem_context *ctx)
+static int intel_context_set_gem(struct intel_context *ce,
+				 struct i915_gem_context *ctx,
+				 struct intel_sseu sseu)
 {
+	int ret = 0;
+
 	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
 	RCU_INIT_POINTER(ce->gem_context, ctx);
 
@@ -349,6 +352,12 @@ static void intel_context_set_gem(struct intel_context *ce,
 
 		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
 	}
+
+	/* A valid SSEU has no zero fields */
+	if (sseu.slice_mask && !WARN_ON(ce->engine->class != RENDER_CLASS))
+		ret = intel_context_reconfigure_sseu(ce, sseu);
+
+	return ret;
 }
 
 static void __free_engines(struct i915_gem_engines *e, unsigned int count)
@@ -416,7 +425,8 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
 	return e;
 }
 
-static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
+static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
+						struct intel_sseu rcs_sseu)
 {
 	const struct intel_gt *gt = &ctx->i915->gt;
 	struct intel_engine_cs *engine;
@@ -429,6 +439,8 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
 
 	for_each_engine(engine, gt, id) {
 		struct intel_context *ce;
+		struct intel_sseu sseu = {};
+		int ret;
 
 		if (engine->legacy_idx == INVALID_ENGINE)
 			continue;
@@ -442,10 +454,18 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
 			goto free_engines;
 		}
 
-		intel_context_set_gem(ce, ctx);
-
 		e->engines[engine->legacy_idx] = ce;
 		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
+
+		if (engine->class == RENDER_CLASS)
+			sseu = rcs_sseu;
+
+		ret = intel_context_set_gem(ce, ctx, sseu);
+		if (ret) {
+			err = ERR_PTR(ret);
+			goto free_engines;
+		}
+
 	}
 
 	return e;
@@ -759,6 +779,7 @@ __create_context(struct drm_i915_private *i915,
 {
 	struct i915_gem_context *ctx;
 	struct i915_gem_engines *e;
+	struct intel_sseu null_sseu = {};
 	int err;
 	int i;
 
@@ -776,7 +797,7 @@ __create_context(struct drm_i915_private *i915,
 	INIT_LIST_HEAD(&ctx->stale.engines);
 
 	mutex_init(&ctx->engines_mutex);
-	e = default_engines(ctx);
+	e = default_engines(ctx, null_sseu);
 	if (IS_ERR(e)) {
 		err = PTR_ERR(e);
 		goto err_free;
@@ -1544,6 +1565,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
 	struct intel_engine_cs *stack[16];
 	struct intel_engine_cs **siblings;
 	struct intel_context *ce;
+	struct intel_sseu null_sseu = {};
 	u16 num_siblings, idx;
 	unsigned int n;
 	int err;
@@ -1616,7 +1638,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
 		goto out_siblings;
 	}
 
-	intel_context_set_gem(ce, set->ctx);
+	intel_context_set_gem(ce, set->ctx, null_sseu);
 
 	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
 		intel_context_put(ce);
@@ -1724,6 +1746,7 @@ set_engines(struct i915_gem_context *ctx,
 	struct drm_i915_private *i915 = ctx->i915;
 	struct i915_context_param_engines __user *user =
 		u64_to_user_ptr(args->value);
+	struct intel_sseu null_sseu = {};
 	struct set_engines set = { .ctx = ctx };
 	unsigned int num_engines, n;
 	u64 extensions;
@@ -1733,7 +1756,7 @@ set_engines(struct i915_gem_context *ctx,
 		if (!i915_gem_context_user_engines(ctx))
 			return 0;
 
-		set.engines = default_engines(ctx);
+		set.engines = default_engines(ctx, null_sseu);
 		if (IS_ERR(set.engines))
 			return PTR_ERR(set.engines);
 
@@ -1790,7 +1813,7 @@ set_engines(struct i915_gem_context *ctx,
 			return PTR_ERR(ce);
 		}
 
-		intel_context_set_gem(ce, ctx);
+		intel_context_set_gem(ce, ctx, null_sseu);
 
 		set.engines->engines[n] = ce;
 	}
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index e0f512ef7f3c6..cbeefd060e97b 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -14,6 +14,7 @@ mock_context(struct drm_i915_private *i915,
 {
 	struct i915_gem_context *ctx;
 	struct i915_gem_engines *e;
+	struct intel_sseu null_sseu = {};
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
@@ -31,7 +32,7 @@ mock_context(struct drm_i915_private *i915,
 	i915_gem_context_set_persistence(ctx);
 
 	mutex_init(&ctx->engines_mutex);
-	e = default_engines(ctx);
+	e = default_engines(ctx, null_sseu);
 	if (IS_ERR(e))
 		goto err_free;
 	RCU_INIT_POINTER(ctx->engines, e);
@@ -112,6 +113,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
 {
 	struct i915_gem_engines *engines;
 	struct i915_gem_context *ctx;
+	struct intel_sseu null_sseu = {};
 	struct intel_context *ce;
 
 	engines = alloc_engines(1);
@@ -130,7 +132,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
 		return ERR_CAST(ce);
 	}
 
-	intel_context_set_gem(ce, ctx);
+	intel_context_set_gem(ce, ctx, null_sseu);
 	engines->engines[0] = ce;
 	engines->num_engines = 1;
 
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

For now this is a no-op because everyone passes in a null SSEU but it
lets us get some of the error handling and selftest refactoring plumbed
through.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 41 +++++++++++++++----
 .../gpu/drm/i915/gem/selftests/mock_context.c |  6 ++-
 2 files changed, 36 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index ce729e640bbf7..6dd50d669c5b9 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -320,9 +320,12 @@ context_get_vm_rcu(struct i915_gem_context *ctx)
 	} while (1);
 }
 
-static void intel_context_set_gem(struct intel_context *ce,
-				  struct i915_gem_context *ctx)
+static int intel_context_set_gem(struct intel_context *ce,
+				 struct i915_gem_context *ctx,
+				 struct intel_sseu sseu)
 {
+	int ret = 0;
+
 	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
 	RCU_INIT_POINTER(ce->gem_context, ctx);
 
@@ -349,6 +352,12 @@ static void intel_context_set_gem(struct intel_context *ce,
 
 		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
 	}
+
+	/* A valid SSEU has no zero fields */
+	if (sseu.slice_mask && !WARN_ON(ce->engine->class != RENDER_CLASS))
+		ret = intel_context_reconfigure_sseu(ce, sseu);
+
+	return ret;
 }
 
 static void __free_engines(struct i915_gem_engines *e, unsigned int count)
@@ -416,7 +425,8 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
 	return e;
 }
 
-static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
+static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
+						struct intel_sseu rcs_sseu)
 {
 	const struct intel_gt *gt = &ctx->i915->gt;
 	struct intel_engine_cs *engine;
@@ -429,6 +439,8 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
 
 	for_each_engine(engine, gt, id) {
 		struct intel_context *ce;
+		struct intel_sseu sseu = {};
+		int ret;
 
 		if (engine->legacy_idx == INVALID_ENGINE)
 			continue;
@@ -442,10 +454,18 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
 			goto free_engines;
 		}
 
-		intel_context_set_gem(ce, ctx);
-
 		e->engines[engine->legacy_idx] = ce;
 		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
+
+		if (engine->class == RENDER_CLASS)
+			sseu = rcs_sseu;
+
+		ret = intel_context_set_gem(ce, ctx, sseu);
+		if (ret) {
+			err = ERR_PTR(ret);
+			goto free_engines;
+		}
+
 	}
 
 	return e;
@@ -759,6 +779,7 @@ __create_context(struct drm_i915_private *i915,
 {
 	struct i915_gem_context *ctx;
 	struct i915_gem_engines *e;
+	struct intel_sseu null_sseu = {};
 	int err;
 	int i;
 
@@ -776,7 +797,7 @@ __create_context(struct drm_i915_private *i915,
 	INIT_LIST_HEAD(&ctx->stale.engines);
 
 	mutex_init(&ctx->engines_mutex);
-	e = default_engines(ctx);
+	e = default_engines(ctx, null_sseu);
 	if (IS_ERR(e)) {
 		err = PTR_ERR(e);
 		goto err_free;
@@ -1544,6 +1565,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
 	struct intel_engine_cs *stack[16];
 	struct intel_engine_cs **siblings;
 	struct intel_context *ce;
+	struct intel_sseu null_sseu = {};
 	u16 num_siblings, idx;
 	unsigned int n;
 	int err;
@@ -1616,7 +1638,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
 		goto out_siblings;
 	}
 
-	intel_context_set_gem(ce, set->ctx);
+	intel_context_set_gem(ce, set->ctx, null_sseu);
 
 	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
 		intel_context_put(ce);
@@ -1724,6 +1746,7 @@ set_engines(struct i915_gem_context *ctx,
 	struct drm_i915_private *i915 = ctx->i915;
 	struct i915_context_param_engines __user *user =
 		u64_to_user_ptr(args->value);
+	struct intel_sseu null_sseu = {};
 	struct set_engines set = { .ctx = ctx };
 	unsigned int num_engines, n;
 	u64 extensions;
@@ -1733,7 +1756,7 @@ set_engines(struct i915_gem_context *ctx,
 		if (!i915_gem_context_user_engines(ctx))
 			return 0;
 
-		set.engines = default_engines(ctx);
+		set.engines = default_engines(ctx, null_sseu);
 		if (IS_ERR(set.engines))
 			return PTR_ERR(set.engines);
 
@@ -1790,7 +1813,7 @@ set_engines(struct i915_gem_context *ctx,
 			return PTR_ERR(ce);
 		}
 
-		intel_context_set_gem(ce, ctx);
+		intel_context_set_gem(ce, ctx, null_sseu);
 
 		set.engines->engines[n] = ce;
 	}
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index e0f512ef7f3c6..cbeefd060e97b 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -14,6 +14,7 @@ mock_context(struct drm_i915_private *i915,
 {
 	struct i915_gem_context *ctx;
 	struct i915_gem_engines *e;
+	struct intel_sseu null_sseu = {};
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
@@ -31,7 +32,7 @@ mock_context(struct drm_i915_private *i915,
 	i915_gem_context_set_persistence(ctx);
 
 	mutex_init(&ctx->engines_mutex);
-	e = default_engines(ctx);
+	e = default_engines(ctx, null_sseu);
 	if (IS_ERR(e))
 		goto err_free;
 	RCU_INIT_POINTER(ctx->engines, e);
@@ -112,6 +113,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
 {
 	struct i915_gem_engines *engines;
 	struct i915_gem_context *ctx;
+	struct intel_sseu null_sseu = {};
 	struct intel_context *ce;
 
 	engines = alloc_engines(1);
@@ -130,7 +132,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
 		return ERR_CAST(ce);
 	}
 
-	intel_context_set_gem(ce, ctx);
+	intel_context_set_gem(ce, ctx, null_sseu);
 	engines->engines[0] = ce;
 	engines->num_engines = 1;
 
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

This means that the proto-context needs to grow support for engine
configuration information as well as setparam logic.  Fortunately, we'll
be deleting a lot of setparam logic on the primary context shortly so it
will hopefully balance out.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
 .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
 2 files changed, 587 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 6dd50d669c5b9..aa4edfbf7ed48 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
 
 static void proto_context_close(struct i915_gem_proto_context *pc)
 {
+	int i;
+
 	if (pc->vm)
 		i915_vm_put(pc->vm);
+	if (pc->user_engines) {
+		for (i = 0; i < pc->num_user_engines; i++)
+			kfree(pc->user_engines[i].siblings);
+		kfree(pc->user_engines);
+	}
 	kfree(pc);
 }
 
@@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
 	if (!pc)
 		return ERR_PTR(-ENOMEM);
 
+	pc->num_user_engines = -1;
+	pc->user_engines = NULL;
+
 	if (HAS_FULL_PPGTT(i915)) {
 		struct i915_ppgtt *ppgtt;
 
@@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
 	return err;
 }
 
+static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
+			    struct i915_gem_proto_context *pc,
+			    const struct drm_i915_gem_context_param *args)
+{
+	struct i915_address_space *vm;
+
+	if (args->size)
+		return -EINVAL;
+
+	if (!pc->vm)
+		return -ENODEV;
+
+	if (upper_32_bits(args->value))
+		return -ENOENT;
+
+	rcu_read_lock();
+	vm = xa_load(&fpriv->vm_xa, args->value);
+	if (vm && !kref_get_unless_zero(&vm->ref))
+		vm = NULL;
+	rcu_read_unlock();
+	if (!vm)
+		return -ENOENT;
+
+	i915_vm_put(pc->vm);
+	pc->vm = vm;
+
+	return 0;
+}
+
+struct set_proto_ctx_engines {
+	struct drm_i915_private *i915;
+	unsigned num_engines;
+	struct i915_gem_proto_engine *engines;
+};
+
+static int
+set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
+			      void *data)
+{
+	struct i915_context_engines_load_balance __user *ext =
+		container_of_user(base, typeof(*ext), base);
+	const struct set_proto_ctx_engines *set = data;
+	struct drm_i915_private *i915 = set->i915;
+	struct intel_engine_cs **siblings;
+	u16 num_siblings, idx;
+	unsigned int n;
+	int err;
+
+	if (!HAS_EXECLISTS(i915))
+		return -ENODEV;
+
+	if (intel_uc_uses_guc_submission(&i915->gt.uc))
+		return -ENODEV; /* not implement yet */
+
+	if (get_user(idx, &ext->engine_index))
+		return -EFAULT;
+
+	if (idx >= set->num_engines) {
+		drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
+			idx, set->num_engines);
+		return -EINVAL;
+	}
+
+	idx = array_index_nospec(idx, set->num_engines);
+	if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
+		drm_dbg(&i915->drm,
+			"Invalid placement[%d], already occupied\n", idx);
+		return -EEXIST;
+	}
+
+	if (get_user(num_siblings, &ext->num_siblings))
+		return -EFAULT;
+
+	err = check_user_mbz(&ext->flags);
+	if (err)
+		return err;
+
+	err = check_user_mbz(&ext->mbz64);
+	if (err)
+		return err;
+
+	if (num_siblings == 0)
+		return 0;
+
+	siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);
+	if (!siblings)
+		return -ENOMEM;
+
+	for (n = 0; n < num_siblings; n++) {
+		struct i915_engine_class_instance ci;
+
+		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
+			err = -EFAULT;
+			goto err_siblings;
+		}
+
+		siblings[n] = intel_engine_lookup_user(i915,
+						       ci.engine_class,
+						       ci.engine_instance);
+		if (!siblings[n]) {
+			drm_dbg(&i915->drm,
+				"Invalid sibling[%d]: { class:%d, inst:%d }\n",
+				n, ci.engine_class, ci.engine_instance);
+			err = -EINVAL;
+			goto err_siblings;
+		}
+	}
+
+	if (num_siblings == 1) {
+		set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
+		set->engines[idx].engine = siblings[0];
+		kfree(siblings);
+	} else {
+		set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
+		set->engines[idx].num_siblings = num_siblings;
+		set->engines[idx].siblings = siblings;
+	}
+
+	return 0;
+
+err_siblings:
+	kfree(siblings);
+
+	return err;
+}
+
+static int
+set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
+{
+	struct i915_context_engines_bond __user *ext =
+		container_of_user(base, typeof(*ext), base);
+	const struct set_proto_ctx_engines *set = data;
+	struct drm_i915_private *i915 = set->i915;
+	struct i915_engine_class_instance ci;
+	struct intel_engine_cs *master;
+	u16 idx, num_bonds;
+	int err, n;
+
+	if (get_user(idx, &ext->virtual_index))
+		return -EFAULT;
+
+	if (idx >= set->num_engines) {
+		drm_dbg(&i915->drm,
+			"Invalid index for virtual engine: %d >= %d\n",
+			idx, set->num_engines);
+		return -EINVAL;
+	}
+
+	idx = array_index_nospec(idx, set->num_engines);
+	if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
+		drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
+		return -EINVAL;
+	}
+
+	if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
+		drm_dbg(&i915->drm,
+			"Bonding with virtual engines not allowed\n");
+		return -EINVAL;
+	}
+
+	err = check_user_mbz(&ext->flags);
+	if (err)
+		return err;
+
+	for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
+		err = check_user_mbz(&ext->mbz64[n]);
+		if (err)
+			return err;
+	}
+
+	if (copy_from_user(&ci, &ext->master, sizeof(ci)))
+		return -EFAULT;
+
+	master = intel_engine_lookup_user(i915,
+					  ci.engine_class,
+					  ci.engine_instance);
+	if (!master) {
+		drm_dbg(&i915->drm,
+			"Unrecognised master engine: { class:%u, instance:%u }\n",
+			ci.engine_class, ci.engine_instance);
+		return -EINVAL;
+	}
+
+	if (get_user(num_bonds, &ext->num_bonds))
+		return -EFAULT;
+
+	for (n = 0; n < num_bonds; n++) {
+		struct intel_engine_cs *bond;
+
+		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
+			return -EFAULT;
+
+		bond = intel_engine_lookup_user(i915,
+						ci.engine_class,
+						ci.engine_instance);
+		if (!bond) {
+			drm_dbg(&i915->drm,
+				"Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
+				n, ci.engine_class, ci.engine_instance);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
+	[I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
+	[I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
+};
+
+static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
+			         struct i915_gem_proto_context *pc,
+			         const struct drm_i915_gem_context_param *args)
+{
+	struct drm_i915_private *i915 = fpriv->dev_priv;
+	struct set_proto_ctx_engines set = { .i915 = i915 };
+	struct i915_context_param_engines __user *user =
+		u64_to_user_ptr(args->value);
+	unsigned int n;
+	u64 extensions;
+	int err;
+
+	if (!args->size) {
+		kfree(pc->user_engines);
+		pc->num_user_engines = -1;
+		pc->user_engines = NULL;
+		memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
+		return 0;
+	}
+
+	BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
+	if (args->size < sizeof(*user) ||
+	    !IS_ALIGNED(args->size, sizeof(*user->engines))) {
+		drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
+			args->size);
+		return -EINVAL;
+	}
+
+	set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
+	/* RING_MASK has no shift so we can use it directly here */
+	if (set.num_engines > I915_EXEC_RING_MASK + 1)
+		return -EINVAL;
+
+	set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
+	if (!set.engines)
+		return -ENOMEM;
+
+	for (n = 0; n < set.num_engines; n++) {
+		struct i915_engine_class_instance ci;
+		struct intel_engine_cs *engine;
+
+		if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
+			kfree(set.engines);
+			return -EFAULT;
+		}
+
+		memset(&set.engines[n], 0, sizeof(set.engines[n]));
+
+		if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
+		    ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
+			continue;
+
+		engine = intel_engine_lookup_user(i915,
+						  ci.engine_class,
+						  ci.engine_instance);
+		if (!engine) {
+			drm_dbg(&i915->drm,
+				"Invalid engine[%d]: { class:%d, instance:%d }\n",
+				n, ci.engine_class, ci.engine_instance);
+			kfree(set.engines);
+			return -ENOENT;
+		}
+
+		set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
+		set.engines[n].engine = engine;
+	}
+
+	err = -EFAULT;
+	if (!get_user(extensions, &user->extensions))
+		err = i915_user_extensions(u64_to_user_ptr(extensions),
+					   set_proto_ctx_engines_extensions,
+					   ARRAY_SIZE(set_proto_ctx_engines_extensions),
+					   &set);
+	if (err) {
+		kfree(set.engines);
+		return err;
+	}
+
+	kfree(pc->user_engines);
+	pc->num_user_engines = set.num_engines;
+	pc->user_engines = set.engines;
+
+	return 0;
+}
+
+static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
+			      struct i915_gem_proto_context *pc,
+			      struct drm_i915_gem_context_param *args)
+{
+	struct drm_i915_private *i915 = fpriv->dev_priv;
+	struct drm_i915_gem_context_param_sseu user_sseu;
+	struct intel_sseu *sseu;
+	int ret;
+
+	if (args->size < sizeof(user_sseu))
+		return -EINVAL;
+
+	if (!IS_GEN(i915, 11))
+		return -ENODEV;
+
+	if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
+			   sizeof(user_sseu)))
+		return -EFAULT;
+
+	if (user_sseu.rsvd)
+		return -EINVAL;
+
+	if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
+		return -EINVAL;
+
+	if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
+		return -EINVAL;
+
+	if (pc->num_user_engines >= 0) {
+		int idx = user_sseu.engine.engine_instance;
+		struct i915_gem_proto_engine *pe;
+
+		if (idx >= pc->num_user_engines)
+			return -EINVAL;
+
+		pe = &pc->user_engines[idx];
+
+		/* Only render engine supports RPCS configuration. */
+		if (pe->engine->class != RENDER_CLASS)
+			return -EINVAL;
+
+		sseu = &pe->sseu;
+	} else {
+		/* Only render engine supports RPCS configuration. */
+		if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
+			return -EINVAL;
+
+		/* There is only one render engine */
+		if (user_sseu.engine.engine_instance != 0)
+			return -EINVAL;
+
+		sseu = &pc->legacy_rcs_sseu;
+	}
+
+	ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
+	if (ret)
+		return ret;
+
+	args->size = sizeof(user_sseu);
+
+	return 0;
+}
+
+static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
+			       struct i915_gem_proto_context *pc,
+			       struct drm_i915_gem_context_param *args)
+{
+	int ret = 0;
+
+	switch (args->param) {
+	case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
+		if (args->size)
+			ret = -EINVAL;
+		else if (args->value)
+			__set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
+		else
+			__clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
+		break;
+
+	case I915_CONTEXT_PARAM_BANNABLE:
+		if (args->size)
+			ret = -EINVAL;
+		else if (!capable(CAP_SYS_ADMIN) && !args->value)
+			ret = -EPERM;
+		else if (args->value)
+			__set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
+		else
+			__clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
+		break;
+
+	case I915_CONTEXT_PARAM_RECOVERABLE:
+		if (args->size)
+			ret = -EINVAL;
+		else if (args->value)
+			__set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
+		else
+			__clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
+		break;
+
+	case I915_CONTEXT_PARAM_PRIORITY:
+		ret = validate_priority(fpriv->dev_priv, args);
+		if (!ret)
+			pc->sched.priority = args->value;
+		break;
+
+	case I915_CONTEXT_PARAM_SSEU:
+		ret = set_proto_ctx_sseu(fpriv, pc, args);
+		break;
+
+	case I915_CONTEXT_PARAM_VM:
+		ret = set_proto_ctx_vm(fpriv, pc, args);
+		break;
+
+	case I915_CONTEXT_PARAM_ENGINES:
+		ret = set_proto_ctx_engines(fpriv, pc, args);
+		break;
+
+	case I915_CONTEXT_PARAM_PERSISTENCE:
+		if (args->size)
+			ret = -EINVAL;
+		else if (args->value)
+			__set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
+		else
+			__clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
+		break;
+
+	case I915_CONTEXT_PARAM_NO_ZEROMAP:
+	case I915_CONTEXT_PARAM_BAN_PERIOD:
+	case I915_CONTEXT_PARAM_RINGSIZE:
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static struct i915_address_space *
 context_get_vm_rcu(struct i915_gem_context *ctx)
 {
@@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
 	return err;
 }
 
+static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
+					     unsigned int num_engines,
+					     struct i915_gem_proto_engine *pe)
+{
+	struct i915_gem_engines *e, *err;
+	unsigned int n;
+
+	e = alloc_engines(num_engines);
+	for (n = 0; n < num_engines; n++) {
+		struct intel_context *ce;
+		int ret;
+
+		switch (pe[n].type) {
+		case I915_GEM_ENGINE_TYPE_PHYSICAL:
+			ce = intel_context_create(pe[n].engine);
+			break;
+
+		case I915_GEM_ENGINE_TYPE_BALANCED:
+			ce = intel_execlists_create_virtual(pe[n].siblings,
+							    pe[n].num_siblings);
+			break;
+
+		case I915_GEM_ENGINE_TYPE_INVALID:
+		default:
+			GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
+			continue;
+		}
+
+		if (IS_ERR(ce)) {
+			err = ERR_CAST(ce);
+			goto free_engines;
+		}
+
+		e->engines[n] = ce;
+
+		ret = intel_context_set_gem(ce, ctx, pe->sseu);
+		if (ret) {
+			err = ERR_PTR(ret);
+			goto free_engines;
+		}
+	}
+	e->num_engines = num_engines;
+
+	return e;
+
+free_engines:
+	free_engines(e);
+	return err;
+}
+
 void i915_gem_context_release(struct kref *ref)
 {
 	struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
@@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
 {
 	struct i915_gem_context *ctx;
 	struct i915_gem_engines *e;
-	struct intel_sseu null_sseu = {};
 	int err;
 	int i;
 
@@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
 	INIT_LIST_HEAD(&ctx->stale.engines);
 
 	mutex_init(&ctx->engines_mutex);
-	e = default_engines(ctx, null_sseu);
+	e = default_engines(ctx, pc->legacy_rcs_sseu);
 	if (IS_ERR(e)) {
 		err = PTR_ERR(e);
 		goto err_free;
@@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
 		mutex_unlock(&ctx->mutex);
 	}
 
+	if (pc->num_user_engines >= 0) {
+		struct i915_gem_engines *engines;
+
+		engines = user_engines(ctx, pc->num_user_engines,
+				       pc->user_engines);
+		if (IS_ERR(engines)) {
+			context_close(ctx);
+			return ERR_CAST(engines);
+		}
+
+		mutex_lock(&ctx->engines_mutex);
+		i915_gem_context_set_user_engines(ctx);
+		engines = rcu_replace_pointer(ctx->engines, engines, 1);
+		mutex_unlock(&ctx->engines_mutex);
+
+		free_engines(engines);
+	}
+
 	if (pc->single_timeline) {
 		ret = drm_syncobj_create(&ctx->syncobj,
 					 DRM_SYNCOBJ_CREATE_SIGNALED,
@@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 }
 
 struct create_ext {
-	struct i915_gem_context *ctx;
+	struct i915_gem_proto_context *pc;
 	struct drm_i915_file_private *fpriv;
 };
 
@@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
 	if (local.param.ctx_id)
 		return -EINVAL;
 
-	return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
+	return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
 }
 
 static int invalid_ext(struct i915_user_extension __user *ext, void *data)
@@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_i915_private *i915 = to_i915(dev);
 	struct drm_i915_gem_context_create_ext *args = data;
-	struct i915_gem_proto_context *pc;
+	struct i915_gem_context *ctx;
 	struct create_ext ext_data;
 	int ret;
 	u32 id;
@@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 		return -EIO;
 	}
 
-	pc = proto_context_create(i915, args->flags);
-	if (IS_ERR(pc))
-		return PTR_ERR(pc);
-
-	ext_data.ctx = i915_gem_create_context(i915, pc);
-	proto_context_close(pc);
-	if (IS_ERR(ext_data.ctx))
-		return PTR_ERR(ext_data.ctx);
+	ext_data.pc = proto_context_create(i915, args->flags);
+	if (IS_ERR(ext_data.pc))
+		return PTR_ERR(ext_data.pc);
 
 	if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
 		ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
 					   create_extensions,
 					   ARRAY_SIZE(create_extensions),
 					   &ext_data);
-		if (ret)
-			goto err_ctx;
+		if (ret) {
+			proto_context_close(ext_data.pc);
+			return ret;
+		}
 	}
 
-	ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
+	ctx = i915_gem_create_context(i915, ext_data.pc);
+	proto_context_close(ext_data.pc);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	ret = gem_context_register(ctx, ext_data.fpriv, &id);
 	if (ret < 0)
 		goto err_ctx;
 
@@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 	return 0;
 
 err_ctx:
-	context_close(ext_data.ctx);
+	context_close(ctx);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 0bf337b6d89ac..2ac341f805c8f 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
 	const struct i915_gem_engines *engines;
 };
 
+/**
+ * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
+ */
+enum i915_gem_engine_type {
+	/** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
+	I915_GEM_ENGINE_TYPE_INVALID = 0,
+
+	/** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
+	I915_GEM_ENGINE_TYPE_PHYSICAL,
+
+	/** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
+	I915_GEM_ENGINE_TYPE_BALANCED,
+};
+
+/**
+ * struct i915_gem_proto_engine - prototype engine
+ *
+ * This struct describes an engine that a context may contain.  Engines
+ * have three types:
+ *
+ *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
+ *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
+ *    use them by the user results in -EINVAL.  They are also useful during
+ *    proto-context construction because the client may create invalid
+ *    engines and then set them up later as bonded engines.
+ *
+ *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
+ *    i915_gem_proto_engine::engine.
+ *
+ *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
+ *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
+ */
+struct i915_gem_proto_engine {
+	/** @type: Type of this engine */
+	enum i915_gem_engine_type type;
+
+	/** @engine: Engine, for physical */
+	struct intel_engine_cs *engine;
+
+	/** @num_siblings: Number of balanced siblings */
+	unsigned int num_siblings;
+
+	/** @siblings: Balanced siblings */
+	struct intel_engine_cs **siblings;
+
+	/** @sseu: Client-set SSEU parameters */
+	struct intel_sseu sseu;
+};
+
 /**
  * struct i915_gem_proto_context - prototype context
  *
@@ -84,6 +133,15 @@ struct i915_gem_proto_context {
 	/** @sched: See i915_gem_context::sched */
 	struct i915_sched_attr sched;
 
+	/** @num_user_engines: Number of user-specified engines or -1 */
+	int num_user_engines;
+
+	/** @user_engines: User-specified engines */
+	struct i915_gem_proto_engine *user_engines;
+
+	/** @sseu: Client-set SSEU parameters for the legacy RCS */
+	struct intel_sseu legacy_rcs_sseu;
+
 	/** @single_timeline: See See i915_gem_context::syncobj */
 	bool single_timeline;
 };
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

This means that the proto-context needs to grow support for engine
configuration information as well as setparam logic.  Fortunately, we'll
be deleting a lot of setparam logic on the primary context shortly so it
will hopefully balance out.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
 .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
 2 files changed, 587 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 6dd50d669c5b9..aa4edfbf7ed48 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
 
 static void proto_context_close(struct i915_gem_proto_context *pc)
 {
+	int i;
+
 	if (pc->vm)
 		i915_vm_put(pc->vm);
+	if (pc->user_engines) {
+		for (i = 0; i < pc->num_user_engines; i++)
+			kfree(pc->user_engines[i].siblings);
+		kfree(pc->user_engines);
+	}
 	kfree(pc);
 }
 
@@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
 	if (!pc)
 		return ERR_PTR(-ENOMEM);
 
+	pc->num_user_engines = -1;
+	pc->user_engines = NULL;
+
 	if (HAS_FULL_PPGTT(i915)) {
 		struct i915_ppgtt *ppgtt;
 
@@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
 	return err;
 }
 
+static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
+			    struct i915_gem_proto_context *pc,
+			    const struct drm_i915_gem_context_param *args)
+{
+	struct i915_address_space *vm;
+
+	if (args->size)
+		return -EINVAL;
+
+	if (!pc->vm)
+		return -ENODEV;
+
+	if (upper_32_bits(args->value))
+		return -ENOENT;
+
+	rcu_read_lock();
+	vm = xa_load(&fpriv->vm_xa, args->value);
+	if (vm && !kref_get_unless_zero(&vm->ref))
+		vm = NULL;
+	rcu_read_unlock();
+	if (!vm)
+		return -ENOENT;
+
+	i915_vm_put(pc->vm);
+	pc->vm = vm;
+
+	return 0;
+}
+
+struct set_proto_ctx_engines {
+	struct drm_i915_private *i915;
+	unsigned num_engines;
+	struct i915_gem_proto_engine *engines;
+};
+
+static int
+set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
+			      void *data)
+{
+	struct i915_context_engines_load_balance __user *ext =
+		container_of_user(base, typeof(*ext), base);
+	const struct set_proto_ctx_engines *set = data;
+	struct drm_i915_private *i915 = set->i915;
+	struct intel_engine_cs **siblings;
+	u16 num_siblings, idx;
+	unsigned int n;
+	int err;
+
+	if (!HAS_EXECLISTS(i915))
+		return -ENODEV;
+
+	if (intel_uc_uses_guc_submission(&i915->gt.uc))
+		return -ENODEV; /* not implement yet */
+
+	if (get_user(idx, &ext->engine_index))
+		return -EFAULT;
+
+	if (idx >= set->num_engines) {
+		drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
+			idx, set->num_engines);
+		return -EINVAL;
+	}
+
+	idx = array_index_nospec(idx, set->num_engines);
+	if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
+		drm_dbg(&i915->drm,
+			"Invalid placement[%d], already occupied\n", idx);
+		return -EEXIST;
+	}
+
+	if (get_user(num_siblings, &ext->num_siblings))
+		return -EFAULT;
+
+	err = check_user_mbz(&ext->flags);
+	if (err)
+		return err;
+
+	err = check_user_mbz(&ext->mbz64);
+	if (err)
+		return err;
+
+	if (num_siblings == 0)
+		return 0;
+
+	siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);
+	if (!siblings)
+		return -ENOMEM;
+
+	for (n = 0; n < num_siblings; n++) {
+		struct i915_engine_class_instance ci;
+
+		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
+			err = -EFAULT;
+			goto err_siblings;
+		}
+
+		siblings[n] = intel_engine_lookup_user(i915,
+						       ci.engine_class,
+						       ci.engine_instance);
+		if (!siblings[n]) {
+			drm_dbg(&i915->drm,
+				"Invalid sibling[%d]: { class:%d, inst:%d }\n",
+				n, ci.engine_class, ci.engine_instance);
+			err = -EINVAL;
+			goto err_siblings;
+		}
+	}
+
+	if (num_siblings == 1) {
+		set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
+		set->engines[idx].engine = siblings[0];
+		kfree(siblings);
+	} else {
+		set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
+		set->engines[idx].num_siblings = num_siblings;
+		set->engines[idx].siblings = siblings;
+	}
+
+	return 0;
+
+err_siblings:
+	kfree(siblings);
+
+	return err;
+}
+
+static int
+set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
+{
+	struct i915_context_engines_bond __user *ext =
+		container_of_user(base, typeof(*ext), base);
+	const struct set_proto_ctx_engines *set = data;
+	struct drm_i915_private *i915 = set->i915;
+	struct i915_engine_class_instance ci;
+	struct intel_engine_cs *master;
+	u16 idx, num_bonds;
+	int err, n;
+
+	if (get_user(idx, &ext->virtual_index))
+		return -EFAULT;
+
+	if (idx >= set->num_engines) {
+		drm_dbg(&i915->drm,
+			"Invalid index for virtual engine: %d >= %d\n",
+			idx, set->num_engines);
+		return -EINVAL;
+	}
+
+	idx = array_index_nospec(idx, set->num_engines);
+	if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
+		drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
+		return -EINVAL;
+	}
+
+	if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
+		drm_dbg(&i915->drm,
+			"Bonding with virtual engines not allowed\n");
+		return -EINVAL;
+	}
+
+	err = check_user_mbz(&ext->flags);
+	if (err)
+		return err;
+
+	for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
+		err = check_user_mbz(&ext->mbz64[n]);
+		if (err)
+			return err;
+	}
+
+	if (copy_from_user(&ci, &ext->master, sizeof(ci)))
+		return -EFAULT;
+
+	master = intel_engine_lookup_user(i915,
+					  ci.engine_class,
+					  ci.engine_instance);
+	if (!master) {
+		drm_dbg(&i915->drm,
+			"Unrecognised master engine: { class:%u, instance:%u }\n",
+			ci.engine_class, ci.engine_instance);
+		return -EINVAL;
+	}
+
+	if (get_user(num_bonds, &ext->num_bonds))
+		return -EFAULT;
+
+	for (n = 0; n < num_bonds; n++) {
+		struct intel_engine_cs *bond;
+
+		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
+			return -EFAULT;
+
+		bond = intel_engine_lookup_user(i915,
+						ci.engine_class,
+						ci.engine_instance);
+		if (!bond) {
+			drm_dbg(&i915->drm,
+				"Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
+				n, ci.engine_class, ci.engine_instance);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
+	[I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
+	[I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
+};
+
+static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
+			         struct i915_gem_proto_context *pc,
+			         const struct drm_i915_gem_context_param *args)
+{
+	struct drm_i915_private *i915 = fpriv->dev_priv;
+	struct set_proto_ctx_engines set = { .i915 = i915 };
+	struct i915_context_param_engines __user *user =
+		u64_to_user_ptr(args->value);
+	unsigned int n;
+	u64 extensions;
+	int err;
+
+	if (!args->size) {
+		kfree(pc->user_engines);
+		pc->num_user_engines = -1;
+		pc->user_engines = NULL;
+		memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
+		return 0;
+	}
+
+	BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
+	if (args->size < sizeof(*user) ||
+	    !IS_ALIGNED(args->size, sizeof(*user->engines))) {
+		drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
+			args->size);
+		return -EINVAL;
+	}
+
+	set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
+	/* RING_MASK has no shift so we can use it directly here */
+	if (set.num_engines > I915_EXEC_RING_MASK + 1)
+		return -EINVAL;
+
+	set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
+	if (!set.engines)
+		return -ENOMEM;
+
+	for (n = 0; n < set.num_engines; n++) {
+		struct i915_engine_class_instance ci;
+		struct intel_engine_cs *engine;
+
+		if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
+			kfree(set.engines);
+			return -EFAULT;
+		}
+
+		memset(&set.engines[n], 0, sizeof(set.engines[n]));
+
+		if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
+		    ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
+			continue;
+
+		engine = intel_engine_lookup_user(i915,
+						  ci.engine_class,
+						  ci.engine_instance);
+		if (!engine) {
+			drm_dbg(&i915->drm,
+				"Invalid engine[%d]: { class:%d, instance:%d }\n",
+				n, ci.engine_class, ci.engine_instance);
+			kfree(set.engines);
+			return -ENOENT;
+		}
+
+		set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
+		set.engines[n].engine = engine;
+	}
+
+	err = -EFAULT;
+	if (!get_user(extensions, &user->extensions))
+		err = i915_user_extensions(u64_to_user_ptr(extensions),
+					   set_proto_ctx_engines_extensions,
+					   ARRAY_SIZE(set_proto_ctx_engines_extensions),
+					   &set);
+	if (err) {
+		kfree(set.engines);
+		return err;
+	}
+
+	kfree(pc->user_engines);
+	pc->num_user_engines = set.num_engines;
+	pc->user_engines = set.engines;
+
+	return 0;
+}
+
+static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
+			      struct i915_gem_proto_context *pc,
+			      struct drm_i915_gem_context_param *args)
+{
+	struct drm_i915_private *i915 = fpriv->dev_priv;
+	struct drm_i915_gem_context_param_sseu user_sseu;
+	struct intel_sseu *sseu;
+	int ret;
+
+	if (args->size < sizeof(user_sseu))
+		return -EINVAL;
+
+	if (!IS_GEN(i915, 11))
+		return -ENODEV;
+
+	if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
+			   sizeof(user_sseu)))
+		return -EFAULT;
+
+	if (user_sseu.rsvd)
+		return -EINVAL;
+
+	if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
+		return -EINVAL;
+
+	if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
+		return -EINVAL;
+
+	if (pc->num_user_engines >= 0) {
+		int idx = user_sseu.engine.engine_instance;
+		struct i915_gem_proto_engine *pe;
+
+		if (idx >= pc->num_user_engines)
+			return -EINVAL;
+
+		pe = &pc->user_engines[idx];
+
+		/* Only render engine supports RPCS configuration. */
+		if (pe->engine->class != RENDER_CLASS)
+			return -EINVAL;
+
+		sseu = &pe->sseu;
+	} else {
+		/* Only render engine supports RPCS configuration. */
+		if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
+			return -EINVAL;
+
+		/* There is only one render engine */
+		if (user_sseu.engine.engine_instance != 0)
+			return -EINVAL;
+
+		sseu = &pc->legacy_rcs_sseu;
+	}
+
+	ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
+	if (ret)
+		return ret;
+
+	args->size = sizeof(user_sseu);
+
+	return 0;
+}
+
+static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
+			       struct i915_gem_proto_context *pc,
+			       struct drm_i915_gem_context_param *args)
+{
+	int ret = 0;
+
+	switch (args->param) {
+	case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
+		if (args->size)
+			ret = -EINVAL;
+		else if (args->value)
+			__set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
+		else
+			__clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
+		break;
+
+	case I915_CONTEXT_PARAM_BANNABLE:
+		if (args->size)
+			ret = -EINVAL;
+		else if (!capable(CAP_SYS_ADMIN) && !args->value)
+			ret = -EPERM;
+		else if (args->value)
+			__set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
+		else
+			__clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
+		break;
+
+	case I915_CONTEXT_PARAM_RECOVERABLE:
+		if (args->size)
+			ret = -EINVAL;
+		else if (args->value)
+			__set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
+		else
+			__clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
+		break;
+
+	case I915_CONTEXT_PARAM_PRIORITY:
+		ret = validate_priority(fpriv->dev_priv, args);
+		if (!ret)
+			pc->sched.priority = args->value;
+		break;
+
+	case I915_CONTEXT_PARAM_SSEU:
+		ret = set_proto_ctx_sseu(fpriv, pc, args);
+		break;
+
+	case I915_CONTEXT_PARAM_VM:
+		ret = set_proto_ctx_vm(fpriv, pc, args);
+		break;
+
+	case I915_CONTEXT_PARAM_ENGINES:
+		ret = set_proto_ctx_engines(fpriv, pc, args);
+		break;
+
+	case I915_CONTEXT_PARAM_PERSISTENCE:
+		if (args->size)
+			ret = -EINVAL;
+		else if (args->value)
+			__set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
+		else
+			__clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
+		break;
+
+	case I915_CONTEXT_PARAM_NO_ZEROMAP:
+	case I915_CONTEXT_PARAM_BAN_PERIOD:
+	case I915_CONTEXT_PARAM_RINGSIZE:
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static struct i915_address_space *
 context_get_vm_rcu(struct i915_gem_context *ctx)
 {
@@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
 	return err;
 }
 
+static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
+					     unsigned int num_engines,
+					     struct i915_gem_proto_engine *pe)
+{
+	struct i915_gem_engines *e, *err;
+	unsigned int n;
+
+	e = alloc_engines(num_engines);
+	for (n = 0; n < num_engines; n++) {
+		struct intel_context *ce;
+		int ret;
+
+		switch (pe[n].type) {
+		case I915_GEM_ENGINE_TYPE_PHYSICAL:
+			ce = intel_context_create(pe[n].engine);
+			break;
+
+		case I915_GEM_ENGINE_TYPE_BALANCED:
+			ce = intel_execlists_create_virtual(pe[n].siblings,
+							    pe[n].num_siblings);
+			break;
+
+		case I915_GEM_ENGINE_TYPE_INVALID:
+		default:
+			GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
+			continue;
+		}
+
+		if (IS_ERR(ce)) {
+			err = ERR_CAST(ce);
+			goto free_engines;
+		}
+
+		e->engines[n] = ce;
+
+		ret = intel_context_set_gem(ce, ctx, pe->sseu);
+		if (ret) {
+			err = ERR_PTR(ret);
+			goto free_engines;
+		}
+	}
+	e->num_engines = num_engines;
+
+	return e;
+
+free_engines:
+	free_engines(e);
+	return err;
+}
+
 void i915_gem_context_release(struct kref *ref)
 {
 	struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
@@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
 {
 	struct i915_gem_context *ctx;
 	struct i915_gem_engines *e;
-	struct intel_sseu null_sseu = {};
 	int err;
 	int i;
 
@@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
 	INIT_LIST_HEAD(&ctx->stale.engines);
 
 	mutex_init(&ctx->engines_mutex);
-	e = default_engines(ctx, null_sseu);
+	e = default_engines(ctx, pc->legacy_rcs_sseu);
 	if (IS_ERR(e)) {
 		err = PTR_ERR(e);
 		goto err_free;
@@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
 		mutex_unlock(&ctx->mutex);
 	}
 
+	if (pc->num_user_engines >= 0) {
+		struct i915_gem_engines *engines;
+
+		engines = user_engines(ctx, pc->num_user_engines,
+				       pc->user_engines);
+		if (IS_ERR(engines)) {
+			context_close(ctx);
+			return ERR_CAST(engines);
+		}
+
+		mutex_lock(&ctx->engines_mutex);
+		i915_gem_context_set_user_engines(ctx);
+		engines = rcu_replace_pointer(ctx->engines, engines, 1);
+		mutex_unlock(&ctx->engines_mutex);
+
+		free_engines(engines);
+	}
+
 	if (pc->single_timeline) {
 		ret = drm_syncobj_create(&ctx->syncobj,
 					 DRM_SYNCOBJ_CREATE_SIGNALED,
@@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 }
 
 struct create_ext {
-	struct i915_gem_context *ctx;
+	struct i915_gem_proto_context *pc;
 	struct drm_i915_file_private *fpriv;
 };
 
@@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
 	if (local.param.ctx_id)
 		return -EINVAL;
 
-	return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
+	return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
 }
 
 static int invalid_ext(struct i915_user_extension __user *ext, void *data)
@@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_i915_private *i915 = to_i915(dev);
 	struct drm_i915_gem_context_create_ext *args = data;
-	struct i915_gem_proto_context *pc;
+	struct i915_gem_context *ctx;
 	struct create_ext ext_data;
 	int ret;
 	u32 id;
@@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 		return -EIO;
 	}
 
-	pc = proto_context_create(i915, args->flags);
-	if (IS_ERR(pc))
-		return PTR_ERR(pc);
-
-	ext_data.ctx = i915_gem_create_context(i915, pc);
-	proto_context_close(pc);
-	if (IS_ERR(ext_data.ctx))
-		return PTR_ERR(ext_data.ctx);
+	ext_data.pc = proto_context_create(i915, args->flags);
+	if (IS_ERR(ext_data.pc))
+		return PTR_ERR(ext_data.pc);
 
 	if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
 		ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
 					   create_extensions,
 					   ARRAY_SIZE(create_extensions),
 					   &ext_data);
-		if (ret)
-			goto err_ctx;
+		if (ret) {
+			proto_context_close(ext_data.pc);
+			return ret;
+		}
 	}
 
-	ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
+	ctx = i915_gem_create_context(i915, ext_data.pc);
+	proto_context_close(ext_data.pc);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	ret = gem_context_register(ctx, ext_data.fpriv, &id);
 	if (ret < 0)
 		goto err_ctx;
 
@@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 	return 0;
 
 err_ctx:
-	context_close(ext_data.ctx);
+	context_close(ctx);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 0bf337b6d89ac..2ac341f805c8f 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
 	const struct i915_gem_engines *engines;
 };
 
+/**
+ * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
+ */
+enum i915_gem_engine_type {
+	/** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
+	I915_GEM_ENGINE_TYPE_INVALID = 0,
+
+	/** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
+	I915_GEM_ENGINE_TYPE_PHYSICAL,
+
+	/** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
+	I915_GEM_ENGINE_TYPE_BALANCED,
+};
+
+/**
+ * struct i915_gem_proto_engine - prototype engine
+ *
+ * This struct describes an engine that a context may contain.  Engines
+ * have three types:
+ *
+ *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
+ *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
+ *    use them by the user results in -EINVAL.  They are also useful during
+ *    proto-context construction because the client may create invalid
+ *    engines and then set them up later as bonded engines.
+ *
+ *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
+ *    i915_gem_proto_engine::engine.
+ *
+ *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
+ *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
+ */
+struct i915_gem_proto_engine {
+	/** @type: Type of this engine */
+	enum i915_gem_engine_type type;
+
+	/** @engine: Engine, for physical */
+	struct intel_engine_cs *engine;
+
+	/** @num_siblings: Number of balanced siblings */
+	unsigned int num_siblings;
+
+	/** @siblings: Balanced siblings */
+	struct intel_engine_cs **siblings;
+
+	/** @sseu: Client-set SSEU parameters */
+	struct intel_sseu sseu;
+};
+
 /**
  * struct i915_gem_proto_context - prototype context
  *
@@ -84,6 +133,15 @@ struct i915_gem_proto_context {
 	/** @sched: See i915_gem_context::sched */
 	struct i915_sched_attr sched;
 
+	/** @num_user_engines: Number of user-specified engines or -1 */
+	int num_user_engines;
+
+	/** @user_engines: User-specified engines */
+	struct i915_gem_proto_engine *user_engines;
+
+	/** @sseu: Client-set SSEU parameters for the legacy RCS */
+	struct intel_sseu legacy_rcs_sseu;
+
 	/** @single_timeline: See See i915_gem_context::syncobj */
 	bool single_timeline;
 };
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 20/27] drm/i915/gem: Return an error ptr from context_lookup
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter, Jason Ekstrand

We're about to start doing lazy context creation which means contexts
get created in i915_gem_context_lookup and we may start having more
errors than -ENOENT.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c    | 12 ++++++------
 drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c |  4 ++--
 drivers/gpu/drm/i915/i915_drv.h                |  2 +-
 drivers/gpu/drm/i915/i915_perf.c               |  4 ++--
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index aa4edfbf7ed48..d84d704534128 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -2646,8 +2646,8 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 	int ret = 0;
 
 	ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
-	if (!ctx)
-		return -ENOENT;
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
 
 	switch (args->param) {
 	case I915_CONTEXT_PARAM_GTT_SIZE:
@@ -2715,8 +2715,8 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 	int ret;
 
 	ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
-	if (!ctx)
-		return -ENOENT;
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
 
 	ret = ctx_setparam(file_priv, ctx, args);
 
@@ -2735,8 +2735,8 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	ctx = i915_gem_context_lookup(file->driver_priv, args->ctx_id);
-	if (!ctx)
-		return -ENOENT;
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
 
 	/*
 	 * We opt for unserialised reads here. This may result in tearing
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index 7024adcd5cf15..de14b26f3b2d5 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -739,8 +739,8 @@ static int eb_select_context(struct i915_execbuffer *eb)
 	struct i915_gem_context *ctx;
 
 	ctx = i915_gem_context_lookup(eb->file->driver_priv, eb->args->rsvd1);
-	if (unlikely(!ctx))
-		return -ENOENT;
+	if (unlikely(IS_ERR(ctx)))
+		return PTR_ERR(ctx);
 
 	eb->gem_context = ctx;
 	if (rcu_access_pointer(ctx->vm))
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8571c5c1509a7..004ed0e59c999 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1851,7 +1851,7 @@ i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
 		ctx = NULL;
 	rcu_read_unlock();
 
-	return ctx;
+	return ctx ? ctx : ERR_PTR(-ENOENT);
 }
 
 /* i915_gem_evict.c */
diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index 85ad62dbabfab..b86ed03f6a705 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -3414,10 +3414,10 @@ i915_perf_open_ioctl_locked(struct i915_perf *perf,
 		struct drm_i915_file_private *file_priv = file->driver_priv;
 
 		specific_ctx = i915_gem_context_lookup(file_priv, ctx_handle);
-		if (!specific_ctx) {
+		if (IS_ERR(specific_ctx)) {
 			DRM_DEBUG("Failed to look up context with ID %u for opening perf stream\n",
 				  ctx_handle);
-			ret = -ENOENT;
+			ret = PTR_ERR(specific_ctx);
 			goto err;
 		}
 	}
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 20/27] drm/i915/gem: Return an error ptr from context_lookup
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter

We're about to start doing lazy context creation which means contexts
get created in i915_gem_context_lookup and we may start having more
errors than -ENOENT.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c    | 12 ++++++------
 drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c |  4 ++--
 drivers/gpu/drm/i915/i915_drv.h                |  2 +-
 drivers/gpu/drm/i915/i915_perf.c               |  4 ++--
 4 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index aa4edfbf7ed48..d84d704534128 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -2646,8 +2646,8 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
 	int ret = 0;
 
 	ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
-	if (!ctx)
-		return -ENOENT;
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
 
 	switch (args->param) {
 	case I915_CONTEXT_PARAM_GTT_SIZE:
@@ -2715,8 +2715,8 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 	int ret;
 
 	ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
-	if (!ctx)
-		return -ENOENT;
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
 
 	ret = ctx_setparam(file_priv, ctx, args);
 
@@ -2735,8 +2735,8 @@ int i915_gem_context_reset_stats_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	ctx = i915_gem_context_lookup(file->driver_priv, args->ctx_id);
-	if (!ctx)
-		return -ENOENT;
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
 
 	/*
 	 * We opt for unserialised reads here. This may result in tearing
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index 7024adcd5cf15..de14b26f3b2d5 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -739,8 +739,8 @@ static int eb_select_context(struct i915_execbuffer *eb)
 	struct i915_gem_context *ctx;
 
 	ctx = i915_gem_context_lookup(eb->file->driver_priv, eb->args->rsvd1);
-	if (unlikely(!ctx))
-		return -ENOENT;
+	if (unlikely(IS_ERR(ctx)))
+		return PTR_ERR(ctx);
 
 	eb->gem_context = ctx;
 	if (rcu_access_pointer(ctx->vm))
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8571c5c1509a7..004ed0e59c999 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1851,7 +1851,7 @@ i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
 		ctx = NULL;
 	rcu_read_unlock();
 
-	return ctx;
+	return ctx ? ctx : ERR_PTR(-ENOENT);
 }
 
 /* i915_gem_evict.c */
diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index 85ad62dbabfab..b86ed03f6a705 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -3414,10 +3414,10 @@ i915_perf_open_ioctl_locked(struct i915_perf *perf,
 		struct drm_i915_file_private *file_priv = file->driver_priv;
 
 		specific_ctx = i915_gem_context_lookup(file_priv, ctx_handle);
-		if (!specific_ctx) {
+		if (IS_ERR(specific_ctx)) {
 			DRM_DEBUG("Failed to look up context with ID %u for opening perf stream\n",
 				  ctx_handle);
-			ret = -ENOENT;
+			ret = PTR_ERR(specific_ctx);
 			goto err;
 		}
 	}
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 21/27] drm/i915/gt: Drop i915_address_space::file (v2)
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter, Jason Ekstrand

There's a big comment saying how useful it is but no one is using this
for anything anymore.

It was added in 2bfa996e031b ("drm/i915: Store owning file on the
i915_address_space") and used for debugfs at the time as well as telling
the difference between the global GTT and a PPGTT.  In f6e8aa387171
("drm/i915: Report the number of closed vma held by each context in
debugfs") we removed one use of it by switching to a context walk and
comparing with the VM in the context.  Finally, VM stats for debugfs
were entirely nuked in db80a1294c23 ("drm/i915/gem: Remove per-client
stats from debugfs/i915_gem_objects")

v2 (Daniel Vetter):
 - Delete a struct drm_i915_file_private pre-declaration
 - Add a comment to the commit message about history

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c |  9 ---------
 drivers/gpu/drm/i915/gt/intel_gtt.h         | 11 -----------
 drivers/gpu/drm/i915/selftests/mock_gtt.c   |  1 -
 3 files changed, 21 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index d84d704534128..06d413eef01a3 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1457,17 +1457,10 @@ static int gem_context_register(struct i915_gem_context *ctx,
 				u32 *id)
 {
 	struct drm_i915_private *i915 = ctx->i915;
-	struct i915_address_space *vm;
 	int ret;
 
 	ctx->file_priv = fpriv;
 
-	mutex_lock(&ctx->mutex);
-	vm = i915_gem_context_vm(ctx);
-	if (vm)
-		WRITE_ONCE(vm->file, fpriv); /* XXX */
-	mutex_unlock(&ctx->mutex);
-
 	ctx->pid = get_task_pid(current, PIDTYPE_PID);
 	snprintf(ctx->name, sizeof(ctx->name), "%s[%d]",
 		 current->comm, pid_nr(ctx->pid));
@@ -1566,8 +1559,6 @@ int i915_gem_vm_create_ioctl(struct drm_device *dev, void *data,
 	if (IS_ERR(ppgtt))
 		return PTR_ERR(ppgtt);
 
-	ppgtt->vm.file = file_priv;
-
 	if (args->extensions) {
 		err = i915_user_extensions(u64_to_user_ptr(args->extensions),
 					   NULL, 0,
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
index e67e34e179131..7e62932b1b12e 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
@@ -140,7 +140,6 @@ typedef u64 gen8_pte_t;
 
 enum i915_cache_level;
 
-struct drm_i915_file_private;
 struct drm_i915_gem_object;
 struct i915_fence_reg;
 struct i915_vma;
@@ -217,16 +216,6 @@ struct i915_address_space {
 	struct intel_gt *gt;
 	struct drm_i915_private *i915;
 	struct device *dma;
-	/*
-	 * Every address space belongs to a struct file - except for the global
-	 * GTT that is owned by the driver (and so @file is set to NULL). In
-	 * principle, no information should leak from one context to another
-	 * (or between files/processes etc) unless explicitly shared by the
-	 * owner. Tracking the owner is important in order to free up per-file
-	 * objects along with the file, to aide resource tracking, and to
-	 * assign blame.
-	 */
-	struct drm_i915_file_private *file;
 	u64 total;		/* size addr space maps (ex. 2GB for ggtt) */
 	u64 reserved;		/* size addr space reserved */
 
diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c
index 5c7ae40bba634..cc047ec594f93 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c
@@ -73,7 +73,6 @@ struct i915_ppgtt *mock_ppgtt(struct drm_i915_private *i915, const char *name)
 	ppgtt->vm.gt = &i915->gt;
 	ppgtt->vm.i915 = i915;
 	ppgtt->vm.total = round_down(U64_MAX, PAGE_SIZE);
-	ppgtt->vm.file = ERR_PTR(-ENODEV);
 	ppgtt->vm.dma = i915->drm.dev;
 
 	i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT);
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 21/27] drm/i915/gt: Drop i915_address_space::file (v2)
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Daniel Vetter

There's a big comment saying how useful it is but no one is using this
for anything anymore.

It was added in 2bfa996e031b ("drm/i915: Store owning file on the
i915_address_space") and used for debugfs at the time as well as telling
the difference between the global GTT and a PPGTT.  In f6e8aa387171
("drm/i915: Report the number of closed vma held by each context in
debugfs") we removed one use of it by switching to a context walk and
comparing with the VM in the context.  Finally, VM stats for debugfs
were entirely nuked in db80a1294c23 ("drm/i915/gem: Remove per-client
stats from debugfs/i915_gem_objects")

v2 (Daniel Vetter):
 - Delete a struct drm_i915_file_private pre-declaration
 - Add a comment to the commit message about history

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c |  9 ---------
 drivers/gpu/drm/i915/gt/intel_gtt.h         | 11 -----------
 drivers/gpu/drm/i915/selftests/mock_gtt.c   |  1 -
 3 files changed, 21 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index d84d704534128..06d413eef01a3 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1457,17 +1457,10 @@ static int gem_context_register(struct i915_gem_context *ctx,
 				u32 *id)
 {
 	struct drm_i915_private *i915 = ctx->i915;
-	struct i915_address_space *vm;
 	int ret;
 
 	ctx->file_priv = fpriv;
 
-	mutex_lock(&ctx->mutex);
-	vm = i915_gem_context_vm(ctx);
-	if (vm)
-		WRITE_ONCE(vm->file, fpriv); /* XXX */
-	mutex_unlock(&ctx->mutex);
-
 	ctx->pid = get_task_pid(current, PIDTYPE_PID);
 	snprintf(ctx->name, sizeof(ctx->name), "%s[%d]",
 		 current->comm, pid_nr(ctx->pid));
@@ -1566,8 +1559,6 @@ int i915_gem_vm_create_ioctl(struct drm_device *dev, void *data,
 	if (IS_ERR(ppgtt))
 		return PTR_ERR(ppgtt);
 
-	ppgtt->vm.file = file_priv;
-
 	if (args->extensions) {
 		err = i915_user_extensions(u64_to_user_ptr(args->extensions),
 					   NULL, 0,
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
index e67e34e179131..7e62932b1b12e 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
@@ -140,7 +140,6 @@ typedef u64 gen8_pte_t;
 
 enum i915_cache_level;
 
-struct drm_i915_file_private;
 struct drm_i915_gem_object;
 struct i915_fence_reg;
 struct i915_vma;
@@ -217,16 +216,6 @@ struct i915_address_space {
 	struct intel_gt *gt;
 	struct drm_i915_private *i915;
 	struct device *dma;
-	/*
-	 * Every address space belongs to a struct file - except for the global
-	 * GTT that is owned by the driver (and so @file is set to NULL). In
-	 * principle, no information should leak from one context to another
-	 * (or between files/processes etc) unless explicitly shared by the
-	 * owner. Tracking the owner is important in order to free up per-file
-	 * objects along with the file, to aide resource tracking, and to
-	 * assign blame.
-	 */
-	struct drm_i915_file_private *file;
 	u64 total;		/* size addr space maps (ex. 2GB for ggtt) */
 	u64 reserved;		/* size addr space reserved */
 
diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c
index 5c7ae40bba634..cc047ec594f93 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c
@@ -73,7 +73,6 @@ struct i915_ppgtt *mock_ppgtt(struct drm_i915_private *i915, const char *name)
 	ppgtt->vm.gt = &i915->gt;
 	ppgtt->vm.i915 = i915;
 	ppgtt->vm.total = round_down(U64_MAX, PAGE_SIZE);
-	ppgtt->vm.file = ERR_PTR(-ENODEV);
 	ppgtt->vm.dma = i915->drm.dev;
 
 	i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT);
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 22/27] drm/i915/gem: Delay context creation
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

The current context uAPI allows for two methods of setting context
parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
former is allowed to be called at any time while the later happens as
part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
settable via the other.  While some params are fairly simple and setting
them on a live context is harmless such the context priority, others are
far trickier such as the VM or the set of engines.  In order to swap out
the VM, for instance, we have to delay until all current in-flight work
is complete, swap in the new VM, and then continue.  This leads to a
plethora of potential race conditions we'd really rather avoid.

In previous patches, we added a i915_gem_proto_context struct which is
capable of storing and tracking all such create parameters.  This commit
delays the creation of the actual context until after the client is done
configuring it with SET_CONTEXT_PARAM.  From the perspective of the
client, it has the same u32 context ID the whole time.  From the
perspective of i915, however, it's an i915_gem_proto_context right up
until the point where we attempt to do something which the proto-context
can't handle at which point the real context gets created.

This is accomplished via a little xarray dance.  When GEM_CONTEXT_CREATE
is called, we create a proto-context, reserve a slot in context_xa but
leave it NULL, the proto-context in the corresponding slot in
proto_context_xa.  Then, whenever we go to look up a context, we first
check context_xa.  If it's there, we return the i915_gem_context and
we're done.  If it's not, we look in proto_context_xa and, if we find it
there, we create the actual context and kill the proto-context.

In order for this dance to work properly, everything which ever touches
a proto-context is guarded by drm_i915_file_private::proto_context_lock,
including context creation.  Yes, this means context creation now takes
a giant global lock but it can't really be helped and that should never
be on any driver's fast-path anyway.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 211 ++++++++++++++----
 drivers/gpu/drm/i915/gem/i915_gem_context.h   |   3 +
 .../gpu/drm/i915/gem/i915_gem_context_types.h |  54 +++++
 .../gpu/drm/i915/gem/selftests/mock_context.c |   5 +-
 drivers/gpu/drm/i915/i915_drv.h               |  24 +-
 5 files changed, 239 insertions(+), 58 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 06d413eef01a3..f0e7ce6b979b4 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -292,6 +292,42 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
 	return err;
 }
 
+static int proto_context_register_locked(struct drm_i915_file_private *fpriv,
+					 struct i915_gem_proto_context *pc,
+					 u32 *id)
+{
+	int ret;
+	void *old;
+
+	lockdep_assert_held(&fpriv->proto_context_lock);
+
+	ret = xa_alloc(&fpriv->context_xa, id, NULL, xa_limit_32b, GFP_KERNEL);
+	if (ret)
+		return ret;
+
+	old = xa_store(&fpriv->proto_context_xa, *id, pc, GFP_KERNEL);
+	if (xa_is_err(old)) {
+		xa_erase(&fpriv->context_xa, *id);
+		return xa_err(old);
+	}
+	GEM_BUG_ON(old);
+
+	return 0;
+}
+
+static int proto_context_register(struct drm_i915_file_private *fpriv,
+				  struct i915_gem_proto_context *pc,
+				  u32 *id)
+{
+	int ret;
+
+	mutex_lock(&fpriv->proto_context_lock);
+	ret = proto_context_register_locked(fpriv, pc, id);
+	mutex_unlock(&fpriv->proto_context_lock);
+
+	return ret;
+}
+
 static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
 			    struct i915_gem_proto_context *pc,
 			    const struct drm_i915_gem_context_param *args)
@@ -1452,12 +1488,12 @@ void i915_gem_init__contexts(struct drm_i915_private *i915)
 	init_contexts(&i915->gem.contexts);
 }
 
-static int gem_context_register(struct i915_gem_context *ctx,
-				struct drm_i915_file_private *fpriv,
-				u32 *id)
+static void gem_context_register(struct i915_gem_context *ctx,
+				 struct drm_i915_file_private *fpriv,
+				 u32 id)
 {
 	struct drm_i915_private *i915 = ctx->i915;
-	int ret;
+	void *old;
 
 	ctx->file_priv = fpriv;
 
@@ -1466,19 +1502,12 @@ static int gem_context_register(struct i915_gem_context *ctx,
 		 current->comm, pid_nr(ctx->pid));
 
 	/* And finally expose ourselves to userspace via the idr */
-	ret = xa_alloc(&fpriv->context_xa, id, ctx, xa_limit_32b, GFP_KERNEL);
-	if (ret)
-		goto err_pid;
+	old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL);
+	GEM_BUG_ON(old);
 
 	spin_lock(&i915->gem.contexts.lock);
 	list_add_tail(&ctx->link, &i915->gem.contexts.list);
 	spin_unlock(&i915->gem.contexts.lock);
-
-	return 0;
-
-err_pid:
-	put_pid(fetch_and_zero(&ctx->pid));
-	return ret;
 }
 
 int i915_gem_context_open(struct drm_i915_private *i915,
@@ -1488,9 +1517,12 @@ int i915_gem_context_open(struct drm_i915_private *i915,
 	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
 	int err;
-	u32 id;
 
-	xa_init_flags(&file_priv->context_xa, XA_FLAGS_ALLOC);
+	mutex_init(&file_priv->proto_context_lock);
+	xa_init_flags(&file_priv->proto_context_xa, XA_FLAGS_ALLOC);
+
+	/* 0 reserved for the default context */
+	xa_init_flags(&file_priv->context_xa, XA_FLAGS_ALLOC1);
 
 	/* 0 reserved for invalid/unassigned ppgtt */
 	xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
@@ -1508,28 +1540,31 @@ int i915_gem_context_open(struct drm_i915_private *i915,
 		goto err;
 	}
 
-	err = gem_context_register(ctx, file_priv, &id);
-	if (err < 0)
-		goto err_ctx;
+	gem_context_register(ctx, file_priv, 0);
 
-	GEM_BUG_ON(id);
 	return 0;
 
-err_ctx:
-	context_close(ctx);
 err:
 	xa_destroy(&file_priv->vm_xa);
 	xa_destroy(&file_priv->context_xa);
+	xa_destroy(&file_priv->proto_context_xa);
+	mutex_destroy(&file_priv->proto_context_lock);
 	return err;
 }
 
 void i915_gem_context_close(struct drm_file *file)
 {
 	struct drm_i915_file_private *file_priv = file->driver_priv;
+	struct i915_gem_proto_context *pc;
 	struct i915_address_space *vm;
 	struct i915_gem_context *ctx;
 	unsigned long idx;
 
+	xa_for_each(&file_priv->proto_context_xa, idx, pc)
+		proto_context_close(pc);
+	xa_destroy(&file_priv->proto_context_xa);
+	mutex_destroy(&file_priv->proto_context_lock);
+
 	xa_for_each(&file_priv->context_xa, idx, ctx)
 		context_close(ctx);
 	xa_destroy(&file_priv->context_xa);
@@ -2490,12 +2525,73 @@ static bool client_is_banned(struct drm_i915_file_private *file_priv)
 	return atomic_read(&file_priv->ban_score) >= I915_CLIENT_SCORE_BANNED;
 }
 
+static inline struct i915_gem_context *
+__context_lookup(struct drm_i915_file_private *file_priv, u32 id)
+{
+	struct i915_gem_context *ctx;
+
+	rcu_read_lock();
+	ctx = xa_load(&file_priv->context_xa, id);
+	if (ctx && !kref_get_unless_zero(&ctx->ref))
+		ctx = NULL;
+	rcu_read_unlock();
+
+	return ctx;
+}
+
+struct i915_gem_context *
+lazy_create_context_locked(struct drm_i915_file_private *file_priv,
+			   struct i915_gem_proto_context *pc, u32 id)
+{
+	struct i915_gem_context *ctx;
+	void *old;
+
+	lockdep_assert_held(&file_priv->proto_context_lock);
+
+	ctx = i915_gem_create_context(file_priv->dev_priv, pc);
+	if (IS_ERR(ctx))
+		return ctx;
+
+	gem_context_register(ctx, file_priv, id);
+
+	old = xa_erase(&file_priv->proto_context_xa, id);
+	GEM_BUG_ON(old != pc);
+	proto_context_close(pc);
+
+	/* One for the xarray and one for the caller */
+	return i915_gem_context_get(ctx);
+}
+
+struct i915_gem_context *
+i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
+{
+	struct i915_gem_proto_context *pc;
+	struct i915_gem_context *ctx;
+
+	ctx = __context_lookup(file_priv, id);
+	if (ctx)
+		return ctx;
+
+	mutex_lock(&file_priv->proto_context_lock);
+	/* Try one more time under the lock */
+	ctx = __context_lookup(file_priv, id);
+	if (!ctx) {
+		pc = xa_load(&file_priv->proto_context_xa, id);
+		if (!pc)
+			ctx = ERR_PTR(-ENOENT);
+		else
+			ctx = lazy_create_context_locked(file_priv, pc, id);
+	}
+	mutex_unlock(&file_priv->proto_context_lock);
+
+	return ctx;
+}
+
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 				  struct drm_file *file)
 {
 	struct drm_i915_private *i915 = to_i915(dev);
 	struct drm_i915_gem_context_create_ext *args = data;
-	struct i915_gem_context *ctx;
 	struct create_ext ext_data;
 	int ret;
 	u32 id;
@@ -2527,28 +2623,21 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 					   create_extensions,
 					   ARRAY_SIZE(create_extensions),
 					   &ext_data);
-		if (ret) {
-			proto_context_close(ext_data.pc);
-			return ret;
-		}
+		if (ret)
+			goto err_pc;
 	}
 
-	ctx = i915_gem_create_context(i915, ext_data.pc);
-	proto_context_close(ext_data.pc);
-	if (IS_ERR(ctx))
-		return PTR_ERR(ctx);
-
-	ret = gem_context_register(ctx, ext_data.fpriv, &id);
+	ret = proto_context_register(ext_data.fpriv, ext_data.pc, &id);
 	if (ret < 0)
-		goto err_ctx;
+		goto err_pc;
 
 	args->ctx_id = id;
 	drm_dbg(&i915->drm, "HW context %d created\n", args->ctx_id);
 
 	return 0;
 
-err_ctx:
-	context_close(ctx);
+err_pc:
+	proto_context_close(ext_data.pc);
 	return ret;
 }
 
@@ -2557,6 +2646,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_i915_gem_context_destroy *args = data;
 	struct drm_i915_file_private *file_priv = file->driver_priv;
+	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
 
 	if (args->pad != 0)
@@ -2565,11 +2655,21 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 	if (!args->ctx_id)
 		return -ENOENT;
 
+	mutex_lock(&file_priv->proto_context_lock);
 	ctx = xa_erase(&file_priv->context_xa, args->ctx_id);
-	if (!ctx)
+	pc = xa_erase(&file_priv->proto_context_xa, args->ctx_id);
+	mutex_unlock(&file_priv->proto_context_lock);
+
+	if (!ctx && !pc)
 		return -ENOENT;
+	GEM_WARN_ON(ctx && pc);
+
+	if (pc)
+		proto_context_close(pc);
+
+	if (ctx)
+		context_close(ctx);
 
-	context_close(ctx);
 	return 0;
 }
 
@@ -2702,16 +2802,41 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_i915_file_private *file_priv = file->driver_priv;
 	struct drm_i915_gem_context_param *args = data;
+	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
-	int ret;
+	int ret = 0;
 
-	ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
-	if (IS_ERR(ctx))
-		return PTR_ERR(ctx);
+	ctx = __context_lookup(file_priv, args->ctx_id);
+	if (ctx)
+		goto set_ctx_param;
 
-	ret = ctx_setparam(file_priv, ctx, args);
+	mutex_lock(&file_priv->proto_context_lock);
+	ctx = __context_lookup(file_priv, args->ctx_id);
+	if (ctx)
+		goto unlock;
+
+	pc = xa_load(&file_priv->proto_context_xa, args->ctx_id);
+	if (!pc) {
+		ret = -ENOENT;
+		goto unlock;
+	}
+
+	/* FIXME: We should consider disallowing SET_CONTEXT_PARAM for most
+	 * things on future platforms.  Clients should be using
+	 * CONTEXT_CREATE_EXT_PARAM instead.
+	 */
+	ret = set_proto_ctx_param(file_priv, pc, args);
+
+unlock:
+	mutex_unlock(&file_priv->proto_context_lock);
+
+set_ctx_param:
+	if (!ret && ctx)
+		ret = ctx_setparam(file_priv, ctx, args);
+
+	if (ctx)
+		i915_gem_context_put(ctx);
 
-	i915_gem_context_put(ctx);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.h b/drivers/gpu/drm/i915/gem/i915_gem_context.h
index b5c908f3f4f22..20411db84914a 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.h
@@ -133,6 +133,9 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 int i915_gem_context_reset_stats_ioctl(struct drm_device *dev, void *data,
 				       struct drm_file *file);
 
+struct i915_gem_context *
+i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id);
+
 static inline struct i915_gem_context *
 i915_gem_context_get(struct i915_gem_context *ctx)
 {
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 2ac341f805c8f..b673061f4f5ba 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -122,6 +122,60 @@ struct i915_gem_proto_engine {
  * an i915_gem_context.  This is used to gather parameters provided either
  * through creation flags or via SET_CONTEXT_PARAM so that, when we create
  * the final i915_gem_context, those parameters can be immutable.
+ *
+ * The context uAPI allows for two methods of setting context parameters:
+ * SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The former is
+ * allowed to be called at any time while the later happens as part of
+ * GEM_CONTEXT_CREATE.  When these were initially added, Currently,
+ * everything settable via one is settable via the other.  While some
+ * params are fairly simple and setting them on a live context is harmless
+ * such the context priority, others are far trickier such as the VM or the
+ * set of engines.  To avoid some truly nasty race conditions, we don't
+ * allow setting the VM or the set of engines on live contexts.
+ *
+ * The way we dealt with this without breaking older userspace that sets
+ * the VM or engine set via SET_CONTEXT_PARAM is to delay the creation of
+ * the actual context until after the client is done configuring it with
+ * SET_CONTEXT_PARAM.  From the perspective of the client, it has the same
+ * u32 context ID the whole time.  From the perspective of i915, however,
+ * it's an i915_gem_proto_context right up until the point where we attempt
+ * to do something which the proto-context can't handle at which point the
+ * real context gets created.
+ *
+ * This is accomplished via a little xarray dance.  When GEM_CONTEXT_CREATE
+ * is called, we create a proto-context, reserve a slot in context_xa but
+ * leave it NULL, the proto-context in the corresponding slot in
+ * proto_context_xa.  Then, whenever we go to look up a context, we first
+ * check context_xa.  If it's there, we return the i915_gem_context and
+ * we're done.  If it's not, we look in proto_context_xa and, if we find it
+ * there, we create the actual context and kill the proto-context.
+ *
+ * At the time we made this change (April, 2021), we did a fairly complete
+ * audit of existing userspace to ensure this wouldn't break anything:
+ *
+ *  - Mesa/i965 didn't use the engines or VM APIs at all
+ *
+ *  - Mesa/ANV used the engines API but via CONTEXT_CREATE_EXT_SETPARAM and
+ *    didn't use the VM API.
+ *
+ *  - Mesa/iris didn't use the engines or VM APIs at all
+ *
+ *  - The open-source compute-runtime didn't yet use the engines API but
+ *    did use the VM API via SET_CONTEXT_PARAM.  However, CONTEXT_SETPARAM
+ *    was always the second ioctl on that context, immediately following
+ *    GEM_CONTEXT_CREATE.
+ *
+ *  - The media driver sets engines and bonding/balancing via
+ *    SET_CONTEXT_PARAM.  However, CONTEXT_SETPARAM to set the VM was
+ *    always the second ioctl on that context, immediately following
+ *    GEM_CONTEXT_CREATE and setting engines immediately followed that.
+ *
+ * In order for this dance to work properly, any modification to an
+ * i915_gem_proto_context that is exposed to the client via
+ * drm_i915_file_private::proto_context_xa must be guarded by
+ * drm_i915_file_private::proto_context_lock.  The exception is when a
+ * proto-context has not yet been exposed such as when handling
+ * CONTEXT_CREATE_SET_PARAM during GEM_CONTEXT_CREATE.
  */
 struct i915_gem_proto_context {
 	/** @vm: See i915_gem_context::vm */
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index cbeefd060e97b..61aaac4a334cf 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -81,6 +81,7 @@ void mock_init_contexts(struct drm_i915_private *i915)
 struct i915_gem_context *
 live_context(struct drm_i915_private *i915, struct file *file)
 {
+	struct drm_i915_file_private *fpriv = to_drm_file(file)->driver_priv;
 	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
 	int err;
@@ -97,10 +98,12 @@ live_context(struct drm_i915_private *i915, struct file *file)
 
 	i915_gem_context_set_no_error_capture(ctx);
 
-	err = gem_context_register(ctx, to_drm_file(file)->driver_priv, &id);
+	err = xa_alloc(&fpriv->context_xa, &id, NULL, xa_limit_32b, GFP_KERNEL);
 	if (err < 0)
 		goto err_ctx;
 
+	gem_context_register(ctx, fpriv, id);
+
 	return ctx;
 
 err_ctx:
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 004ed0e59c999..2b323b986dbab 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -200,6 +200,16 @@ struct drm_i915_file_private {
 		struct rcu_head rcu;
 	};
 
+	/** @proto_context_lock: Guards all i915_gem_proto_context operations
+	 *
+	 * See i915_gem_proto_context.
+	 */
+	struct mutex proto_context_lock;
+
+	/** @proto_context_xa: xarray of i915_gem_proto_context */
+	struct xarray proto_context_xa;
+
+	/** @context_xa: xarray of fully created i915_gem_context */
 	struct xarray context_xa;
 	struct xarray vm_xa;
 
@@ -1840,20 +1850,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
 
 struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags);
 
-static inline struct i915_gem_context *
-i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
-{
-	struct i915_gem_context *ctx;
-
-	rcu_read_lock();
-	ctx = xa_load(&file_priv->context_xa, id);
-	if (ctx && !kref_get_unless_zero(&ctx->ref))
-		ctx = NULL;
-	rcu_read_unlock();
-
-	return ctx ? ctx : ERR_PTR(-ENOENT);
-}
-
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct i915_address_space *vm,
 					  u64 min_size, u64 alignment,
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 22/27] drm/i915/gem: Delay context creation
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

The current context uAPI allows for two methods of setting context
parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
former is allowed to be called at any time while the later happens as
part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
settable via the other.  While some params are fairly simple and setting
them on a live context is harmless such the context priority, others are
far trickier such as the VM or the set of engines.  In order to swap out
the VM, for instance, we have to delay until all current in-flight work
is complete, swap in the new VM, and then continue.  This leads to a
plethora of potential race conditions we'd really rather avoid.

In previous patches, we added a i915_gem_proto_context struct which is
capable of storing and tracking all such create parameters.  This commit
delays the creation of the actual context until after the client is done
configuring it with SET_CONTEXT_PARAM.  From the perspective of the
client, it has the same u32 context ID the whole time.  From the
perspective of i915, however, it's an i915_gem_proto_context right up
until the point where we attempt to do something which the proto-context
can't handle at which point the real context gets created.

This is accomplished via a little xarray dance.  When GEM_CONTEXT_CREATE
is called, we create a proto-context, reserve a slot in context_xa but
leave it NULL, the proto-context in the corresponding slot in
proto_context_xa.  Then, whenever we go to look up a context, we first
check context_xa.  If it's there, we return the i915_gem_context and
we're done.  If it's not, we look in proto_context_xa and, if we find it
there, we create the actual context and kill the proto-context.

In order for this dance to work properly, everything which ever touches
a proto-context is guarded by drm_i915_file_private::proto_context_lock,
including context creation.  Yes, this means context creation now takes
a giant global lock but it can't really be helped and that should never
be on any driver's fast-path anyway.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 211 ++++++++++++++----
 drivers/gpu/drm/i915/gem/i915_gem_context.h   |   3 +
 .../gpu/drm/i915/gem/i915_gem_context_types.h |  54 +++++
 .../gpu/drm/i915/gem/selftests/mock_context.c |   5 +-
 drivers/gpu/drm/i915/i915_drv.h               |  24 +-
 5 files changed, 239 insertions(+), 58 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 06d413eef01a3..f0e7ce6b979b4 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -292,6 +292,42 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
 	return err;
 }
 
+static int proto_context_register_locked(struct drm_i915_file_private *fpriv,
+					 struct i915_gem_proto_context *pc,
+					 u32 *id)
+{
+	int ret;
+	void *old;
+
+	lockdep_assert_held(&fpriv->proto_context_lock);
+
+	ret = xa_alloc(&fpriv->context_xa, id, NULL, xa_limit_32b, GFP_KERNEL);
+	if (ret)
+		return ret;
+
+	old = xa_store(&fpriv->proto_context_xa, *id, pc, GFP_KERNEL);
+	if (xa_is_err(old)) {
+		xa_erase(&fpriv->context_xa, *id);
+		return xa_err(old);
+	}
+	GEM_BUG_ON(old);
+
+	return 0;
+}
+
+static int proto_context_register(struct drm_i915_file_private *fpriv,
+				  struct i915_gem_proto_context *pc,
+				  u32 *id)
+{
+	int ret;
+
+	mutex_lock(&fpriv->proto_context_lock);
+	ret = proto_context_register_locked(fpriv, pc, id);
+	mutex_unlock(&fpriv->proto_context_lock);
+
+	return ret;
+}
+
 static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
 			    struct i915_gem_proto_context *pc,
 			    const struct drm_i915_gem_context_param *args)
@@ -1452,12 +1488,12 @@ void i915_gem_init__contexts(struct drm_i915_private *i915)
 	init_contexts(&i915->gem.contexts);
 }
 
-static int gem_context_register(struct i915_gem_context *ctx,
-				struct drm_i915_file_private *fpriv,
-				u32 *id)
+static void gem_context_register(struct i915_gem_context *ctx,
+				 struct drm_i915_file_private *fpriv,
+				 u32 id)
 {
 	struct drm_i915_private *i915 = ctx->i915;
-	int ret;
+	void *old;
 
 	ctx->file_priv = fpriv;
 
@@ -1466,19 +1502,12 @@ static int gem_context_register(struct i915_gem_context *ctx,
 		 current->comm, pid_nr(ctx->pid));
 
 	/* And finally expose ourselves to userspace via the idr */
-	ret = xa_alloc(&fpriv->context_xa, id, ctx, xa_limit_32b, GFP_KERNEL);
-	if (ret)
-		goto err_pid;
+	old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL);
+	GEM_BUG_ON(old);
 
 	spin_lock(&i915->gem.contexts.lock);
 	list_add_tail(&ctx->link, &i915->gem.contexts.list);
 	spin_unlock(&i915->gem.contexts.lock);
-
-	return 0;
-
-err_pid:
-	put_pid(fetch_and_zero(&ctx->pid));
-	return ret;
 }
 
 int i915_gem_context_open(struct drm_i915_private *i915,
@@ -1488,9 +1517,12 @@ int i915_gem_context_open(struct drm_i915_private *i915,
 	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
 	int err;
-	u32 id;
 
-	xa_init_flags(&file_priv->context_xa, XA_FLAGS_ALLOC);
+	mutex_init(&file_priv->proto_context_lock);
+	xa_init_flags(&file_priv->proto_context_xa, XA_FLAGS_ALLOC);
+
+	/* 0 reserved for the default context */
+	xa_init_flags(&file_priv->context_xa, XA_FLAGS_ALLOC1);
 
 	/* 0 reserved for invalid/unassigned ppgtt */
 	xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
@@ -1508,28 +1540,31 @@ int i915_gem_context_open(struct drm_i915_private *i915,
 		goto err;
 	}
 
-	err = gem_context_register(ctx, file_priv, &id);
-	if (err < 0)
-		goto err_ctx;
+	gem_context_register(ctx, file_priv, 0);
 
-	GEM_BUG_ON(id);
 	return 0;
 
-err_ctx:
-	context_close(ctx);
 err:
 	xa_destroy(&file_priv->vm_xa);
 	xa_destroy(&file_priv->context_xa);
+	xa_destroy(&file_priv->proto_context_xa);
+	mutex_destroy(&file_priv->proto_context_lock);
 	return err;
 }
 
 void i915_gem_context_close(struct drm_file *file)
 {
 	struct drm_i915_file_private *file_priv = file->driver_priv;
+	struct i915_gem_proto_context *pc;
 	struct i915_address_space *vm;
 	struct i915_gem_context *ctx;
 	unsigned long idx;
 
+	xa_for_each(&file_priv->proto_context_xa, idx, pc)
+		proto_context_close(pc);
+	xa_destroy(&file_priv->proto_context_xa);
+	mutex_destroy(&file_priv->proto_context_lock);
+
 	xa_for_each(&file_priv->context_xa, idx, ctx)
 		context_close(ctx);
 	xa_destroy(&file_priv->context_xa);
@@ -2490,12 +2525,73 @@ static bool client_is_banned(struct drm_i915_file_private *file_priv)
 	return atomic_read(&file_priv->ban_score) >= I915_CLIENT_SCORE_BANNED;
 }
 
+static inline struct i915_gem_context *
+__context_lookup(struct drm_i915_file_private *file_priv, u32 id)
+{
+	struct i915_gem_context *ctx;
+
+	rcu_read_lock();
+	ctx = xa_load(&file_priv->context_xa, id);
+	if (ctx && !kref_get_unless_zero(&ctx->ref))
+		ctx = NULL;
+	rcu_read_unlock();
+
+	return ctx;
+}
+
+struct i915_gem_context *
+lazy_create_context_locked(struct drm_i915_file_private *file_priv,
+			   struct i915_gem_proto_context *pc, u32 id)
+{
+	struct i915_gem_context *ctx;
+	void *old;
+
+	lockdep_assert_held(&file_priv->proto_context_lock);
+
+	ctx = i915_gem_create_context(file_priv->dev_priv, pc);
+	if (IS_ERR(ctx))
+		return ctx;
+
+	gem_context_register(ctx, file_priv, id);
+
+	old = xa_erase(&file_priv->proto_context_xa, id);
+	GEM_BUG_ON(old != pc);
+	proto_context_close(pc);
+
+	/* One for the xarray and one for the caller */
+	return i915_gem_context_get(ctx);
+}
+
+struct i915_gem_context *
+i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
+{
+	struct i915_gem_proto_context *pc;
+	struct i915_gem_context *ctx;
+
+	ctx = __context_lookup(file_priv, id);
+	if (ctx)
+		return ctx;
+
+	mutex_lock(&file_priv->proto_context_lock);
+	/* Try one more time under the lock */
+	ctx = __context_lookup(file_priv, id);
+	if (!ctx) {
+		pc = xa_load(&file_priv->proto_context_xa, id);
+		if (!pc)
+			ctx = ERR_PTR(-ENOENT);
+		else
+			ctx = lazy_create_context_locked(file_priv, pc, id);
+	}
+	mutex_unlock(&file_priv->proto_context_lock);
+
+	return ctx;
+}
+
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 				  struct drm_file *file)
 {
 	struct drm_i915_private *i915 = to_i915(dev);
 	struct drm_i915_gem_context_create_ext *args = data;
-	struct i915_gem_context *ctx;
 	struct create_ext ext_data;
 	int ret;
 	u32 id;
@@ -2527,28 +2623,21 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
 					   create_extensions,
 					   ARRAY_SIZE(create_extensions),
 					   &ext_data);
-		if (ret) {
-			proto_context_close(ext_data.pc);
-			return ret;
-		}
+		if (ret)
+			goto err_pc;
 	}
 
-	ctx = i915_gem_create_context(i915, ext_data.pc);
-	proto_context_close(ext_data.pc);
-	if (IS_ERR(ctx))
-		return PTR_ERR(ctx);
-
-	ret = gem_context_register(ctx, ext_data.fpriv, &id);
+	ret = proto_context_register(ext_data.fpriv, ext_data.pc, &id);
 	if (ret < 0)
-		goto err_ctx;
+		goto err_pc;
 
 	args->ctx_id = id;
 	drm_dbg(&i915->drm, "HW context %d created\n", args->ctx_id);
 
 	return 0;
 
-err_ctx:
-	context_close(ctx);
+err_pc:
+	proto_context_close(ext_data.pc);
 	return ret;
 }
 
@@ -2557,6 +2646,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_i915_gem_context_destroy *args = data;
 	struct drm_i915_file_private *file_priv = file->driver_priv;
+	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
 
 	if (args->pad != 0)
@@ -2565,11 +2655,21 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 	if (!args->ctx_id)
 		return -ENOENT;
 
+	mutex_lock(&file_priv->proto_context_lock);
 	ctx = xa_erase(&file_priv->context_xa, args->ctx_id);
-	if (!ctx)
+	pc = xa_erase(&file_priv->proto_context_xa, args->ctx_id);
+	mutex_unlock(&file_priv->proto_context_lock);
+
+	if (!ctx && !pc)
 		return -ENOENT;
+	GEM_WARN_ON(ctx && pc);
+
+	if (pc)
+		proto_context_close(pc);
+
+	if (ctx)
+		context_close(ctx);
 
-	context_close(ctx);
 	return 0;
 }
 
@@ -2702,16 +2802,41 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 {
 	struct drm_i915_file_private *file_priv = file->driver_priv;
 	struct drm_i915_gem_context_param *args = data;
+	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
-	int ret;
+	int ret = 0;
 
-	ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
-	if (IS_ERR(ctx))
-		return PTR_ERR(ctx);
+	ctx = __context_lookup(file_priv, args->ctx_id);
+	if (ctx)
+		goto set_ctx_param;
 
-	ret = ctx_setparam(file_priv, ctx, args);
+	mutex_lock(&file_priv->proto_context_lock);
+	ctx = __context_lookup(file_priv, args->ctx_id);
+	if (ctx)
+		goto unlock;
+
+	pc = xa_load(&file_priv->proto_context_xa, args->ctx_id);
+	if (!pc) {
+		ret = -ENOENT;
+		goto unlock;
+	}
+
+	/* FIXME: We should consider disallowing SET_CONTEXT_PARAM for most
+	 * things on future platforms.  Clients should be using
+	 * CONTEXT_CREATE_EXT_PARAM instead.
+	 */
+	ret = set_proto_ctx_param(file_priv, pc, args);
+
+unlock:
+	mutex_unlock(&file_priv->proto_context_lock);
+
+set_ctx_param:
+	if (!ret && ctx)
+		ret = ctx_setparam(file_priv, ctx, args);
+
+	if (ctx)
+		i915_gem_context_put(ctx);
 
-	i915_gem_context_put(ctx);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.h b/drivers/gpu/drm/i915/gem/i915_gem_context.h
index b5c908f3f4f22..20411db84914a 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.h
@@ -133,6 +133,9 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 int i915_gem_context_reset_stats_ioctl(struct drm_device *dev, void *data,
 				       struct drm_file *file);
 
+struct i915_gem_context *
+i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id);
+
 static inline struct i915_gem_context *
 i915_gem_context_get(struct i915_gem_context *ctx)
 {
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index 2ac341f805c8f..b673061f4f5ba 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -122,6 +122,60 @@ struct i915_gem_proto_engine {
  * an i915_gem_context.  This is used to gather parameters provided either
  * through creation flags or via SET_CONTEXT_PARAM so that, when we create
  * the final i915_gem_context, those parameters can be immutable.
+ *
+ * The context uAPI allows for two methods of setting context parameters:
+ * SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The former is
+ * allowed to be called at any time while the later happens as part of
+ * GEM_CONTEXT_CREATE.  When these were initially added, Currently,
+ * everything settable via one is settable via the other.  While some
+ * params are fairly simple and setting them on a live context is harmless
+ * such the context priority, others are far trickier such as the VM or the
+ * set of engines.  To avoid some truly nasty race conditions, we don't
+ * allow setting the VM or the set of engines on live contexts.
+ *
+ * The way we dealt with this without breaking older userspace that sets
+ * the VM or engine set via SET_CONTEXT_PARAM is to delay the creation of
+ * the actual context until after the client is done configuring it with
+ * SET_CONTEXT_PARAM.  From the perspective of the client, it has the same
+ * u32 context ID the whole time.  From the perspective of i915, however,
+ * it's an i915_gem_proto_context right up until the point where we attempt
+ * to do something which the proto-context can't handle at which point the
+ * real context gets created.
+ *
+ * This is accomplished via a little xarray dance.  When GEM_CONTEXT_CREATE
+ * is called, we create a proto-context, reserve a slot in context_xa but
+ * leave it NULL, the proto-context in the corresponding slot in
+ * proto_context_xa.  Then, whenever we go to look up a context, we first
+ * check context_xa.  If it's there, we return the i915_gem_context and
+ * we're done.  If it's not, we look in proto_context_xa and, if we find it
+ * there, we create the actual context and kill the proto-context.
+ *
+ * At the time we made this change (April, 2021), we did a fairly complete
+ * audit of existing userspace to ensure this wouldn't break anything:
+ *
+ *  - Mesa/i965 didn't use the engines or VM APIs at all
+ *
+ *  - Mesa/ANV used the engines API but via CONTEXT_CREATE_EXT_SETPARAM and
+ *    didn't use the VM API.
+ *
+ *  - Mesa/iris didn't use the engines or VM APIs at all
+ *
+ *  - The open-source compute-runtime didn't yet use the engines API but
+ *    did use the VM API via SET_CONTEXT_PARAM.  However, CONTEXT_SETPARAM
+ *    was always the second ioctl on that context, immediately following
+ *    GEM_CONTEXT_CREATE.
+ *
+ *  - The media driver sets engines and bonding/balancing via
+ *    SET_CONTEXT_PARAM.  However, CONTEXT_SETPARAM to set the VM was
+ *    always the second ioctl on that context, immediately following
+ *    GEM_CONTEXT_CREATE and setting engines immediately followed that.
+ *
+ * In order for this dance to work properly, any modification to an
+ * i915_gem_proto_context that is exposed to the client via
+ * drm_i915_file_private::proto_context_xa must be guarded by
+ * drm_i915_file_private::proto_context_lock.  The exception is when a
+ * proto-context has not yet been exposed such as when handling
+ * CONTEXT_CREATE_SET_PARAM during GEM_CONTEXT_CREATE.
  */
 struct i915_gem_proto_context {
 	/** @vm: See i915_gem_context::vm */
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index cbeefd060e97b..61aaac4a334cf 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -81,6 +81,7 @@ void mock_init_contexts(struct drm_i915_private *i915)
 struct i915_gem_context *
 live_context(struct drm_i915_private *i915, struct file *file)
 {
+	struct drm_i915_file_private *fpriv = to_drm_file(file)->driver_priv;
 	struct i915_gem_proto_context *pc;
 	struct i915_gem_context *ctx;
 	int err;
@@ -97,10 +98,12 @@ live_context(struct drm_i915_private *i915, struct file *file)
 
 	i915_gem_context_set_no_error_capture(ctx);
 
-	err = gem_context_register(ctx, to_drm_file(file)->driver_priv, &id);
+	err = xa_alloc(&fpriv->context_xa, &id, NULL, xa_limit_32b, GFP_KERNEL);
 	if (err < 0)
 		goto err_ctx;
 
+	gem_context_register(ctx, fpriv, id);
+
 	return ctx;
 
 err_ctx:
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 004ed0e59c999..2b323b986dbab 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -200,6 +200,16 @@ struct drm_i915_file_private {
 		struct rcu_head rcu;
 	};
 
+	/** @proto_context_lock: Guards all i915_gem_proto_context operations
+	 *
+	 * See i915_gem_proto_context.
+	 */
+	struct mutex proto_context_lock;
+
+	/** @proto_context_xa: xarray of i915_gem_proto_context */
+	struct xarray proto_context_xa;
+
+	/** @context_xa: xarray of fully created i915_gem_context */
 	struct xarray context_xa;
 	struct xarray vm_xa;
 
@@ -1840,20 +1850,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
 
 struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags);
 
-static inline struct i915_gem_context *
-i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
-{
-	struct i915_gem_context *ctx;
-
-	rcu_read_lock();
-	ctx = xa_load(&file_priv->context_xa, id);
-	if (ctx && !kref_get_unless_zero(&ctx->ref))
-		ctx = NULL;
-	rcu_read_unlock();
-
-	return ctx ? ctx : ERR_PTR(-ENOENT);
-}
-
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct i915_address_space *vm,
 					  u64 min_size, u64 alignment,
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 267 ------------------
 .../gpu/drm/i915/gem/i915_gem_context_types.h |   2 +-
 .../drm/i915/gem/selftests/i915_gem_context.c | 119 --------
 .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
 4 files changed, 1 insertion(+), 388 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index f0e7ce6b979b4..ad6e98d8a4fbd 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1637,121 +1637,6 @@ int i915_gem_vm_destroy_ioctl(struct drm_device *dev, void *data,
 	return 0;
 }
 
-struct context_barrier_task {
-	struct i915_active base;
-	void (*task)(void *data);
-	void *data;
-};
-
-__i915_active_call
-static void cb_retire(struct i915_active *base)
-{
-	struct context_barrier_task *cb = container_of(base, typeof(*cb), base);
-
-	if (cb->task)
-		cb->task(cb->data);
-
-	i915_active_fini(&cb->base);
-	kfree(cb);
-}
-
-I915_SELFTEST_DECLARE(static intel_engine_mask_t context_barrier_inject_fault);
-static int context_barrier_task(struct i915_gem_context *ctx,
-				intel_engine_mask_t engines,
-				bool (*skip)(struct intel_context *ce, void *data),
-				int (*pin)(struct intel_context *ce, struct i915_gem_ww_ctx *ww, void *data),
-				int (*emit)(struct i915_request *rq, void *data),
-				void (*task)(void *data),
-				void *data)
-{
-	struct context_barrier_task *cb;
-	struct i915_gem_engines_iter it;
-	struct i915_gem_engines *e;
-	struct i915_gem_ww_ctx ww;
-	struct intel_context *ce;
-	int err = 0;
-
-	GEM_BUG_ON(!task);
-
-	cb = kmalloc(sizeof(*cb), GFP_KERNEL);
-	if (!cb)
-		return -ENOMEM;
-
-	i915_active_init(&cb->base, NULL, cb_retire);
-	err = i915_active_acquire(&cb->base);
-	if (err) {
-		kfree(cb);
-		return err;
-	}
-
-	e = __context_engines_await(ctx, NULL);
-	if (!e) {
-		i915_active_release(&cb->base);
-		return -ENOENT;
-	}
-
-	for_each_gem_engine(ce, e, it) {
-		struct i915_request *rq;
-
-		if (I915_SELFTEST_ONLY(context_barrier_inject_fault &
-				       ce->engine->mask)) {
-			err = -ENXIO;
-			break;
-		}
-
-		if (!(ce->engine->mask & engines))
-			continue;
-
-		if (skip && skip(ce, data))
-			continue;
-
-		i915_gem_ww_ctx_init(&ww, true);
-retry:
-		err = intel_context_pin_ww(ce, &ww);
-		if (err)
-			goto err;
-
-		if (pin)
-			err = pin(ce, &ww, data);
-		if (err)
-			goto err_unpin;
-
-		rq = i915_request_create(ce);
-		if (IS_ERR(rq)) {
-			err = PTR_ERR(rq);
-			goto err_unpin;
-		}
-
-		err = 0;
-		if (emit)
-			err = emit(rq, data);
-		if (err == 0)
-			err = i915_active_add_request(&cb->base, rq);
-
-		i915_request_add(rq);
-err_unpin:
-		intel_context_unpin(ce);
-err:
-		if (err == -EDEADLK) {
-			err = i915_gem_ww_ctx_backoff(&ww);
-			if (!err)
-				goto retry;
-		}
-		i915_gem_ww_ctx_fini(&ww);
-
-		if (err)
-			break;
-	}
-	i915_sw_fence_complete(&e->fence);
-
-	cb->task = err ? NULL : task; /* caller needs to unwind instead */
-	cb->data = data;
-
-	i915_active_release(&cb->base);
-
-	return err;
-}
-
 static int get_ppgtt(struct drm_i915_file_private *file_priv,
 		     struct i915_gem_context *ctx,
 		     struct drm_i915_gem_context_param *args)
@@ -1784,154 +1669,6 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
 	return err;
 }
 
-static void set_ppgtt_barrier(void *data)
-{
-	struct i915_address_space *old = data;
-
-	if (INTEL_GEN(old->i915) < 8)
-		gen6_ppgtt_unpin_all(i915_vm_to_ppgtt(old));
-
-	i915_vm_close(old);
-}
-
-static int pin_ppgtt_update(struct intel_context *ce, struct i915_gem_ww_ctx *ww, void *data)
-{
-	struct i915_address_space *vm = ce->vm;
-
-	if (!HAS_LOGICAL_RING_CONTEXTS(vm->i915))
-		/* ppGTT is not part of the legacy context image */
-		return gen6_ppgtt_pin(i915_vm_to_ppgtt(vm), ww);
-
-	return 0;
-}
-
-static int emit_ppgtt_update(struct i915_request *rq, void *data)
-{
-	struct i915_address_space *vm = rq->context->vm;
-	struct intel_engine_cs *engine = rq->engine;
-	u32 base = engine->mmio_base;
-	u32 *cs;
-	int i;
-
-	if (i915_vm_is_4lvl(vm)) {
-		struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
-		const dma_addr_t pd_daddr = px_dma(ppgtt->pd);
-
-		cs = intel_ring_begin(rq, 6);
-		if (IS_ERR(cs))
-			return PTR_ERR(cs);
-
-		*cs++ = MI_LOAD_REGISTER_IMM(2);
-
-		*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(base, 0));
-		*cs++ = upper_32_bits(pd_daddr);
-		*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(base, 0));
-		*cs++ = lower_32_bits(pd_daddr);
-
-		*cs++ = MI_NOOP;
-		intel_ring_advance(rq, cs);
-	} else if (HAS_LOGICAL_RING_CONTEXTS(engine->i915)) {
-		struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
-		int err;
-
-		/* Magic required to prevent forcewake errors! */
-		err = engine->emit_flush(rq, EMIT_INVALIDATE);
-		if (err)
-			return err;
-
-		cs = intel_ring_begin(rq, 4 * GEN8_3LVL_PDPES + 2);
-		if (IS_ERR(cs))
-			return PTR_ERR(cs);
-
-		*cs++ = MI_LOAD_REGISTER_IMM(2 * GEN8_3LVL_PDPES) | MI_LRI_FORCE_POSTED;
-		for (i = GEN8_3LVL_PDPES; i--; ) {
-			const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i);
-
-			*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(base, i));
-			*cs++ = upper_32_bits(pd_daddr);
-			*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(base, i));
-			*cs++ = lower_32_bits(pd_daddr);
-		}
-		*cs++ = MI_NOOP;
-		intel_ring_advance(rq, cs);
-	}
-
-	return 0;
-}
-
-static bool skip_ppgtt_update(struct intel_context *ce, void *data)
-{
-	if (HAS_LOGICAL_RING_CONTEXTS(ce->engine->i915))
-		return !ce->state;
-	else
-		return !atomic_read(&ce->pin_count);
-}
-
-static int set_ppgtt(struct drm_i915_file_private *file_priv,
-		     struct i915_gem_context *ctx,
-		     struct drm_i915_gem_context_param *args)
-{
-	struct i915_address_space *vm, *old;
-	int err;
-
-	if (args->size)
-		return -EINVAL;
-
-	if (!rcu_access_pointer(ctx->vm))
-		return -ENODEV;
-
-	if (upper_32_bits(args->value))
-		return -ENOENT;
-
-	rcu_read_lock();
-	vm = xa_load(&file_priv->vm_xa, args->value);
-	if (vm && !kref_get_unless_zero(&vm->ref))
-		vm = NULL;
-	rcu_read_unlock();
-	if (!vm)
-		return -ENOENT;
-
-	err = mutex_lock_interruptible(&ctx->mutex);
-	if (err)
-		goto out;
-
-	if (i915_gem_context_is_closed(ctx)) {
-		err = -ENOENT;
-		goto unlock;
-	}
-
-	if (vm == rcu_access_pointer(ctx->vm))
-		goto unlock;
-
-	old = __set_ppgtt(ctx, vm);
-
-	/* Teardown the existing obj:vma cache, it will have to be rebuilt. */
-	lut_close(ctx);
-
-	/*
-	 * We need to flush any requests using the current ppgtt before
-	 * we release it as the requests do not hold a reference themselves,
-	 * only indirectly through the context.
-	 */
-	err = context_barrier_task(ctx, ALL_ENGINES,
-				   skip_ppgtt_update,
-				   pin_ppgtt_update,
-				   emit_ppgtt_update,
-				   set_ppgtt_barrier,
-				   old);
-	if (err) {
-		i915_vm_close(__set_ppgtt(ctx, old));
-		i915_vm_close(old);
-		lut_close(ctx); /* force a rebuild of the old obj:vma cache */
-	}
-
-unlock:
-	mutex_unlock(&ctx->mutex);
-out:
-	i915_vm_put(vm);
-	return err;
-}
-
 int
 i915_gem_user_to_context_sseu(struct intel_gt *gt,
 			      const struct drm_i915_gem_context_param_sseu *user,
@@ -2468,10 +2205,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 		ret = set_sseu(ctx, args);
 		break;
 
-	case I915_CONTEXT_PARAM_VM:
-		ret = set_ppgtt(fpriv, ctx, args);
-		break;
-
 	case I915_CONTEXT_PARAM_ENGINES:
 		ret = set_engines(ctx, args);
 		break;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index b673061f4f5ba..84c821cca1739 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -262,7 +262,7 @@ struct i915_gem_context {
 	 * In other modes, this is a NULL pointer with the expectation that
 	 * the caller uses the shared global GTT.
 	 */
-	struct i915_address_space __rcu *vm;
+	struct i915_address_space *vm;
 
 	/**
 	 * @pid: process id of creator
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index 5fef592390cb5..16ff64ab34a1b 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -1882,125 +1882,6 @@ static int igt_vm_isolation(void *arg)
 	return err;
 }
 
-static bool skip_unused_engines(struct intel_context *ce, void *data)
-{
-	return !ce->state;
-}
-
-static void mock_barrier_task(void *data)
-{
-	unsigned int *counter = data;
-
-	++*counter;
-}
-
-static int mock_context_barrier(void *arg)
-{
-#undef pr_fmt
-#define pr_fmt(x) "context_barrier_task():" # x
-	struct drm_i915_private *i915 = arg;
-	struct i915_gem_context *ctx;
-	struct i915_request *rq;
-	unsigned int counter;
-	int err;
-
-	/*
-	 * The context barrier provides us with a callback after it emits
-	 * a request; useful for retiring old state after loading new.
-	 */
-
-	ctx = mock_context(i915, "mock");
-	if (!ctx)
-		return -ENOMEM;
-
-	counter = 0;
-	err = context_barrier_task(ctx, 0, NULL, NULL, NULL,
-				   mock_barrier_task, &counter);
-	if (err) {
-		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
-		goto out;
-	}
-	if (counter == 0) {
-		pr_err("Did not retire immediately with 0 engines\n");
-		err = -EINVAL;
-		goto out;
-	}
-
-	counter = 0;
-	err = context_barrier_task(ctx, ALL_ENGINES, skip_unused_engines,
-				   NULL, NULL, mock_barrier_task, &counter);
-	if (err) {
-		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
-		goto out;
-	}
-	if (counter == 0) {
-		pr_err("Did not retire immediately for all unused engines\n");
-		err = -EINVAL;
-		goto out;
-	}
-
-	rq = igt_request_alloc(ctx, i915->gt.engine[RCS0]);
-	if (IS_ERR(rq)) {
-		pr_err("Request allocation failed!\n");
-		goto out;
-	}
-	i915_request_add(rq);
-
-	counter = 0;
-	context_barrier_inject_fault = BIT(RCS0);
-	err = context_barrier_task(ctx, ALL_ENGINES, NULL, NULL, NULL,
-				   mock_barrier_task, &counter);
-	context_barrier_inject_fault = 0;
-	if (err == -ENXIO)
-		err = 0;
-	else
-		pr_err("Did not hit fault injection!\n");
-	if (counter != 0) {
-		pr_err("Invoked callback on error!\n");
-		err = -EIO;
-	}
-	if (err)
-		goto out;
-
-	counter = 0;
-	err = context_barrier_task(ctx, ALL_ENGINES, skip_unused_engines,
-				   NULL, NULL, mock_barrier_task, &counter);
-	if (err) {
-		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
-		goto out;
-	}
-	mock_device_flush(i915);
-	if (counter == 0) {
-		pr_err("Did not retire on each active engines\n");
-		err = -EINVAL;
-		goto out;
-	}
-
-out:
-	mock_context_close(ctx);
-	return err;
-#undef pr_fmt
-#define pr_fmt(x) x
-}
-
-int i915_gem_context_mock_selftests(void)
-{
-	static const struct i915_subtest tests[] = {
-		SUBTEST(mock_context_barrier),
-	};
-	struct drm_i915_private *i915;
-	int err;
-
-	i915 = mock_gem_device();
-	if (!i915)
-		return -ENOMEM;
-
-	err = i915_subtests(tests, i915);
-
-	mock_destroy_device(i915);
-	return err;
-}
-
 int i915_gem_context_live_selftests(struct drm_i915_private *i915)
 {
 	static const struct i915_subtest tests[] = {
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index 3db34d3eea58a..52aa91716dc1f 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -32,6 +32,5 @@ selftest(vma, i915_vma_mock_selftests)
 selftest(evict, i915_gem_evict_mock_selftests)
 selftest(gtt, i915_gem_gtt_mock_selftests)
 selftest(hugepages, i915_gem_huge_page_mock_selftests)
-selftest(contexts, i915_gem_context_mock_selftests)
 selftest(buddy, i915_buddy_mock_selftests)
 selftest(memory_region, intel_memory_region_mock_selftests)
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 267 ------------------
 .../gpu/drm/i915/gem/i915_gem_context_types.h |   2 +-
 .../drm/i915/gem/selftests/i915_gem_context.c | 119 --------
 .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
 4 files changed, 1 insertion(+), 388 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index f0e7ce6b979b4..ad6e98d8a4fbd 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1637,121 +1637,6 @@ int i915_gem_vm_destroy_ioctl(struct drm_device *dev, void *data,
 	return 0;
 }
 
-struct context_barrier_task {
-	struct i915_active base;
-	void (*task)(void *data);
-	void *data;
-};
-
-__i915_active_call
-static void cb_retire(struct i915_active *base)
-{
-	struct context_barrier_task *cb = container_of(base, typeof(*cb), base);
-
-	if (cb->task)
-		cb->task(cb->data);
-
-	i915_active_fini(&cb->base);
-	kfree(cb);
-}
-
-I915_SELFTEST_DECLARE(static intel_engine_mask_t context_barrier_inject_fault);
-static int context_barrier_task(struct i915_gem_context *ctx,
-				intel_engine_mask_t engines,
-				bool (*skip)(struct intel_context *ce, void *data),
-				int (*pin)(struct intel_context *ce, struct i915_gem_ww_ctx *ww, void *data),
-				int (*emit)(struct i915_request *rq, void *data),
-				void (*task)(void *data),
-				void *data)
-{
-	struct context_barrier_task *cb;
-	struct i915_gem_engines_iter it;
-	struct i915_gem_engines *e;
-	struct i915_gem_ww_ctx ww;
-	struct intel_context *ce;
-	int err = 0;
-
-	GEM_BUG_ON(!task);
-
-	cb = kmalloc(sizeof(*cb), GFP_KERNEL);
-	if (!cb)
-		return -ENOMEM;
-
-	i915_active_init(&cb->base, NULL, cb_retire);
-	err = i915_active_acquire(&cb->base);
-	if (err) {
-		kfree(cb);
-		return err;
-	}
-
-	e = __context_engines_await(ctx, NULL);
-	if (!e) {
-		i915_active_release(&cb->base);
-		return -ENOENT;
-	}
-
-	for_each_gem_engine(ce, e, it) {
-		struct i915_request *rq;
-
-		if (I915_SELFTEST_ONLY(context_barrier_inject_fault &
-				       ce->engine->mask)) {
-			err = -ENXIO;
-			break;
-		}
-
-		if (!(ce->engine->mask & engines))
-			continue;
-
-		if (skip && skip(ce, data))
-			continue;
-
-		i915_gem_ww_ctx_init(&ww, true);
-retry:
-		err = intel_context_pin_ww(ce, &ww);
-		if (err)
-			goto err;
-
-		if (pin)
-			err = pin(ce, &ww, data);
-		if (err)
-			goto err_unpin;
-
-		rq = i915_request_create(ce);
-		if (IS_ERR(rq)) {
-			err = PTR_ERR(rq);
-			goto err_unpin;
-		}
-
-		err = 0;
-		if (emit)
-			err = emit(rq, data);
-		if (err == 0)
-			err = i915_active_add_request(&cb->base, rq);
-
-		i915_request_add(rq);
-err_unpin:
-		intel_context_unpin(ce);
-err:
-		if (err == -EDEADLK) {
-			err = i915_gem_ww_ctx_backoff(&ww);
-			if (!err)
-				goto retry;
-		}
-		i915_gem_ww_ctx_fini(&ww);
-
-		if (err)
-			break;
-	}
-	i915_sw_fence_complete(&e->fence);
-
-	cb->task = err ? NULL : task; /* caller needs to unwind instead */
-	cb->data = data;
-
-	i915_active_release(&cb->base);
-
-	return err;
-}
-
 static int get_ppgtt(struct drm_i915_file_private *file_priv,
 		     struct i915_gem_context *ctx,
 		     struct drm_i915_gem_context_param *args)
@@ -1784,154 +1669,6 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
 	return err;
 }
 
-static void set_ppgtt_barrier(void *data)
-{
-	struct i915_address_space *old = data;
-
-	if (INTEL_GEN(old->i915) < 8)
-		gen6_ppgtt_unpin_all(i915_vm_to_ppgtt(old));
-
-	i915_vm_close(old);
-}
-
-static int pin_ppgtt_update(struct intel_context *ce, struct i915_gem_ww_ctx *ww, void *data)
-{
-	struct i915_address_space *vm = ce->vm;
-
-	if (!HAS_LOGICAL_RING_CONTEXTS(vm->i915))
-		/* ppGTT is not part of the legacy context image */
-		return gen6_ppgtt_pin(i915_vm_to_ppgtt(vm), ww);
-
-	return 0;
-}
-
-static int emit_ppgtt_update(struct i915_request *rq, void *data)
-{
-	struct i915_address_space *vm = rq->context->vm;
-	struct intel_engine_cs *engine = rq->engine;
-	u32 base = engine->mmio_base;
-	u32 *cs;
-	int i;
-
-	if (i915_vm_is_4lvl(vm)) {
-		struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
-		const dma_addr_t pd_daddr = px_dma(ppgtt->pd);
-
-		cs = intel_ring_begin(rq, 6);
-		if (IS_ERR(cs))
-			return PTR_ERR(cs);
-
-		*cs++ = MI_LOAD_REGISTER_IMM(2);
-
-		*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(base, 0));
-		*cs++ = upper_32_bits(pd_daddr);
-		*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(base, 0));
-		*cs++ = lower_32_bits(pd_daddr);
-
-		*cs++ = MI_NOOP;
-		intel_ring_advance(rq, cs);
-	} else if (HAS_LOGICAL_RING_CONTEXTS(engine->i915)) {
-		struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
-		int err;
-
-		/* Magic required to prevent forcewake errors! */
-		err = engine->emit_flush(rq, EMIT_INVALIDATE);
-		if (err)
-			return err;
-
-		cs = intel_ring_begin(rq, 4 * GEN8_3LVL_PDPES + 2);
-		if (IS_ERR(cs))
-			return PTR_ERR(cs);
-
-		*cs++ = MI_LOAD_REGISTER_IMM(2 * GEN8_3LVL_PDPES) | MI_LRI_FORCE_POSTED;
-		for (i = GEN8_3LVL_PDPES; i--; ) {
-			const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i);
-
-			*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(base, i));
-			*cs++ = upper_32_bits(pd_daddr);
-			*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(base, i));
-			*cs++ = lower_32_bits(pd_daddr);
-		}
-		*cs++ = MI_NOOP;
-		intel_ring_advance(rq, cs);
-	}
-
-	return 0;
-}
-
-static bool skip_ppgtt_update(struct intel_context *ce, void *data)
-{
-	if (HAS_LOGICAL_RING_CONTEXTS(ce->engine->i915))
-		return !ce->state;
-	else
-		return !atomic_read(&ce->pin_count);
-}
-
-static int set_ppgtt(struct drm_i915_file_private *file_priv,
-		     struct i915_gem_context *ctx,
-		     struct drm_i915_gem_context_param *args)
-{
-	struct i915_address_space *vm, *old;
-	int err;
-
-	if (args->size)
-		return -EINVAL;
-
-	if (!rcu_access_pointer(ctx->vm))
-		return -ENODEV;
-
-	if (upper_32_bits(args->value))
-		return -ENOENT;
-
-	rcu_read_lock();
-	vm = xa_load(&file_priv->vm_xa, args->value);
-	if (vm && !kref_get_unless_zero(&vm->ref))
-		vm = NULL;
-	rcu_read_unlock();
-	if (!vm)
-		return -ENOENT;
-
-	err = mutex_lock_interruptible(&ctx->mutex);
-	if (err)
-		goto out;
-
-	if (i915_gem_context_is_closed(ctx)) {
-		err = -ENOENT;
-		goto unlock;
-	}
-
-	if (vm == rcu_access_pointer(ctx->vm))
-		goto unlock;
-
-	old = __set_ppgtt(ctx, vm);
-
-	/* Teardown the existing obj:vma cache, it will have to be rebuilt. */
-	lut_close(ctx);
-
-	/*
-	 * We need to flush any requests using the current ppgtt before
-	 * we release it as the requests do not hold a reference themselves,
-	 * only indirectly through the context.
-	 */
-	err = context_barrier_task(ctx, ALL_ENGINES,
-				   skip_ppgtt_update,
-				   pin_ppgtt_update,
-				   emit_ppgtt_update,
-				   set_ppgtt_barrier,
-				   old);
-	if (err) {
-		i915_vm_close(__set_ppgtt(ctx, old));
-		i915_vm_close(old);
-		lut_close(ctx); /* force a rebuild of the old obj:vma cache */
-	}
-
-unlock:
-	mutex_unlock(&ctx->mutex);
-out:
-	i915_vm_put(vm);
-	return err;
-}
-
 int
 i915_gem_user_to_context_sseu(struct intel_gt *gt,
 			      const struct drm_i915_gem_context_param_sseu *user,
@@ -2468,10 +2205,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 		ret = set_sseu(ctx, args);
 		break;
 
-	case I915_CONTEXT_PARAM_VM:
-		ret = set_ppgtt(fpriv, ctx, args);
-		break;
-
 	case I915_CONTEXT_PARAM_ENGINES:
 		ret = set_engines(ctx, args);
 		break;
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
index b673061f4f5ba..84c821cca1739 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
@@ -262,7 +262,7 @@ struct i915_gem_context {
 	 * In other modes, this is a NULL pointer with the expectation that
 	 * the caller uses the shared global GTT.
 	 */
-	struct i915_address_space __rcu *vm;
+	struct i915_address_space *vm;
 
 	/**
 	 * @pid: process id of creator
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index 5fef592390cb5..16ff64ab34a1b 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -1882,125 +1882,6 @@ static int igt_vm_isolation(void *arg)
 	return err;
 }
 
-static bool skip_unused_engines(struct intel_context *ce, void *data)
-{
-	return !ce->state;
-}
-
-static void mock_barrier_task(void *data)
-{
-	unsigned int *counter = data;
-
-	++*counter;
-}
-
-static int mock_context_barrier(void *arg)
-{
-#undef pr_fmt
-#define pr_fmt(x) "context_barrier_task():" # x
-	struct drm_i915_private *i915 = arg;
-	struct i915_gem_context *ctx;
-	struct i915_request *rq;
-	unsigned int counter;
-	int err;
-
-	/*
-	 * The context barrier provides us with a callback after it emits
-	 * a request; useful for retiring old state after loading new.
-	 */
-
-	ctx = mock_context(i915, "mock");
-	if (!ctx)
-		return -ENOMEM;
-
-	counter = 0;
-	err = context_barrier_task(ctx, 0, NULL, NULL, NULL,
-				   mock_barrier_task, &counter);
-	if (err) {
-		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
-		goto out;
-	}
-	if (counter == 0) {
-		pr_err("Did not retire immediately with 0 engines\n");
-		err = -EINVAL;
-		goto out;
-	}
-
-	counter = 0;
-	err = context_barrier_task(ctx, ALL_ENGINES, skip_unused_engines,
-				   NULL, NULL, mock_barrier_task, &counter);
-	if (err) {
-		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
-		goto out;
-	}
-	if (counter == 0) {
-		pr_err("Did not retire immediately for all unused engines\n");
-		err = -EINVAL;
-		goto out;
-	}
-
-	rq = igt_request_alloc(ctx, i915->gt.engine[RCS0]);
-	if (IS_ERR(rq)) {
-		pr_err("Request allocation failed!\n");
-		goto out;
-	}
-	i915_request_add(rq);
-
-	counter = 0;
-	context_barrier_inject_fault = BIT(RCS0);
-	err = context_barrier_task(ctx, ALL_ENGINES, NULL, NULL, NULL,
-				   mock_barrier_task, &counter);
-	context_barrier_inject_fault = 0;
-	if (err == -ENXIO)
-		err = 0;
-	else
-		pr_err("Did not hit fault injection!\n");
-	if (counter != 0) {
-		pr_err("Invoked callback on error!\n");
-		err = -EIO;
-	}
-	if (err)
-		goto out;
-
-	counter = 0;
-	err = context_barrier_task(ctx, ALL_ENGINES, skip_unused_engines,
-				   NULL, NULL, mock_barrier_task, &counter);
-	if (err) {
-		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
-		goto out;
-	}
-	mock_device_flush(i915);
-	if (counter == 0) {
-		pr_err("Did not retire on each active engines\n");
-		err = -EINVAL;
-		goto out;
-	}
-
-out:
-	mock_context_close(ctx);
-	return err;
-#undef pr_fmt
-#define pr_fmt(x) x
-}
-
-int i915_gem_context_mock_selftests(void)
-{
-	static const struct i915_subtest tests[] = {
-		SUBTEST(mock_context_barrier),
-	};
-	struct drm_i915_private *i915;
-	int err;
-
-	i915 = mock_gem_device();
-	if (!i915)
-		return -ENOMEM;
-
-	err = i915_subtests(tests, i915);
-
-	mock_destroy_device(i915);
-	return err;
-}
-
 int i915_gem_context_live_selftests(struct drm_i915_private *i915)
 {
 	static const struct i915_subtest tests[] = {
diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
index 3db34d3eea58a..52aa91716dc1f 100644
--- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
+++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
@@ -32,6 +32,5 @@ selftest(vma, i915_vma_mock_selftests)
 selftest(evict, i915_gem_evict_mock_selftests)
 selftest(gtt, i915_gem_gtt_mock_selftests)
 selftest(hugepages, i915_gem_huge_page_mock_selftests)
-selftest(contexts, i915_gem_context_mock_selftests)
 selftest(buddy, i915_buddy_mock_selftests)
 selftest(memory_region, intel_memory_region_mock_selftests)
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 24/27] drm/i915/gem: Don't allow changing the engine set on running contexts
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 304 --------------------
 1 file changed, 304 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index ad6e98d8a4fbd..6e5828fe1a792 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1823,306 +1823,6 @@ static int set_sseu(struct i915_gem_context *ctx,
 	return ret;
 }
 
-struct set_engines {
-	struct i915_gem_context *ctx;
-	struct i915_gem_engines *engines;
-};
-
-static int
-set_engines__load_balance(struct i915_user_extension __user *base, void *data)
-{
-	struct i915_context_engines_load_balance __user *ext =
-		container_of_user(base, typeof(*ext), base);
-	const struct set_engines *set = data;
-	struct drm_i915_private *i915 = set->ctx->i915;
-	struct intel_engine_cs *stack[16];
-	struct intel_engine_cs **siblings;
-	struct intel_context *ce;
-	struct intel_sseu null_sseu = {};
-	u16 num_siblings, idx;
-	unsigned int n;
-	int err;
-
-	if (!HAS_EXECLISTS(i915))
-		return -ENODEV;
-
-	if (intel_uc_uses_guc_submission(&i915->gt.uc))
-		return -ENODEV; /* not implement yet */
-
-	if (get_user(idx, &ext->engine_index))
-		return -EFAULT;
-
-	if (idx >= set->engines->num_engines) {
-		drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
-			idx, set->engines->num_engines);
-		return -EINVAL;
-	}
-
-	idx = array_index_nospec(idx, set->engines->num_engines);
-	if (set->engines->engines[idx]) {
-		drm_dbg(&i915->drm,
-			"Invalid placement[%d], already occupied\n", idx);
-		return -EEXIST;
-	}
-
-	if (get_user(num_siblings, &ext->num_siblings))
-		return -EFAULT;
-
-	err = check_user_mbz(&ext->flags);
-	if (err)
-		return err;
-
-	err = check_user_mbz(&ext->mbz64);
-	if (err)
-		return err;
-
-	siblings = stack;
-	if (num_siblings > ARRAY_SIZE(stack)) {
-		siblings = kmalloc_array(num_siblings,
-					 sizeof(*siblings),
-					 GFP_KERNEL);
-		if (!siblings)
-			return -ENOMEM;
-	}
-
-	for (n = 0; n < num_siblings; n++) {
-		struct i915_engine_class_instance ci;
-
-		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
-			err = -EFAULT;
-			goto out_siblings;
-		}
-
-		siblings[n] = intel_engine_lookup_user(i915,
-						       ci.engine_class,
-						       ci.engine_instance);
-		if (!siblings[n]) {
-			drm_dbg(&i915->drm,
-				"Invalid sibling[%d]: { class:%d, inst:%d }\n",
-				n, ci.engine_class, ci.engine_instance);
-			err = -EINVAL;
-			goto out_siblings;
-		}
-	}
-
-	ce = intel_execlists_create_virtual(siblings, n);
-	if (IS_ERR(ce)) {
-		err = PTR_ERR(ce);
-		goto out_siblings;
-	}
-
-	intel_context_set_gem(ce, set->ctx, null_sseu);
-
-	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
-		intel_context_put(ce);
-		err = -EEXIST;
-		goto out_siblings;
-	}
-
-out_siblings:
-	if (siblings != stack)
-		kfree(siblings);
-
-	return err;
-}
-
-static int
-set_engines__bond(struct i915_user_extension __user *base, void *data)
-{
-	struct i915_context_engines_bond __user *ext =
-		container_of_user(base, typeof(*ext), base);
-	const struct set_engines *set = data;
-	struct drm_i915_private *i915 = set->ctx->i915;
-	struct i915_engine_class_instance ci;
-	struct intel_engine_cs *virtual;
-	struct intel_engine_cs *master;
-	u16 idx, num_bonds;
-	int err, n;
-
-	if (get_user(idx, &ext->virtual_index))
-		return -EFAULT;
-
-	if (idx >= set->engines->num_engines) {
-		drm_dbg(&i915->drm,
-			"Invalid index for virtual engine: %d >= %d\n",
-			idx, set->engines->num_engines);
-		return -EINVAL;
-	}
-
-	idx = array_index_nospec(idx, set->engines->num_engines);
-	if (!set->engines->engines[idx]) {
-		drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
-		return -EINVAL;
-	}
-	virtual = set->engines->engines[idx]->engine;
-
-	if (intel_engine_is_virtual(virtual)) {
-		drm_dbg(&i915->drm,
-			"Bonding with virtual engines not allowed\n");
-		return -EINVAL;
-	}
-
-	err = check_user_mbz(&ext->flags);
-	if (err)
-		return err;
-
-	for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
-		err = check_user_mbz(&ext->mbz64[n]);
-		if (err)
-			return err;
-	}
-
-	if (copy_from_user(&ci, &ext->master, sizeof(ci)))
-		return -EFAULT;
-
-	master = intel_engine_lookup_user(i915,
-					  ci.engine_class, ci.engine_instance);
-	if (!master) {
-		drm_dbg(&i915->drm,
-			"Unrecognised master engine: { class:%u, instance:%u }\n",
-			ci.engine_class, ci.engine_instance);
-		return -EINVAL;
-	}
-
-	if (get_user(num_bonds, &ext->num_bonds))
-		return -EFAULT;
-
-	for (n = 0; n < num_bonds; n++) {
-		struct intel_engine_cs *bond;
-
-		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
-			return -EFAULT;
-
-		bond = intel_engine_lookup_user(i915,
-						ci.engine_class,
-						ci.engine_instance);
-		if (!bond) {
-			drm_dbg(&i915->drm,
-				"Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
-				n, ci.engine_class, ci.engine_instance);
-			return -EINVAL;
-		}
-	}
-
-	return 0;
-}
-
-static const i915_user_extension_fn set_engines__extensions[] = {
-	[I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_engines__load_balance,
-	[I915_CONTEXT_ENGINES_EXT_BOND] = set_engines__bond,
-};
-
-static int
-set_engines(struct i915_gem_context *ctx,
-	    const struct drm_i915_gem_context_param *args)
-{
-	struct drm_i915_private *i915 = ctx->i915;
-	struct i915_context_param_engines __user *user =
-		u64_to_user_ptr(args->value);
-	struct intel_sseu null_sseu = {};
-	struct set_engines set = { .ctx = ctx };
-	unsigned int num_engines, n;
-	u64 extensions;
-	int err;
-
-	if (!args->size) { /* switch back to legacy user_ring_map */
-		if (!i915_gem_context_user_engines(ctx))
-			return 0;
-
-		set.engines = default_engines(ctx, null_sseu);
-		if (IS_ERR(set.engines))
-			return PTR_ERR(set.engines);
-
-		goto replace;
-	}
-
-	BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
-	if (args->size < sizeof(*user) ||
-	    !IS_ALIGNED(args->size, sizeof(*user->engines))) {
-		drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
-			args->size);
-		return -EINVAL;
-	}
-
-	num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
-	/* RING_MASK has no shift so we can use it directly here */
-	if (num_engines > I915_EXEC_RING_MASK + 1)
-		return -EINVAL;
-
-	set.engines = alloc_engines(num_engines);
-	if (!set.engines)
-		return -ENOMEM;
-
-	for (n = 0; n < num_engines; n++) {
-		struct i915_engine_class_instance ci;
-		struct intel_engine_cs *engine;
-		struct intel_context *ce;
-
-		if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
-			__free_engines(set.engines, n);
-			return -EFAULT;
-		}
-
-		if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
-		    ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE) {
-			set.engines->engines[n] = NULL;
-			continue;
-		}
-
-		engine = intel_engine_lookup_user(ctx->i915,
-						  ci.engine_class,
-						  ci.engine_instance);
-		if (!engine) {
-			drm_dbg(&i915->drm,
-				"Invalid engine[%d]: { class:%d, instance:%d }\n",
-				n, ci.engine_class, ci.engine_instance);
-			__free_engines(set.engines, n);
-			return -ENOENT;
-		}
-
-		ce = intel_context_create(engine);
-		if (IS_ERR(ce)) {
-			__free_engines(set.engines, n);
-			return PTR_ERR(ce);
-		}
-
-		intel_context_set_gem(ce, ctx, null_sseu);
-
-		set.engines->engines[n] = ce;
-	}
-	set.engines->num_engines = num_engines;
-
-	err = -EFAULT;
-	if (!get_user(extensions, &user->extensions))
-		err = i915_user_extensions(u64_to_user_ptr(extensions),
-					   set_engines__extensions,
-					   ARRAY_SIZE(set_engines__extensions),
-					   &set);
-	if (err) {
-		free_engines(set.engines);
-		return err;
-	}
-
-replace:
-	mutex_lock(&ctx->engines_mutex);
-	if (i915_gem_context_is_closed(ctx)) {
-		mutex_unlock(&ctx->engines_mutex);
-		free_engines(set.engines);
-		return -ENOENT;
-	}
-	if (args->size)
-		i915_gem_context_set_user_engines(ctx);
-	else
-		i915_gem_context_clear_user_engines(ctx);
-	set.engines = rcu_replace_pointer(ctx->engines, set.engines, 1);
-	mutex_unlock(&ctx->engines_mutex);
-
-	/* Keep track of old engine sets for kill_context() */
-	engines_idle_release(ctx, set.engines);
-
-	return 0;
-}
-
 static int
 set_persistence(struct i915_gem_context *ctx,
 		const struct drm_i915_gem_context_param *args)
@@ -2205,10 +1905,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 		ret = set_sseu(ctx, args);
 		break;
 
-	case I915_CONTEXT_PARAM_ENGINES:
-		ret = set_engines(ctx, args);
-		break;
-
 	case I915_CONTEXT_PARAM_PERSISTENCE:
 		ret = set_persistence(ctx, args);
 		break;
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 24/27] drm/i915/gem: Don't allow changing the engine set on running contexts
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c | 304 --------------------
 1 file changed, 304 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index ad6e98d8a4fbd..6e5828fe1a792 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1823,306 +1823,6 @@ static int set_sseu(struct i915_gem_context *ctx,
 	return ret;
 }
 
-struct set_engines {
-	struct i915_gem_context *ctx;
-	struct i915_gem_engines *engines;
-};
-
-static int
-set_engines__load_balance(struct i915_user_extension __user *base, void *data)
-{
-	struct i915_context_engines_load_balance __user *ext =
-		container_of_user(base, typeof(*ext), base);
-	const struct set_engines *set = data;
-	struct drm_i915_private *i915 = set->ctx->i915;
-	struct intel_engine_cs *stack[16];
-	struct intel_engine_cs **siblings;
-	struct intel_context *ce;
-	struct intel_sseu null_sseu = {};
-	u16 num_siblings, idx;
-	unsigned int n;
-	int err;
-
-	if (!HAS_EXECLISTS(i915))
-		return -ENODEV;
-
-	if (intel_uc_uses_guc_submission(&i915->gt.uc))
-		return -ENODEV; /* not implement yet */
-
-	if (get_user(idx, &ext->engine_index))
-		return -EFAULT;
-
-	if (idx >= set->engines->num_engines) {
-		drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
-			idx, set->engines->num_engines);
-		return -EINVAL;
-	}
-
-	idx = array_index_nospec(idx, set->engines->num_engines);
-	if (set->engines->engines[idx]) {
-		drm_dbg(&i915->drm,
-			"Invalid placement[%d], already occupied\n", idx);
-		return -EEXIST;
-	}
-
-	if (get_user(num_siblings, &ext->num_siblings))
-		return -EFAULT;
-
-	err = check_user_mbz(&ext->flags);
-	if (err)
-		return err;
-
-	err = check_user_mbz(&ext->mbz64);
-	if (err)
-		return err;
-
-	siblings = stack;
-	if (num_siblings > ARRAY_SIZE(stack)) {
-		siblings = kmalloc_array(num_siblings,
-					 sizeof(*siblings),
-					 GFP_KERNEL);
-		if (!siblings)
-			return -ENOMEM;
-	}
-
-	for (n = 0; n < num_siblings; n++) {
-		struct i915_engine_class_instance ci;
-
-		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
-			err = -EFAULT;
-			goto out_siblings;
-		}
-
-		siblings[n] = intel_engine_lookup_user(i915,
-						       ci.engine_class,
-						       ci.engine_instance);
-		if (!siblings[n]) {
-			drm_dbg(&i915->drm,
-				"Invalid sibling[%d]: { class:%d, inst:%d }\n",
-				n, ci.engine_class, ci.engine_instance);
-			err = -EINVAL;
-			goto out_siblings;
-		}
-	}
-
-	ce = intel_execlists_create_virtual(siblings, n);
-	if (IS_ERR(ce)) {
-		err = PTR_ERR(ce);
-		goto out_siblings;
-	}
-
-	intel_context_set_gem(ce, set->ctx, null_sseu);
-
-	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
-		intel_context_put(ce);
-		err = -EEXIST;
-		goto out_siblings;
-	}
-
-out_siblings:
-	if (siblings != stack)
-		kfree(siblings);
-
-	return err;
-}
-
-static int
-set_engines__bond(struct i915_user_extension __user *base, void *data)
-{
-	struct i915_context_engines_bond __user *ext =
-		container_of_user(base, typeof(*ext), base);
-	const struct set_engines *set = data;
-	struct drm_i915_private *i915 = set->ctx->i915;
-	struct i915_engine_class_instance ci;
-	struct intel_engine_cs *virtual;
-	struct intel_engine_cs *master;
-	u16 idx, num_bonds;
-	int err, n;
-
-	if (get_user(idx, &ext->virtual_index))
-		return -EFAULT;
-
-	if (idx >= set->engines->num_engines) {
-		drm_dbg(&i915->drm,
-			"Invalid index for virtual engine: %d >= %d\n",
-			idx, set->engines->num_engines);
-		return -EINVAL;
-	}
-
-	idx = array_index_nospec(idx, set->engines->num_engines);
-	if (!set->engines->engines[idx]) {
-		drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
-		return -EINVAL;
-	}
-	virtual = set->engines->engines[idx]->engine;
-
-	if (intel_engine_is_virtual(virtual)) {
-		drm_dbg(&i915->drm,
-			"Bonding with virtual engines not allowed\n");
-		return -EINVAL;
-	}
-
-	err = check_user_mbz(&ext->flags);
-	if (err)
-		return err;
-
-	for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
-		err = check_user_mbz(&ext->mbz64[n]);
-		if (err)
-			return err;
-	}
-
-	if (copy_from_user(&ci, &ext->master, sizeof(ci)))
-		return -EFAULT;
-
-	master = intel_engine_lookup_user(i915,
-					  ci.engine_class, ci.engine_instance);
-	if (!master) {
-		drm_dbg(&i915->drm,
-			"Unrecognised master engine: { class:%u, instance:%u }\n",
-			ci.engine_class, ci.engine_instance);
-		return -EINVAL;
-	}
-
-	if (get_user(num_bonds, &ext->num_bonds))
-		return -EFAULT;
-
-	for (n = 0; n < num_bonds; n++) {
-		struct intel_engine_cs *bond;
-
-		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
-			return -EFAULT;
-
-		bond = intel_engine_lookup_user(i915,
-						ci.engine_class,
-						ci.engine_instance);
-		if (!bond) {
-			drm_dbg(&i915->drm,
-				"Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
-				n, ci.engine_class, ci.engine_instance);
-			return -EINVAL;
-		}
-	}
-
-	return 0;
-}
-
-static const i915_user_extension_fn set_engines__extensions[] = {
-	[I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_engines__load_balance,
-	[I915_CONTEXT_ENGINES_EXT_BOND] = set_engines__bond,
-};
-
-static int
-set_engines(struct i915_gem_context *ctx,
-	    const struct drm_i915_gem_context_param *args)
-{
-	struct drm_i915_private *i915 = ctx->i915;
-	struct i915_context_param_engines __user *user =
-		u64_to_user_ptr(args->value);
-	struct intel_sseu null_sseu = {};
-	struct set_engines set = { .ctx = ctx };
-	unsigned int num_engines, n;
-	u64 extensions;
-	int err;
-
-	if (!args->size) { /* switch back to legacy user_ring_map */
-		if (!i915_gem_context_user_engines(ctx))
-			return 0;
-
-		set.engines = default_engines(ctx, null_sseu);
-		if (IS_ERR(set.engines))
-			return PTR_ERR(set.engines);
-
-		goto replace;
-	}
-
-	BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
-	if (args->size < sizeof(*user) ||
-	    !IS_ALIGNED(args->size, sizeof(*user->engines))) {
-		drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
-			args->size);
-		return -EINVAL;
-	}
-
-	num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
-	/* RING_MASK has no shift so we can use it directly here */
-	if (num_engines > I915_EXEC_RING_MASK + 1)
-		return -EINVAL;
-
-	set.engines = alloc_engines(num_engines);
-	if (!set.engines)
-		return -ENOMEM;
-
-	for (n = 0; n < num_engines; n++) {
-		struct i915_engine_class_instance ci;
-		struct intel_engine_cs *engine;
-		struct intel_context *ce;
-
-		if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
-			__free_engines(set.engines, n);
-			return -EFAULT;
-		}
-
-		if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
-		    ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE) {
-			set.engines->engines[n] = NULL;
-			continue;
-		}
-
-		engine = intel_engine_lookup_user(ctx->i915,
-						  ci.engine_class,
-						  ci.engine_instance);
-		if (!engine) {
-			drm_dbg(&i915->drm,
-				"Invalid engine[%d]: { class:%d, instance:%d }\n",
-				n, ci.engine_class, ci.engine_instance);
-			__free_engines(set.engines, n);
-			return -ENOENT;
-		}
-
-		ce = intel_context_create(engine);
-		if (IS_ERR(ce)) {
-			__free_engines(set.engines, n);
-			return PTR_ERR(ce);
-		}
-
-		intel_context_set_gem(ce, ctx, null_sseu);
-
-		set.engines->engines[n] = ce;
-	}
-	set.engines->num_engines = num_engines;
-
-	err = -EFAULT;
-	if (!get_user(extensions, &user->extensions))
-		err = i915_user_extensions(u64_to_user_ptr(extensions),
-					   set_engines__extensions,
-					   ARRAY_SIZE(set_engines__extensions),
-					   &set);
-	if (err) {
-		free_engines(set.engines);
-		return err;
-	}
-
-replace:
-	mutex_lock(&ctx->engines_mutex);
-	if (i915_gem_context_is_closed(ctx)) {
-		mutex_unlock(&ctx->engines_mutex);
-		free_engines(set.engines);
-		return -ENOENT;
-	}
-	if (args->size)
-		i915_gem_context_set_user_engines(ctx);
-	else
-		i915_gem_context_clear_user_engines(ctx);
-	set.engines = rcu_replace_pointer(ctx->engines, set.engines, 1);
-	mutex_unlock(&ctx->engines_mutex);
-
-	/* Keep track of old engine sets for kill_context() */
-	engines_idle_release(ctx, set.engines);
-
-	return 0;
-}
-
 static int
 set_persistence(struct i915_gem_context *ctx,
 		const struct drm_i915_gem_context_param *args)
@@ -2205,10 +1905,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
 		ret = set_sseu(ctx, args);
 		break;
 
-	case I915_CONTEXT_PARAM_ENGINES:
-		ret = set_engines(ctx, args);
-		break;
-
 	case I915_CONTEXT_PARAM_PERSISTENCE:
 		ret = set_persistence(ctx, args);
 		break;
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 25/27] drm/i915/selftests: Take a VM in kernel_context()
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

This better models where we want to go with contexts in general where
things like the VM and engine set are create parameters instead of being
set after the fact.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 .../drm/i915/gem/selftests/i915_gem_context.c |  4 ++--
 .../gpu/drm/i915/gem/selftests/mock_context.c |  9 ++++++++-
 .../gpu/drm/i915/gem/selftests/mock_context.h |  4 +++-
 drivers/gpu/drm/i915/gt/selftest_execlists.c  | 20 +++++++++----------
 drivers/gpu/drm/i915/gt/selftest_hangcheck.c  |  2 +-
 5 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index 16ff64ab34a1b..76029d7143f6c 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -680,7 +680,7 @@ static int igt_ctx_exec(void *arg)
 			struct i915_gem_context *ctx;
 			struct intel_context *ce;
 
-			ctx = kernel_context(i915);
+			ctx = kernel_context(i915, NULL);
 			if (IS_ERR(ctx)) {
 				err = PTR_ERR(ctx);
 				goto out_file;
@@ -813,7 +813,7 @@ static int igt_shared_ctx_exec(void *arg)
 			struct i915_gem_context *ctx;
 			struct intel_context *ce;
 
-			ctx = kernel_context(i915);
+			ctx = kernel_context(i915, NULL);
 			if (IS_ERR(ctx)) {
 				err = PTR_ERR(ctx);
 				goto out_test;
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index 61aaac4a334cf..500ef27ba4771 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -150,7 +150,8 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
 }
 
 struct i915_gem_context *
-kernel_context(struct drm_i915_private *i915)
+kernel_context(struct drm_i915_private *i915,
+	       struct i915_address_space *vm)
 {
 	struct i915_gem_context *ctx;
 	struct i915_gem_proto_context *pc;
@@ -159,6 +160,12 @@ kernel_context(struct drm_i915_private *i915)
 	if (IS_ERR(pc))
 		return ERR_CAST(pc);
 
+	if (vm) {
+		if (pc->vm)
+			i915_vm_put(pc->vm);
+		pc->vm = i915_vm_get(vm);
+	}
+
 	ctx = i915_gem_create_context(i915, pc);
 	proto_context_close(pc);
 	if (IS_ERR(ctx))
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.h b/drivers/gpu/drm/i915/gem/selftests/mock_context.h
index 2a6121d33352d..7a02fd9b5866a 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.h
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.h
@@ -10,6 +10,7 @@
 struct file;
 struct drm_i915_private;
 struct intel_engine_cs;
+struct i915_address_space;
 
 void mock_init_contexts(struct drm_i915_private *i915);
 
@@ -25,7 +26,8 @@ live_context(struct drm_i915_private *i915, struct file *file);
 struct i915_gem_context *
 live_context_for_engine(struct intel_engine_cs *engine, struct file *file);
 
-struct i915_gem_context *kernel_context(struct drm_i915_private *i915);
+struct i915_gem_context *kernel_context(struct drm_i915_private *i915,
+					struct i915_address_space *vm);
 void kernel_context_close(struct i915_gem_context *ctx);
 
 #endif /* !__MOCK_CONTEXT_H */
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index a0e75b71a3374..0989e024f7a03 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -1522,12 +1522,12 @@ static int live_busywait_preempt(void *arg)
 	 * preempt the busywaits used to synchronise between rings.
 	 */
 
-	ctx_hi = kernel_context(gt->i915);
+	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
 		return -ENOMEM;
 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
-	ctx_lo = kernel_context(gt->i915);
+	ctx_lo = kernel_context(gt->i915, NULL);
 	if (!ctx_lo)
 		goto err_ctx_hi;
 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
@@ -1724,12 +1724,12 @@ static int live_preempt(void *arg)
 	if (igt_spinner_init(&spin_lo, gt))
 		goto err_spin_hi;
 
-	ctx_hi = kernel_context(gt->i915);
+	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
 		goto err_spin_lo;
 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
-	ctx_lo = kernel_context(gt->i915);
+	ctx_lo = kernel_context(gt->i915, NULL);
 	if (!ctx_lo)
 		goto err_ctx_hi;
 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
@@ -1816,11 +1816,11 @@ static int live_late_preempt(void *arg)
 	if (igt_spinner_init(&spin_lo, gt))
 		goto err_spin_hi;
 
-	ctx_hi = kernel_context(gt->i915);
+	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
 		goto err_spin_lo;
 
-	ctx_lo = kernel_context(gt->i915);
+	ctx_lo = kernel_context(gt->i915, NULL);
 	if (!ctx_lo)
 		goto err_ctx_hi;
 
@@ -1910,7 +1910,7 @@ struct preempt_client {
 
 static int preempt_client_init(struct intel_gt *gt, struct preempt_client *c)
 {
-	c->ctx = kernel_context(gt->i915);
+	c->ctx = kernel_context(gt->i915, NULL);
 	if (!c->ctx)
 		return -ENOMEM;
 
@@ -3367,12 +3367,12 @@ static int live_preempt_timeout(void *arg)
 	if (igt_spinner_init(&spin_lo, gt))
 		return -ENOMEM;
 
-	ctx_hi = kernel_context(gt->i915);
+	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
 		goto err_spin_lo;
 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
-	ctx_lo = kernel_context(gt->i915);
+	ctx_lo = kernel_context(gt->i915, NULL);
 	if (!ctx_lo)
 		goto err_ctx_hi;
 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
@@ -3659,7 +3659,7 @@ static int live_preempt_smoke(void *arg)
 	}
 
 	for (n = 0; n < smoke.ncontext; n++) {
-		smoke.contexts[n] = kernel_context(smoke.gt->i915);
+		smoke.contexts[n] = kernel_context(smoke.gt->i915, NULL);
 		if (!smoke.contexts[n])
 			goto err_ctx;
 	}
diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
index 746985971c3a6..3676eaf6b2aee 100644
--- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
+++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
@@ -42,7 +42,7 @@ static int hang_init(struct hang *h, struct intel_gt *gt)
 	memset(h, 0, sizeof(*h));
 	h->gt = gt;
 
-	h->ctx = kernel_context(gt->i915);
+	h->ctx = kernel_context(gt->i915, NULL);
 	if (IS_ERR(h->ctx))
 		return PTR_ERR(h->ctx);
 
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 25/27] drm/i915/selftests: Take a VM in kernel_context()
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

This better models where we want to go with contexts in general where
things like the VM and engine set are create parameters instead of being
set after the fact.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 .../drm/i915/gem/selftests/i915_gem_context.c |  4 ++--
 .../gpu/drm/i915/gem/selftests/mock_context.c |  9 ++++++++-
 .../gpu/drm/i915/gem/selftests/mock_context.h |  4 +++-
 drivers/gpu/drm/i915/gt/selftest_execlists.c  | 20 +++++++++----------
 drivers/gpu/drm/i915/gt/selftest_hangcheck.c  |  2 +-
 5 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index 16ff64ab34a1b..76029d7143f6c 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -680,7 +680,7 @@ static int igt_ctx_exec(void *arg)
 			struct i915_gem_context *ctx;
 			struct intel_context *ce;
 
-			ctx = kernel_context(i915);
+			ctx = kernel_context(i915, NULL);
 			if (IS_ERR(ctx)) {
 				err = PTR_ERR(ctx);
 				goto out_file;
@@ -813,7 +813,7 @@ static int igt_shared_ctx_exec(void *arg)
 			struct i915_gem_context *ctx;
 			struct intel_context *ce;
 
-			ctx = kernel_context(i915);
+			ctx = kernel_context(i915, NULL);
 			if (IS_ERR(ctx)) {
 				err = PTR_ERR(ctx);
 				goto out_test;
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index 61aaac4a334cf..500ef27ba4771 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -150,7 +150,8 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
 }
 
 struct i915_gem_context *
-kernel_context(struct drm_i915_private *i915)
+kernel_context(struct drm_i915_private *i915,
+	       struct i915_address_space *vm)
 {
 	struct i915_gem_context *ctx;
 	struct i915_gem_proto_context *pc;
@@ -159,6 +160,12 @@ kernel_context(struct drm_i915_private *i915)
 	if (IS_ERR(pc))
 		return ERR_CAST(pc);
 
+	if (vm) {
+		if (pc->vm)
+			i915_vm_put(pc->vm);
+		pc->vm = i915_vm_get(vm);
+	}
+
 	ctx = i915_gem_create_context(i915, pc);
 	proto_context_close(pc);
 	if (IS_ERR(ctx))
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.h b/drivers/gpu/drm/i915/gem/selftests/mock_context.h
index 2a6121d33352d..7a02fd9b5866a 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.h
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.h
@@ -10,6 +10,7 @@
 struct file;
 struct drm_i915_private;
 struct intel_engine_cs;
+struct i915_address_space;
 
 void mock_init_contexts(struct drm_i915_private *i915);
 
@@ -25,7 +26,8 @@ live_context(struct drm_i915_private *i915, struct file *file);
 struct i915_gem_context *
 live_context_for_engine(struct intel_engine_cs *engine, struct file *file);
 
-struct i915_gem_context *kernel_context(struct drm_i915_private *i915);
+struct i915_gem_context *kernel_context(struct drm_i915_private *i915,
+					struct i915_address_space *vm);
 void kernel_context_close(struct i915_gem_context *ctx);
 
 #endif /* !__MOCK_CONTEXT_H */
diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
index a0e75b71a3374..0989e024f7a03 100644
--- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
+++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
@@ -1522,12 +1522,12 @@ static int live_busywait_preempt(void *arg)
 	 * preempt the busywaits used to synchronise between rings.
 	 */
 
-	ctx_hi = kernel_context(gt->i915);
+	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
 		return -ENOMEM;
 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
-	ctx_lo = kernel_context(gt->i915);
+	ctx_lo = kernel_context(gt->i915, NULL);
 	if (!ctx_lo)
 		goto err_ctx_hi;
 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
@@ -1724,12 +1724,12 @@ static int live_preempt(void *arg)
 	if (igt_spinner_init(&spin_lo, gt))
 		goto err_spin_hi;
 
-	ctx_hi = kernel_context(gt->i915);
+	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
 		goto err_spin_lo;
 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
-	ctx_lo = kernel_context(gt->i915);
+	ctx_lo = kernel_context(gt->i915, NULL);
 	if (!ctx_lo)
 		goto err_ctx_hi;
 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
@@ -1816,11 +1816,11 @@ static int live_late_preempt(void *arg)
 	if (igt_spinner_init(&spin_lo, gt))
 		goto err_spin_hi;
 
-	ctx_hi = kernel_context(gt->i915);
+	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
 		goto err_spin_lo;
 
-	ctx_lo = kernel_context(gt->i915);
+	ctx_lo = kernel_context(gt->i915, NULL);
 	if (!ctx_lo)
 		goto err_ctx_hi;
 
@@ -1910,7 +1910,7 @@ struct preempt_client {
 
 static int preempt_client_init(struct intel_gt *gt, struct preempt_client *c)
 {
-	c->ctx = kernel_context(gt->i915);
+	c->ctx = kernel_context(gt->i915, NULL);
 	if (!c->ctx)
 		return -ENOMEM;
 
@@ -3367,12 +3367,12 @@ static int live_preempt_timeout(void *arg)
 	if (igt_spinner_init(&spin_lo, gt))
 		return -ENOMEM;
 
-	ctx_hi = kernel_context(gt->i915);
+	ctx_hi = kernel_context(gt->i915, NULL);
 	if (!ctx_hi)
 		goto err_spin_lo;
 	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
-	ctx_lo = kernel_context(gt->i915);
+	ctx_lo = kernel_context(gt->i915, NULL);
 	if (!ctx_lo)
 		goto err_ctx_hi;
 	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
@@ -3659,7 +3659,7 @@ static int live_preempt_smoke(void *arg)
 	}
 
 	for (n = 0; n < smoke.ncontext; n++) {
-		smoke.contexts[n] = kernel_context(smoke.gt->i915);
+		smoke.contexts[n] = kernel_context(smoke.gt->i915, NULL);
 		if (!smoke.contexts[n])
 			goto err_ctx;
 	}
diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
index 746985971c3a6..3676eaf6b2aee 100644
--- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
+++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
@@ -42,7 +42,7 @@ static int hang_init(struct hang *h, struct intel_gt *gt)
 	memset(h, 0, sizeof(*h));
 	h->gt = gt;
 
-	h->ctx = kernel_context(gt->i915);
+	h->ctx = kernel_context(gt->i915, NULL);
 	if (IS_ERR(h->ctx))
 		return PTR_ERR(h->ctx);
 
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 26/27] i915/gem/selftests: Assign the VM at context creation in igt_shared_ctx_exec
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

We want to delete __assign_ppgtt and, generally, stop setting the VM
after context creation.  This is the one place I could find in the
selftests where we set a VM after the fact.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index 76029d7143f6c..76dd5cfe11b3c 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -813,16 +813,12 @@ static int igt_shared_ctx_exec(void *arg)
 			struct i915_gem_context *ctx;
 			struct intel_context *ce;
 
-			ctx = kernel_context(i915, NULL);
+			ctx = kernel_context(i915, ctx_vm(parent));
 			if (IS_ERR(ctx)) {
 				err = PTR_ERR(ctx);
 				goto out_test;
 			}
 
-			mutex_lock(&ctx->mutex);
-			__assign_ppgtt(ctx, ctx_vm(parent));
-			mutex_unlock(&ctx->mutex);
-
 			ce = i915_gem_context_get_engine(ctx, engine->legacy_idx);
 			GEM_BUG_ON(IS_ERR(ce));
 
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 26/27] i915/gem/selftests: Assign the VM at context creation in igt_shared_ctx_exec
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

We want to delete __assign_ppgtt and, generally, stop setting the VM
after context creation.  This is the one place I could find in the
selftests where we set a VM after the fact.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index 76029d7143f6c..76dd5cfe11b3c 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -813,16 +813,12 @@ static int igt_shared_ctx_exec(void *arg)
 			struct i915_gem_context *ctx;
 			struct intel_context *ce;
 
-			ctx = kernel_context(i915, NULL);
+			ctx = kernel_context(i915, ctx_vm(parent));
 			if (IS_ERR(ctx)) {
 				err = PTR_ERR(ctx);
 				goto out_test;
 			}
 
-			mutex_lock(&ctx->mutex);
-			__assign_ppgtt(ctx, ctx_vm(parent));
-			mutex_unlock(&ctx->mutex);
-
 			ce = i915_gem_context_get_engine(ctx, engine->legacy_idx);
 			GEM_BUG_ON(IS_ERR(ce));
 
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [PATCH 27/27] drm/i915/gem: Roll all of context creation together
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-03 15:57   ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel; +Cc: Jason Ekstrand

Now that we have the whole engine set and VM at context creation time,
we can just assign those fields instead of creating first and handling
the VM and engines later.  This lets us avoid creating useless VMs and
engine sets and lets us get rid of the complex VM setting code.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 159 ++++++------------
 .../gpu/drm/i915/gem/selftests/mock_context.c |  33 ++--
 2 files changed, 64 insertions(+), 128 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 6e5828fe1a792..6bffb0e579b4e 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1302,56 +1302,6 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
 	return 0;
 }
 
-static struct i915_gem_context *
-__create_context(struct drm_i915_private *i915,
-		 const struct i915_gem_proto_context *pc)
-{
-	struct i915_gem_context *ctx;
-	struct i915_gem_engines *e;
-	int err;
-	int i;
-
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-	if (!ctx)
-		return ERR_PTR(-ENOMEM);
-
-	kref_init(&ctx->ref);
-	ctx->i915 = i915;
-	ctx->sched = pc->sched;
-	mutex_init(&ctx->mutex);
-	INIT_LIST_HEAD(&ctx->link);
-
-	spin_lock_init(&ctx->stale.lock);
-	INIT_LIST_HEAD(&ctx->stale.engines);
-
-	mutex_init(&ctx->engines_mutex);
-	e = default_engines(ctx, pc->legacy_rcs_sseu);
-	if (IS_ERR(e)) {
-		err = PTR_ERR(e);
-		goto err_free;
-	}
-	RCU_INIT_POINTER(ctx->engines, e);
-
-	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
-	mutex_init(&ctx->lut_mutex);
-
-	/* NB: Mark all slices as needing a remap so that when the context first
-	 * loads it will restore whatever remap state already exists. If there
-	 * is no remap info, it will be a NOP. */
-	ctx->remap_slice = ALL_L3_SLICES(i915);
-
-	ctx->user_flags = pc->user_flags;
-
-	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
-		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
-
-	return ctx;
-
-err_free:
-	kfree(ctx);
-	return ERR_PTR(err);
-}
-
 static inline struct i915_gem_engines *
 __context_engines_await(const struct i915_gem_context *ctx,
 			bool *user_engines)
@@ -1395,86 +1345,77 @@ context_apply_all(struct i915_gem_context *ctx,
 	i915_sw_fence_complete(&e->fence);
 }
 
-static void __apply_ppgtt(struct intel_context *ce, void *vm)
-{
-	i915_vm_put(ce->vm);
-	ce->vm = i915_vm_get(vm);
-}
-
-static struct i915_address_space *
-__set_ppgtt(struct i915_gem_context *ctx, struct i915_address_space *vm)
-{
-	struct i915_address_space *old;
-
-	old = rcu_replace_pointer(ctx->vm,
-				  i915_vm_open(vm),
-				  lockdep_is_held(&ctx->mutex));
-	GEM_BUG_ON(old && i915_vm_is_4lvl(vm) != i915_vm_is_4lvl(old));
-
-	context_apply_all(ctx, __apply_ppgtt, vm);
-
-	return old;
-}
-
-static void __assign_ppgtt(struct i915_gem_context *ctx,
-			   struct i915_address_space *vm)
-{
-	if (vm == rcu_access_pointer(ctx->vm))
-		return;
-
-	vm = __set_ppgtt(ctx, vm);
-	if (vm)
-		i915_vm_close(vm);
-}
-
 static struct i915_gem_context *
 i915_gem_create_context(struct drm_i915_private *i915,
 			const struct i915_gem_proto_context *pc)
 {
 	struct i915_gem_context *ctx;
-	int ret;
+	struct i915_gem_engines *e;
+	int err;
+	int i;
 
-	ctx = __create_context(i915, pc);
-	if (IS_ERR(ctx))
-		return ctx;
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return ERR_PTR(-ENOMEM);
 
-	if (pc->vm) {
-		mutex_lock(&ctx->mutex);
-		__assign_ppgtt(ctx, pc->vm);
-		mutex_unlock(&ctx->mutex);
-	}
+	kref_init(&ctx->ref);
+	ctx->i915 = i915;
+	ctx->sched = pc->sched;
+	mutex_init(&ctx->mutex);
+	INIT_LIST_HEAD(&ctx->link);
 
-	if (pc->num_user_engines >= 0) {
-		struct i915_gem_engines *engines;
+	spin_lock_init(&ctx->stale.lock);
+	INIT_LIST_HEAD(&ctx->stale.engines);
 
-		engines = user_engines(ctx, pc->num_user_engines,
-				       pc->user_engines);
-		if (IS_ERR(engines)) {
-			context_close(ctx);
-			return ERR_CAST(engines);
-		}
+	if (pc->vm)
+		RCU_INIT_POINTER(ctx->vm, i915_vm_open(pc->vm));
 
-		mutex_lock(&ctx->engines_mutex);
+	mutex_init(&ctx->engines_mutex);
+	if (pc->num_user_engines >= 0) {
 		i915_gem_context_set_user_engines(ctx);
-		engines = rcu_replace_pointer(ctx->engines, engines, 1);
-		mutex_unlock(&ctx->engines_mutex);
-
-		free_engines(engines);
+		e = user_engines(ctx, pc->num_user_engines, pc->user_engines);
+	} else {
+		i915_gem_context_clear_user_engines(ctx);
+		e = default_engines(ctx, pc->legacy_rcs_sseu);
 	}
+	if (IS_ERR(e)) {
+		err = PTR_ERR(e);
+		goto err_vm;
+	}
+	RCU_INIT_POINTER(ctx->engines, e);
+
+	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
+	mutex_init(&ctx->lut_mutex);
+
+	/* NB: Mark all slices as needing a remap so that when the context first
+	 * loads it will restore whatever remap state already exists. If there
+	 * is no remap info, it will be a NOP. */
+	ctx->remap_slice = ALL_L3_SLICES(i915);
+
+	ctx->user_flags = pc->user_flags;
+
+	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
+		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
 
 	if (pc->single_timeline) {
-		ret = drm_syncobj_create(&ctx->syncobj,
+		err = drm_syncobj_create(&ctx->syncobj,
 					 DRM_SYNCOBJ_CREATE_SIGNALED,
 					 NULL);
-		if (ret) {
-			context_close(ctx);
-			return ERR_PTR(ret);
-		}
+		if (err)
+			goto err_engines;
 	}
 
 	trace_i915_context_create(ctx);
 
 	return ctx;
+
+err_engines:
+	free_engines(e);
+err_vm:
+	if (ctx->vm)
+		i915_vm_close(ctx->vm);
+	kfree(ctx);
+	return ERR_PTR(err);
 }
 
 static void init_contexts(struct i915_gem_contexts *gc)
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index 500ef27ba4771..fee070df1c97b 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -31,15 +31,6 @@ mock_context(struct drm_i915_private *i915,
 
 	i915_gem_context_set_persistence(ctx);
 
-	mutex_init(&ctx->engines_mutex);
-	e = default_engines(ctx, null_sseu);
-	if (IS_ERR(e))
-		goto err_free;
-	RCU_INIT_POINTER(ctx->engines, e);
-
-	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
-	mutex_init(&ctx->lut_mutex);
-
 	if (name) {
 		struct i915_ppgtt *ppgtt;
 
@@ -47,25 +38,29 @@ mock_context(struct drm_i915_private *i915,
 
 		ppgtt = mock_ppgtt(i915, name);
 		if (!ppgtt)
-			goto err_put;
-
-		mutex_lock(&ctx->mutex);
-		__set_ppgtt(ctx, &ppgtt->vm);
-		mutex_unlock(&ctx->mutex);
+			goto err_free;
 
+		ctx->vm = i915_vm_open(&ppgtt->vm);
 		i915_vm_put(&ppgtt->vm);
 	}
 
+	mutex_init(&ctx->engines_mutex);
+	e = default_engines(ctx, null_sseu);
+	if (IS_ERR(e))
+		goto err_vm;
+	RCU_INIT_POINTER(ctx->engines, e);
+
+	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
+	mutex_init(&ctx->lut_mutex);
+
 	return ctx;
 
+err_vm:
+	if (ctx->vm)
+		i915_vm_close(ctx->vm);
 err_free:
 	kfree(ctx);
 	return NULL;
-
-err_put:
-	i915_gem_context_set_closed(ctx);
-	i915_gem_context_put(ctx);
-	return NULL;
 }
 
 void mock_context_close(struct i915_gem_context *ctx)
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* [Intel-gfx] [PATCH 27/27] drm/i915/gem: Roll all of context creation together
@ 2021-05-03 15:57   ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-03 15:57 UTC (permalink / raw)
  To: intel-gfx, dri-devel

Now that we have the whole engine set and VM at context creation time,
we can just assign those fields instead of creating first and handling
the VM and engines later.  This lets us avoid creating useless VMs and
engine sets and lets us get rid of the complex VM setting code.

Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
---
 drivers/gpu/drm/i915/gem/i915_gem_context.c   | 159 ++++++------------
 .../gpu/drm/i915/gem/selftests/mock_context.c |  33 ++--
 2 files changed, 64 insertions(+), 128 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 6e5828fe1a792..6bffb0e579b4e 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1302,56 +1302,6 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
 	return 0;
 }
 
-static struct i915_gem_context *
-__create_context(struct drm_i915_private *i915,
-		 const struct i915_gem_proto_context *pc)
-{
-	struct i915_gem_context *ctx;
-	struct i915_gem_engines *e;
-	int err;
-	int i;
-
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-	if (!ctx)
-		return ERR_PTR(-ENOMEM);
-
-	kref_init(&ctx->ref);
-	ctx->i915 = i915;
-	ctx->sched = pc->sched;
-	mutex_init(&ctx->mutex);
-	INIT_LIST_HEAD(&ctx->link);
-
-	spin_lock_init(&ctx->stale.lock);
-	INIT_LIST_HEAD(&ctx->stale.engines);
-
-	mutex_init(&ctx->engines_mutex);
-	e = default_engines(ctx, pc->legacy_rcs_sseu);
-	if (IS_ERR(e)) {
-		err = PTR_ERR(e);
-		goto err_free;
-	}
-	RCU_INIT_POINTER(ctx->engines, e);
-
-	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
-	mutex_init(&ctx->lut_mutex);
-
-	/* NB: Mark all slices as needing a remap so that when the context first
-	 * loads it will restore whatever remap state already exists. If there
-	 * is no remap info, it will be a NOP. */
-	ctx->remap_slice = ALL_L3_SLICES(i915);
-
-	ctx->user_flags = pc->user_flags;
-
-	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
-		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
-
-	return ctx;
-
-err_free:
-	kfree(ctx);
-	return ERR_PTR(err);
-}
-
 static inline struct i915_gem_engines *
 __context_engines_await(const struct i915_gem_context *ctx,
 			bool *user_engines)
@@ -1395,86 +1345,77 @@ context_apply_all(struct i915_gem_context *ctx,
 	i915_sw_fence_complete(&e->fence);
 }
 
-static void __apply_ppgtt(struct intel_context *ce, void *vm)
-{
-	i915_vm_put(ce->vm);
-	ce->vm = i915_vm_get(vm);
-}
-
-static struct i915_address_space *
-__set_ppgtt(struct i915_gem_context *ctx, struct i915_address_space *vm)
-{
-	struct i915_address_space *old;
-
-	old = rcu_replace_pointer(ctx->vm,
-				  i915_vm_open(vm),
-				  lockdep_is_held(&ctx->mutex));
-	GEM_BUG_ON(old && i915_vm_is_4lvl(vm) != i915_vm_is_4lvl(old));
-
-	context_apply_all(ctx, __apply_ppgtt, vm);
-
-	return old;
-}
-
-static void __assign_ppgtt(struct i915_gem_context *ctx,
-			   struct i915_address_space *vm)
-{
-	if (vm == rcu_access_pointer(ctx->vm))
-		return;
-
-	vm = __set_ppgtt(ctx, vm);
-	if (vm)
-		i915_vm_close(vm);
-}
-
 static struct i915_gem_context *
 i915_gem_create_context(struct drm_i915_private *i915,
 			const struct i915_gem_proto_context *pc)
 {
 	struct i915_gem_context *ctx;
-	int ret;
+	struct i915_gem_engines *e;
+	int err;
+	int i;
 
-	ctx = __create_context(i915, pc);
-	if (IS_ERR(ctx))
-		return ctx;
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return ERR_PTR(-ENOMEM);
 
-	if (pc->vm) {
-		mutex_lock(&ctx->mutex);
-		__assign_ppgtt(ctx, pc->vm);
-		mutex_unlock(&ctx->mutex);
-	}
+	kref_init(&ctx->ref);
+	ctx->i915 = i915;
+	ctx->sched = pc->sched;
+	mutex_init(&ctx->mutex);
+	INIT_LIST_HEAD(&ctx->link);
 
-	if (pc->num_user_engines >= 0) {
-		struct i915_gem_engines *engines;
+	spin_lock_init(&ctx->stale.lock);
+	INIT_LIST_HEAD(&ctx->stale.engines);
 
-		engines = user_engines(ctx, pc->num_user_engines,
-				       pc->user_engines);
-		if (IS_ERR(engines)) {
-			context_close(ctx);
-			return ERR_CAST(engines);
-		}
+	if (pc->vm)
+		RCU_INIT_POINTER(ctx->vm, i915_vm_open(pc->vm));
 
-		mutex_lock(&ctx->engines_mutex);
+	mutex_init(&ctx->engines_mutex);
+	if (pc->num_user_engines >= 0) {
 		i915_gem_context_set_user_engines(ctx);
-		engines = rcu_replace_pointer(ctx->engines, engines, 1);
-		mutex_unlock(&ctx->engines_mutex);
-
-		free_engines(engines);
+		e = user_engines(ctx, pc->num_user_engines, pc->user_engines);
+	} else {
+		i915_gem_context_clear_user_engines(ctx);
+		e = default_engines(ctx, pc->legacy_rcs_sseu);
 	}
+	if (IS_ERR(e)) {
+		err = PTR_ERR(e);
+		goto err_vm;
+	}
+	RCU_INIT_POINTER(ctx->engines, e);
+
+	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
+	mutex_init(&ctx->lut_mutex);
+
+	/* NB: Mark all slices as needing a remap so that when the context first
+	 * loads it will restore whatever remap state already exists. If there
+	 * is no remap info, it will be a NOP. */
+	ctx->remap_slice = ALL_L3_SLICES(i915);
+
+	ctx->user_flags = pc->user_flags;
+
+	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
+		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
 
 	if (pc->single_timeline) {
-		ret = drm_syncobj_create(&ctx->syncobj,
+		err = drm_syncobj_create(&ctx->syncobj,
 					 DRM_SYNCOBJ_CREATE_SIGNALED,
 					 NULL);
-		if (ret) {
-			context_close(ctx);
-			return ERR_PTR(ret);
-		}
+		if (err)
+			goto err_engines;
 	}
 
 	trace_i915_context_create(ctx);
 
 	return ctx;
+
+err_engines:
+	free_engines(e);
+err_vm:
+	if (ctx->vm)
+		i915_vm_close(ctx->vm);
+	kfree(ctx);
+	return ERR_PTR(err);
 }
 
 static void init_contexts(struct i915_gem_contexts *gc)
diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
index 500ef27ba4771..fee070df1c97b 100644
--- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
@@ -31,15 +31,6 @@ mock_context(struct drm_i915_private *i915,
 
 	i915_gem_context_set_persistence(ctx);
 
-	mutex_init(&ctx->engines_mutex);
-	e = default_engines(ctx, null_sseu);
-	if (IS_ERR(e))
-		goto err_free;
-	RCU_INIT_POINTER(ctx->engines, e);
-
-	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
-	mutex_init(&ctx->lut_mutex);
-
 	if (name) {
 		struct i915_ppgtt *ppgtt;
 
@@ -47,25 +38,29 @@ mock_context(struct drm_i915_private *i915,
 
 		ppgtt = mock_ppgtt(i915, name);
 		if (!ppgtt)
-			goto err_put;
-
-		mutex_lock(&ctx->mutex);
-		__set_ppgtt(ctx, &ppgtt->vm);
-		mutex_unlock(&ctx->mutex);
+			goto err_free;
 
+		ctx->vm = i915_vm_open(&ppgtt->vm);
 		i915_vm_put(&ppgtt->vm);
 	}
 
+	mutex_init(&ctx->engines_mutex);
+	e = default_engines(ctx, null_sseu);
+	if (IS_ERR(e))
+		goto err_vm;
+	RCU_INIT_POINTER(ctx->engines, e);
+
+	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
+	mutex_init(&ctx->lut_mutex);
+
 	return ctx;
 
+err_vm:
+	if (ctx->vm)
+		i915_vm_close(ctx->vm);
 err_free:
 	kfree(ctx);
 	return NULL;
-
-err_put:
-	i915_gem_context_set_closed(ctx);
-	i915_gem_context_put(ctx);
-	return NULL;
 }
 
 void mock_context_close(struct i915_gem_context *ctx)
-- 
2.31.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
  (?)
@ 2021-05-03 18:52     ` kernel test robot
  -1 siblings, 0 replies; 135+ messages in thread
From: kernel test robot @ 2021-05-03 18:52 UTC (permalink / raw)
  To: Jason Ekstrand, intel-gfx, dri-devel; +Cc: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 6511 bytes --]

Hi Jason,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on drm-intel/for-linux-next]
[also build test WARNING on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
[cannot apply to tegra-drm/drm/tegra/for-next drm/drm-next v5.12]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: i386-randconfig-s002-20210503 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.3-341-g8af24329-dirty
        # https://github.com/0day-ci/linux/commit/6af12f5ca765ecd59075344f3be4c4c0b68ef95e
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
        git checkout 6af12f5ca765ecd59075344f3be4c4c0b68ef95e
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)
   drivers/gpu/drm/i915/gt/intel_reset.c:1329:5: sparse: sparse: context imbalance in 'intel_gt_reset_trylock' - different lock contexts for basic block
   drivers/gpu/drm/i915/gt/intel_reset.c: note: in included file:
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/gt/intel_execlists_submission.c: note: in included file (through drivers/gpu/drm/i915/selftests/igt_spinner.h, drivers/gpu/drm/i915/gt/selftest_execlists.c):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/gem/i915_gem_object.c: note: in included file:
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
   drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space [noderef] __rcu *
   drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/i915_gem_gtt.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_gem_gtt.c):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/i915_vma.c: note: in included file:
>> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space *
   drivers/gpu/drm/i915/i915_vma.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_vma.c):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *

vim +163 drivers/gpu/drm/i915/gem/i915_gem_context.h

a4e7ccdac38ec8 Chris Wilson 2019-10-04  156  
a4e7ccdac38ec8 Chris Wilson 2019-10-04  157  static inline struct i915_address_space *
a4e7ccdac38ec8 Chris Wilson 2019-10-04  158  i915_gem_context_get_vm_rcu(struct i915_gem_context *ctx)
a4e7ccdac38ec8 Chris Wilson 2019-10-04  159  {
a4e7ccdac38ec8 Chris Wilson 2019-10-04  160  	struct i915_address_space *vm;
a4e7ccdac38ec8 Chris Wilson 2019-10-04  161  
a4e7ccdac38ec8 Chris Wilson 2019-10-04  162  	rcu_read_lock();
a4e7ccdac38ec8 Chris Wilson 2019-10-04 @163  	vm = rcu_dereference(ctx->vm);
a4e7ccdac38ec8 Chris Wilson 2019-10-04  164  	if (!vm)
a4e7ccdac38ec8 Chris Wilson 2019-10-04  165  		vm = &ctx->i915->ggtt.vm;
a4e7ccdac38ec8 Chris Wilson 2019-10-04  166  	vm = i915_vm_get(vm);
a4e7ccdac38ec8 Chris Wilson 2019-10-04  167  	rcu_read_unlock();
a4e7ccdac38ec8 Chris Wilson 2019-10-04  168  
a4e7ccdac38ec8 Chris Wilson 2019-10-04  169  	return vm;
a4e7ccdac38ec8 Chris Wilson 2019-10-04  170  }
a4e7ccdac38ec8 Chris Wilson 2019-10-04  171  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 40790 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts
@ 2021-05-03 18:52     ` kernel test robot
  0 siblings, 0 replies; 135+ messages in thread
From: kernel test robot @ 2021-05-03 18:52 UTC (permalink / raw)
  To: Jason Ekstrand, intel-gfx, dri-devel; +Cc: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 6511 bytes --]

Hi Jason,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on drm-intel/for-linux-next]
[also build test WARNING on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
[cannot apply to tegra-drm/drm/tegra/for-next drm/drm-next v5.12]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: i386-randconfig-s002-20210503 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.3-341-g8af24329-dirty
        # https://github.com/0day-ci/linux/commit/6af12f5ca765ecd59075344f3be4c4c0b68ef95e
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
        git checkout 6af12f5ca765ecd59075344f3be4c4c0b68ef95e
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)
   drivers/gpu/drm/i915/gt/intel_reset.c:1329:5: sparse: sparse: context imbalance in 'intel_gt_reset_trylock' - different lock contexts for basic block
   drivers/gpu/drm/i915/gt/intel_reset.c: note: in included file:
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/gt/intel_execlists_submission.c: note: in included file (through drivers/gpu/drm/i915/selftests/igt_spinner.h, drivers/gpu/drm/i915/gt/selftest_execlists.c):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/gem/i915_gem_object.c: note: in included file:
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
   drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space [noderef] __rcu *
   drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/i915_gem_gtt.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_gem_gtt.c):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/i915_vma.c: note: in included file:
>> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space *
   drivers/gpu/drm/i915/i915_vma.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_vma.c):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *

vim +163 drivers/gpu/drm/i915/gem/i915_gem_context.h

a4e7ccdac38ec8 Chris Wilson 2019-10-04  156  
a4e7ccdac38ec8 Chris Wilson 2019-10-04  157  static inline struct i915_address_space *
a4e7ccdac38ec8 Chris Wilson 2019-10-04  158  i915_gem_context_get_vm_rcu(struct i915_gem_context *ctx)
a4e7ccdac38ec8 Chris Wilson 2019-10-04  159  {
a4e7ccdac38ec8 Chris Wilson 2019-10-04  160  	struct i915_address_space *vm;
a4e7ccdac38ec8 Chris Wilson 2019-10-04  161  
a4e7ccdac38ec8 Chris Wilson 2019-10-04  162  	rcu_read_lock();
a4e7ccdac38ec8 Chris Wilson 2019-10-04 @163  	vm = rcu_dereference(ctx->vm);
a4e7ccdac38ec8 Chris Wilson 2019-10-04  164  	if (!vm)
a4e7ccdac38ec8 Chris Wilson 2019-10-04  165  		vm = &ctx->i915->ggtt.vm;
a4e7ccdac38ec8 Chris Wilson 2019-10-04  166  	vm = i915_vm_get(vm);
a4e7ccdac38ec8 Chris Wilson 2019-10-04  167  	rcu_read_unlock();
a4e7ccdac38ec8 Chris Wilson 2019-10-04  168  
a4e7ccdac38ec8 Chris Wilson 2019-10-04  169  	return vm;
a4e7ccdac38ec8 Chris Wilson 2019-10-04  170  }
a4e7ccdac38ec8 Chris Wilson 2019-10-04  171  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 40790 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts
@ 2021-05-03 18:52     ` kernel test robot
  0 siblings, 0 replies; 135+ messages in thread
From: kernel test robot @ 2021-05-03 18:52 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 6604 bytes --]

Hi Jason,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on drm-intel/for-linux-next]
[also build test WARNING on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
[cannot apply to tegra-drm/drm/tegra/for-next drm/drm-next v5.12]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: i386-randconfig-s002-20210503 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.3-341-g8af24329-dirty
        # https://github.com/0day-ci/linux/commit/6af12f5ca765ecd59075344f3be4c4c0b68ef95e
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
        git checkout 6af12f5ca765ecd59075344f3be4c4c0b68ef95e
        # save the attached .config to linux build tree
        make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)
   drivers/gpu/drm/i915/gt/intel_reset.c:1329:5: sparse: sparse: context imbalance in 'intel_gt_reset_trylock' - different lock contexts for basic block
   drivers/gpu/drm/i915/gt/intel_reset.c: note: in included file:
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/gt/intel_execlists_submission.c: note: in included file (through drivers/gpu/drm/i915/selftests/igt_spinner.h, drivers/gpu/drm/i915/gt/selftest_execlists.c):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/gem/i915_gem_object.c: note: in included file:
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
   drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse: sparse: incompatible types in comparison expression (different address spaces):
   drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space [noderef] __rcu *
   drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/i915_gem_gtt.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_gem_gtt.c):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
--
   drivers/gpu/drm/i915/i915_vma.c: note: in included file:
>> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space *
   drivers/gpu/drm/i915/i915_vma.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_vma.c):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
>> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *

vim +163 drivers/gpu/drm/i915/gem/i915_gem_context.h

a4e7ccdac38ec8 Chris Wilson 2019-10-04  156  
a4e7ccdac38ec8 Chris Wilson 2019-10-04  157  static inline struct i915_address_space *
a4e7ccdac38ec8 Chris Wilson 2019-10-04  158  i915_gem_context_get_vm_rcu(struct i915_gem_context *ctx)
a4e7ccdac38ec8 Chris Wilson 2019-10-04  159  {
a4e7ccdac38ec8 Chris Wilson 2019-10-04  160  	struct i915_address_space *vm;
a4e7ccdac38ec8 Chris Wilson 2019-10-04  161  
a4e7ccdac38ec8 Chris Wilson 2019-10-04  162  	rcu_read_lock();
a4e7ccdac38ec8 Chris Wilson 2019-10-04 @163  	vm = rcu_dereference(ctx->vm);
a4e7ccdac38ec8 Chris Wilson 2019-10-04  164  	if (!vm)
a4e7ccdac38ec8 Chris Wilson 2019-10-04  165  		vm = &ctx->i915->ggtt.vm;
a4e7ccdac38ec8 Chris Wilson 2019-10-04  166  	vm = i915_vm_get(vm);
a4e7ccdac38ec8 Chris Wilson 2019-10-04  167  	rcu_read_unlock();
a4e7ccdac38ec8 Chris Wilson 2019-10-04  168  
a4e7ccdac38ec8 Chris Wilson 2019-10-04  169  	return vm;
a4e7ccdac38ec8 Chris Wilson 2019-10-04  170  }
a4e7ccdac38ec8 Chris Wilson 2019-10-04  171  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 40790 bytes --]

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 22/27] drm/i915/gem: Delay context creation
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
  (?)
@ 2021-05-03 19:38     ` kernel test robot
  -1 siblings, 0 replies; 135+ messages in thread
From: kernel test robot @ 2021-05-03 19:38 UTC (permalink / raw)
  To: Jason Ekstrand, intel-gfx, dri-devel; +Cc: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2555 bytes --]

Hi Jason,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on drm-intel/for-linux-next]
[also build test ERROR on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
[cannot apply to tegra-drm/drm/tegra/for-next v5.12]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: i386-randconfig-r013-20210503 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/66ce6ce447515a302711a65f731d1e6f66abdcdc
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
        git checkout 66ce6ce447515a302711a65f731d1e6f66abdcdc
        # save the attached .config to linux build tree
        make W=1 W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/i915/gem/i915_gem_context.c:2543:1: error: no previous prototype for 'lazy_create_context_locked' [-Werror=missing-prototypes]
    2543 | lazy_create_context_locked(struct drm_i915_file_private *file_priv,
         | ^~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: all warnings being treated as errors


vim +/lazy_create_context_locked +2543 drivers/gpu/drm/i915/gem/i915_gem_context.c

  2541	
  2542	struct i915_gem_context *
> 2543	lazy_create_context_locked(struct drm_i915_file_private *file_priv,
  2544				   struct i915_gem_proto_context *pc, u32 id)
  2545	{
  2546		struct i915_gem_context *ctx;
  2547		void *old;
  2548	
  2549		lockdep_assert_held(&file_priv->proto_context_lock);
  2550	
  2551		ctx = i915_gem_create_context(file_priv->dev_priv, pc);
  2552		if (IS_ERR(ctx))
  2553			return ctx;
  2554	
  2555		gem_context_register(ctx, file_priv, id);
  2556	
  2557		old = xa_erase(&file_priv->proto_context_xa, id);
  2558		GEM_BUG_ON(old != pc);
  2559		proto_context_close(pc);
  2560	
  2561		/* One for the xarray and one for the caller */
  2562		return i915_gem_context_get(ctx);
  2563	}
  2564	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 42249 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 22/27] drm/i915/gem: Delay context creation
@ 2021-05-03 19:38     ` kernel test robot
  0 siblings, 0 replies; 135+ messages in thread
From: kernel test robot @ 2021-05-03 19:38 UTC (permalink / raw)
  To: Jason Ekstrand, intel-gfx, dri-devel; +Cc: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2555 bytes --]

Hi Jason,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on drm-intel/for-linux-next]
[also build test ERROR on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
[cannot apply to tegra-drm/drm/tegra/for-next v5.12]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: i386-randconfig-r013-20210503 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/66ce6ce447515a302711a65f731d1e6f66abdcdc
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
        git checkout 66ce6ce447515a302711a65f731d1e6f66abdcdc
        # save the attached .config to linux build tree
        make W=1 W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/i915/gem/i915_gem_context.c:2543:1: error: no previous prototype for 'lazy_create_context_locked' [-Werror=missing-prototypes]
    2543 | lazy_create_context_locked(struct drm_i915_file_private *file_priv,
         | ^~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: all warnings being treated as errors


vim +/lazy_create_context_locked +2543 drivers/gpu/drm/i915/gem/i915_gem_context.c

  2541	
  2542	struct i915_gem_context *
> 2543	lazy_create_context_locked(struct drm_i915_file_private *file_priv,
  2544				   struct i915_gem_proto_context *pc, u32 id)
  2545	{
  2546		struct i915_gem_context *ctx;
  2547		void *old;
  2548	
  2549		lockdep_assert_held(&file_priv->proto_context_lock);
  2550	
  2551		ctx = i915_gem_create_context(file_priv->dev_priv, pc);
  2552		if (IS_ERR(ctx))
  2553			return ctx;
  2554	
  2555		gem_context_register(ctx, file_priv, id);
  2556	
  2557		old = xa_erase(&file_priv->proto_context_xa, id);
  2558		GEM_BUG_ON(old != pc);
  2559		proto_context_close(pc);
  2560	
  2561		/* One for the xarray and one for the caller */
  2562		return i915_gem_context_get(ctx);
  2563	}
  2564	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 42249 bytes --]

[-- Attachment #3: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 22/27] drm/i915/gem: Delay context creation
@ 2021-05-03 19:38     ` kernel test robot
  0 siblings, 0 replies; 135+ messages in thread
From: kernel test robot @ 2021-05-03 19:38 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 2621 bytes --]

Hi Jason,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on drm-intel/for-linux-next]
[also build test ERROR on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
[cannot apply to tegra-drm/drm/tegra/for-next v5.12]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
base:   git://anongit.freedesktop.org/drm-intel for-linux-next
config: i386-randconfig-r013-20210503 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/66ce6ce447515a302711a65f731d1e6f66abdcdc
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
        git checkout 66ce6ce447515a302711a65f731d1e6f66abdcdc
        # save the attached .config to linux build tree
        make W=1 W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/gpu/drm/i915/gem/i915_gem_context.c:2543:1: error: no previous prototype for 'lazy_create_context_locked' [-Werror=missing-prototypes]
    2543 | lazy_create_context_locked(struct drm_i915_file_private *file_priv,
         | ^~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: all warnings being treated as errors


vim +/lazy_create_context_locked +2543 drivers/gpu/drm/i915/gem/i915_gem_context.c

  2541	
  2542	struct i915_gem_context *
> 2543	lazy_create_context_locked(struct drm_i915_file_private *file_priv,
  2544				   struct i915_gem_proto_context *pc, u32 id)
  2545	{
  2546		struct i915_gem_context *ctx;
  2547		void *old;
  2548	
  2549		lockdep_assert_held(&file_priv->proto_context_lock);
  2550	
  2551		ctx = i915_gem_create_context(file_priv->dev_priv, pc);
  2552		if (IS_ERR(ctx))
  2553			return ctx;
  2554	
  2555		gem_context_register(ctx, file_priv, id);
  2556	
  2557		old = xa_erase(&file_priv->proto_context_xa, id);
  2558		GEM_BUG_ON(old != pc);
  2559		proto_context_close(pc);
  2560	
  2561		/* One for the xarray and one for the caller */
  2562		return i915_gem_context_get(ctx);
  2563	}
  2564	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 42249 bytes --]

^ permalink raw reply	[flat|nested] 135+ messages in thread

* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915/gem: ioctl clean-ups (rev4)
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
                   ` (27 preceding siblings ...)
  (?)
@ 2021-05-03 20:33 ` Patchwork
  -1 siblings, 0 replies; 135+ messages in thread
From: Patchwork @ 2021-05-03 20:33 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx

== Series Details ==

Series: drm/i915/gem: ioctl clean-ups (rev4)
URL   : https://patchwork.freedesktop.org/series/89443/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
8d290e6238e7 drm/i915: Drop I915_CONTEXT_PARAM_RINGSIZE
-:177: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#177: 
deleted file mode 100644

total: 0 errors, 1 warnings, 0 checks, 159 lines checked
904e773fd289 drm/i915: Stop storing the ring size in the ring pointer
1c4bd7993075 drm/i915: Drop I915_CONTEXT_PARAM_NO_ZEROMAP
8a99bfd835ff drm/i915/gem: Set the watchdog timeout directly in intel_context_set_gem (v2)
715ae33bf9aa drm/i915/gem: Return void from context_apply_all
5e5b1ed85776 drm/i915: Drop the CONTEXT_CLONE API
8032eecf682d drm/i915: Implement SINGLE_TIMELINE with a syncobj (v4)
895c2e4c3bdb drm/i915: Drop getparam support for I915_CONTEXT_PARAM_ENGINES
25801b1c52c4 drm/i915/gem: Disallow bonding of virtual engines (v3)
c8b0561320c7 drm/i915/gem: Remove engine auto-magic with FENCE_SUBMIT
9ce8f241d55a drm/i915/request: Remove the hook from await_execution
255f845b4348 drm/i915/gem: Disallow creating contexts with too many engines
178b1c5883fd drm/i915: Stop manually RCU banging in reset_stats_ioctl (v2)
b8dd7d97db62 drm/i915/gem: Add a separate validate_priority helper
72c4d93eb050 drm/i915: Add gem/i915_gem_context.h to the docs
4b7c0de90422 drm/i915/gem: Add an intermediate proto_context struct
-:274: WARNING:REPEATED_WORD: Possible repeated word: 'See'
#274: FILE: drivers/gpu/drm/i915/gem/i915_gem_context_types.h:87:
+	/** @single_timeline: See See i915_gem_context::syncobj */

total: 0 errors, 1 warnings, 0 checks, 271 lines checked
b3c8a4f17cc3 drm/i915/gem: Rework error handling in default_engines
3353ac966ea8 drm/i915/gem: Optionally set SSEU in intel_context_set_gem
56d933b875f6 drm/i915/gem: Use the proto-context to handle create parameters
-:79: WARNING:UNSPECIFIED_INT: Prefer 'unsigned int' to bare use of 'unsigned'
#79: FILE: drivers/gpu/drm/i915/gem/i915_gem_context.c:326:
+	unsigned num_engines;

-:260: ERROR:CODE_INDENT: code indent should use tabs where possible
#260: FILE: drivers/gpu/drm/i915/gem/i915_gem_context.c:507:
+^I^I^I         struct i915_gem_proto_context *pc,$

-:260: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#260: FILE: drivers/gpu/drm/i915/gem/i915_gem_context.c:507:
+static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
+			         struct i915_gem_proto_context *pc,

-:261: ERROR:CODE_INDENT: code indent should use tabs where possible
#261: FILE: drivers/gpu/drm/i915/gem/i915_gem_context.c:508:
+^I^I^I         const struct drm_i915_gem_context_param *args)$

-:369: WARNING:LONG_LINE: line length of 101 exceeds 100 columns
#369: FILE: drivers/gpu/drm/i915/gem/i915_gem_context.c:616:
+	if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))

-:369: CHECK:UNNECESSARY_PARENTHESES: Unnecessary parentheses around 'pc->num_user_engines >= 0'
#369: FILE: drivers/gpu/drm/i915/gem/i915_gem_context.c:616:
+	if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))

total: 2 errors, 2 warnings, 2 checks, 698 lines checked
0a99acad1096 drm/i915/gem: Return an error ptr from context_lookup
-:60: WARNING:LIKELY_MISUSE: nested (un)?likely() calls, IS_ERR already uses unlikely() internally
#60: FILE: drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c:742:
+	if (unlikely(IS_ERR(ctx)))

total: 0 errors, 1 warnings, 0 checks, 60 lines checked
c7bd40e3ab15 drm/i915/gt: Drop i915_address_space::file (v2)
-:9: ERROR:GIT_COMMIT_ID: Please use git commit description style 'commit <12+ chars of sha1> ("<title line>")' - ie: 'commit 2bfa996e031b ("drm/i915: Store owning file on the i915_address_space")'
#9: 
It was added in 2bfa996e031b ("drm/i915: Store owning file on the

-:11: ERROR:GIT_COMMIT_ID: Please use git commit description style 'commit <12+ chars of sha1> ("<title line>")' - ie: 'commit f6e8aa387171 ("drm/i915: Report the number of closed vma held by each context in debugfs")'
#11: 
the difference between the global GTT and a PPGTT.  In f6e8aa387171

-:15: ERROR:GIT_COMMIT_ID: Please use git commit description style 'commit <12+ chars of sha1> ("<title line>")' - ie: 'commit db80a1294c23 ("drm/i915/gem: Remove per-client stats from debugfs/i915_gem_objects")'
#15: 
were entirely nuked in db80a1294c23 ("drm/i915/gem: Remove per-client

total: 3 errors, 0 warnings, 0 checks, 55 lines checked
4dced50754af drm/i915/gem: Delay context creation
6c98c574e624 drm/i915/gem: Don't allow changing the VM on running contexts
-:7: WARNING:COMMIT_MESSAGE: Missing commit description - Add an appropriate one

total: 0 errors, 1 warnings, 0 checks, 424 lines checked
60bb25bf2322 drm/i915/gem: Don't allow changing the engine set on running contexts
-:8: WARNING:COMMIT_MESSAGE: Missing commit description - Add an appropriate one

total: 0 errors, 1 warnings, 0 checks, 316 lines checked
c7405d6d9678 drm/i915/selftests: Take a VM in kernel_context()
304ef8c57818 i915/gem/selftests: Assign the VM at context creation in igt_shared_ctx_exec
bd3af6aa2571 drm/i915/gem: Roll all of context creation together
-:176: WARNING:BLOCK_COMMENT_STYLE: Block comments use a trailing */ on a separate line
#176: FILE: drivers/gpu/drm/i915/gem/i915_gem_context.c:1392:
+	 * is no remap info, it will be a NOP. */

total: 0 errors, 1 warnings, 0 checks, 246 lines checked


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* [Intel-gfx] ✗ Fi.CI.SPARSE: warning for drm/i915/gem: ioctl clean-ups (rev4)
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
                   ` (28 preceding siblings ...)
  (?)
@ 2021-05-03 20:35 ` Patchwork
  -1 siblings, 0 replies; 135+ messages in thread
From: Patchwork @ 2021-05-03 20:35 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx

== Series Details ==

Series: drm/i915/gem: ioctl clean-ups (rev4)
URL   : https://patchwork.freedesktop.org/series/89443/
State : warning

== Summary ==

$ dim sparse --fast origin/drm-tip
Sparse version: v0.6.2
Fast mode used, each commit won't be checked separately.
-
+drivers/gpu/drm/i915/gem/i915_gem_context.c:1371:17: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.c:1371:17:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:1371:17:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:1589:14: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.c:1589:14:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:1589:14:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:1912:25: warning: symbol 'lazy_create_context_locked' was not declared. Should it be static?
+drivers/gpu/drm/i915/gem/i915_gem_context.c:2117:21: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.c:2117:21:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:2117:21:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:2118:39: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.c:2118:39:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:2118:39:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:767:9: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.c:767:9:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:767:9:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:776:22: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.c:776:22:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:776:22:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:795:27: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.c:795:27:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:795:27:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:813:13: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.c:813:13:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.c:813:13:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16:    struct i915_address_space [noderef] __rcu *
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: error: incompatible types in comparison expression (different address spaces):
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: error: incompatible types in comparison expression (different address spaces):
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: error: incompatible types in comparison expression (different address spaces):
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: error: incompatible types in comparison expression (different address spaces):
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: error: incompatible types in comparison expression (different address spaces):
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space *
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space *
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space *
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space *
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space *
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space [noderef] __rcu *
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space [noderef] __rcu *
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space [noderef] __rcu *
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space [noderef] __rcu *
+./drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c:746:13: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c:746:13:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c:746:13:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c:772:49: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c:772:49:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c:772:49:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:33:16:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:704:33: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:704:33:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:704:33:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:838:33: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:838:33:    struct i915_address_space *
+drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c:838:33:    struct i915_address_space [noderef] __rcu *
+drivers/gpu/drm/i915/gt/intel_engine_stats.h:27:9: warning: trying to copy expression type 31
+drivers/gpu/drm/i915/gt/intel_engine_stats.h:27:9: warning: trying to copy expression type 31
+drivers/gpu/drm/i915/gt/intel_engine_stats.h:27:9: warning: trying to copy expression type 31
+drivers/gpu/drm/i915/gt/intel_engine_stats.h:32:9: warning: trying to copy expression type 31
+drivers/gpu/drm/i915/gt/intel_engine_stats.h:32:9: warning: trying to copy expression type 31
+drivers/gpu/drm/i915/gt/intel_engine_stats.h:49:9: warning: trying to copy expression type 31
+drivers/gpu/drm/i915/gt/intel_engine_stats.h:49:9: warning: trying to copy expression type 31
+drivers/gpu/drm/i915/gt/intel_engine_stats.h:49:9: warning: trying to copy expression type 31
+drivers/gpu/drm/i915/gt/intel_engine_stats.h:56:9: warning: trying to copy expression type 31
+drivers/gpu/drm/i915/gt/intel_engine_stats.h:56:9: warning: trying to copy expression type 31
+drivers/gpu/drm/i915/gt/intel_reset.c:1329:5: warning: context imbalance in 'intel_gt_reset_trylock' - different lock contexts for basic block
+drivers/gpu/drm/i915/gt/intel_ring_submission.c:1203:24: warning: Using plain integer as NULL pointer
+drivers/gpu/drm/i915/gvt/mmio.c:295:23: warning: memcpy with byte count of 279040
+drivers/gpu/drm/i915/i915_perf.c:1434:15: warning: memset with byte count of 16777216
+drivers/gpu/drm/i915/i915_perf.c:1488:15: warning: memset with byte count of 16777216
+drivers/gpu/drm/i915/selftests/i915_syncmap.c:80:54: warning: dubious: x | !y
+drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/i915/selftests/i915_vma.c:42:24:    struct i915_address_space *
+drivers/gpu/drm/i915/selftests/i915_vma.c:42:24:    struct i915_address_space [noderef] __rcu *
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'fwtable_read16' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'fwtable_read32' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'fwtable_read64' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'fwtable_read8' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'fwtable_write16' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'fwtable_write32' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'fwtable_write8' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen11_fwtable_read16' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen11_fwtable_read32' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen11_fwtable_read64' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen11_fwtable_read8' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen11_fwtable_write16' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen11_fwtable_write32' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen11_fwtable_write8' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen12_fwtable_read16' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen12_fwtable_read32' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen12_fwtable_read64' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen12_fwtable_read8' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen12_fwtable_write16' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen12_fwtable_write32' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen12_fwtable_write8' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen6_read16' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen6_read32' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen6_read64' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen6_read8' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen6_write16' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen6_write32' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen6_write8' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen8_write16' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen8_write32' - different lock contexts for basic block
+./include/linux/spinlock.h:409:9: warning: context imbalance in 'gen8_write8' - different lock contexts for basic block


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* [Intel-gfx] ✗ Fi.CI.DOCS: warning for drm/i915/gem: ioctl clean-ups (rev4)
  2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
                   ` (29 preceding siblings ...)
  (?)
@ 2021-05-03 20:38 ` Patchwork
  -1 siblings, 0 replies; 135+ messages in thread
From: Patchwork @ 2021-05-03 20:38 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx

== Series Details ==

Series: drm/i915/gem: ioctl clean-ups (rev4)
URL   : https://patchwork.freedesktop.org/series/89443/
State : warning

== Summary ==

$ make htmldocs 2>&1 > /dev/null | grep i915
./drivers/gpu/drm/i915/gem/i915_gem_context_types.h:201: warning: Function parameter or member 'legacy_rcs_sseu' not described in 'i915_gem_proto_context'


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 02/27] drm/i915: Stop storing the ring size in the ring pointer
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04  8:47     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  8:47 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:23AM -0500, Jason Ekstrand wrote:
> Previously, we were storing the ring size in the ring pointer before it
> was actually allocated.  We would then guard setting the ring size on
> checking for CONTEXT_ALLOC_BIT.  This is error-prone at best and really
> only saves us a few bytes on something that already burns at least 4K.
> Instead, this patch adds a new ring_size field and makes everything use
> that.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 3 +--
>  drivers/gpu/drm/i915/gt/intel_context.c       | 3 ++-
>  drivers/gpu/drm/i915/gt/intel_context.h       | 5 -----
>  drivers/gpu/drm/i915/gt/intel_context_types.h | 1 +
>  drivers/gpu/drm/i915/gt/intel_lrc.c           | 2 +-
>  drivers/gpu/drm/i915/gt/selftest_execlists.c  | 2 +-
>  drivers/gpu/drm/i915/gt/selftest_mocs.c       | 2 +-
>  drivers/gpu/drm/i915/gt/selftest_timeline.c   | 2 +-
>  drivers/gpu/drm/i915/gvt/scheduler.c          | 7 ++-----
>  9 files changed, 10 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index e52b85b8f923d..2ba4c7e4011b4 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -211,8 +211,7 @@ static void intel_context_set_gem(struct intel_context *ce,
>  	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
>  	RCU_INIT_POINTER(ce->gem_context, ctx);
>  
> -	if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags))
> -		ce->ring = __intel_context_ring_size(SZ_16K);
> +	ce->ring_size = SZ_16K;
>  
>  	if (rcu_access_pointer(ctx->vm)) {
>  		struct i915_address_space *vm;
> diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c
> index 17cf2640b082b..342fa7daa08b5 100644
> --- a/drivers/gpu/drm/i915/gt/intel_context.c
> +++ b/drivers/gpu/drm/i915/gt/intel_context.c
> @@ -372,7 +372,8 @@ intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine)
>  	ce->engine = engine;
>  	ce->ops = engine->cops;
>  	ce->sseu = engine->sseu;
> -	ce->ring = __intel_context_ring_size(SZ_4K);
> +	ce->ring = NULL;
> +	ce->ring_size = SZ_4K;
>  
>  	ewma_runtime_init(&ce->runtime.avg);
>  
> diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h
> index f83a73a2b39fc..b10cbe8fee992 100644
> --- a/drivers/gpu/drm/i915/gt/intel_context.h
> +++ b/drivers/gpu/drm/i915/gt/intel_context.h
> @@ -175,11 +175,6 @@ int intel_context_prepare_remote_request(struct intel_context *ce,
>  
>  struct i915_request *intel_context_create_request(struct intel_context *ce);
>  
> -static inline struct intel_ring *__intel_context_ring_size(u64 sz)
> -{
> -	return u64_to_ptr(struct intel_ring, sz);
> -}
> -
>  static inline bool intel_context_is_barrier(const struct intel_context *ce)
>  {
>  	return test_bit(CONTEXT_BARRIER_BIT, &ce->flags);
> diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
> index ed8c447a7346b..90026c1771055 100644
> --- a/drivers/gpu/drm/i915/gt/intel_context_types.h
> +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
> @@ -82,6 +82,7 @@ struct intel_context {
>  	spinlock_t signal_lock; /* protects signals, the list of requests */
>  
>  	struct i915_vma *state;
> +	u32 ring_size;
>  	struct intel_ring *ring;
>  	struct intel_timeline *timeline;
>  
> diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
> index e86897cde9846..63193c80fb117 100644
> --- a/drivers/gpu/drm/i915/gt/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
> @@ -845,7 +845,7 @@ int lrc_alloc(struct intel_context *ce, struct intel_engine_cs *engine)
>  	if (IS_ERR(vma))
>  		return PTR_ERR(vma);
>  
> -	ring = intel_engine_create_ring(engine, (unsigned long)ce->ring);
> +	ring = intel_engine_create_ring(engine, ce->ring_size);
>  	if (IS_ERR(ring)) {
>  		err = PTR_ERR(ring);
>  		goto err_vma;
> diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> index 1081cd36a2bd3..01d9896dd4844 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> @@ -2793,7 +2793,7 @@ static int __live_preempt_ring(struct intel_engine_cs *engine,
>  			goto err_ce;
>  		}
>  
> -		tmp->ring = __intel_context_ring_size(ring_sz);
> +		tmp->ring_size = ring_sz;
>  
>  		err = intel_context_pin(tmp);
>  		if (err) {
> diff --git a/drivers/gpu/drm/i915/gt/selftest_mocs.c b/drivers/gpu/drm/i915/gt/selftest_mocs.c
> index e55a887d11e2b..f343fa5fd986f 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_mocs.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_mocs.c
> @@ -28,7 +28,7 @@ static struct intel_context *mocs_context_create(struct intel_engine_cs *engine)
>  		return ce;
>  
>  	/* We build large requests to read the registers from the ring */
> -	ce->ring = __intel_context_ring_size(SZ_16K);
> +	ce->ring_size = SZ_16K;
>  
>  	return ce;
>  }
> diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c
> index 9adbd9d147bea..7eedecfb86e59 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_timeline.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c
> @@ -874,7 +874,7 @@ static int create_watcher(struct hwsp_watcher *w,
>  	if (IS_ERR(ce))
>  		return PTR_ERR(ce);
>  
> -	ce->ring = __intel_context_ring_size(ringsz);
> +	ce->ring_size = ringsz;
>  	w->rq = intel_context_create_request(ce);
>  	intel_context_put(ce);
>  	if (IS_ERR(w->rq))
> diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
> index fc735692f21fb..99bc9fed6fbb6 100644
> --- a/drivers/gpu/drm/i915/gvt/scheduler.c
> +++ b/drivers/gpu/drm/i915/gvt/scheduler.c
> @@ -1409,11 +1409,8 @@ int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
>  		intel_context_set_single_submission(ce);
>  
>  		/* Max ring buffer size */
> -		if (!intel_uc_wants_guc_submission(&engine->gt->uc)) {
> -			const unsigned int ring_size = 512 * SZ_4K;
> -
> -			ce->ring = __intel_context_ring_size(ring_size);
> -		}
> +		if (!intel_uc_wants_guc_submission(&engine->gt->uc))
> +			ce->ring_size = 512 * SZ_4K;

A rather funny way of saying SZ_2M. Maybe fix that if you feel like. W/ or
w/o that:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

>  
>  		s->shadow[i] = ce;
>  	}
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 02/27] drm/i915: Stop storing the ring size in the ring pointer
@ 2021-05-04  8:47     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  8:47 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:23AM -0500, Jason Ekstrand wrote:
> Previously, we were storing the ring size in the ring pointer before it
> was actually allocated.  We would then guard setting the ring size on
> checking for CONTEXT_ALLOC_BIT.  This is error-prone at best and really
> only saves us a few bytes on something that already burns at least 4K.
> Instead, this patch adds a new ring_size field and makes everything use
> that.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 3 +--
>  drivers/gpu/drm/i915/gt/intel_context.c       | 3 ++-
>  drivers/gpu/drm/i915/gt/intel_context.h       | 5 -----
>  drivers/gpu/drm/i915/gt/intel_context_types.h | 1 +
>  drivers/gpu/drm/i915/gt/intel_lrc.c           | 2 +-
>  drivers/gpu/drm/i915/gt/selftest_execlists.c  | 2 +-
>  drivers/gpu/drm/i915/gt/selftest_mocs.c       | 2 +-
>  drivers/gpu/drm/i915/gt/selftest_timeline.c   | 2 +-
>  drivers/gpu/drm/i915/gvt/scheduler.c          | 7 ++-----
>  9 files changed, 10 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index e52b85b8f923d..2ba4c7e4011b4 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -211,8 +211,7 @@ static void intel_context_set_gem(struct intel_context *ce,
>  	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
>  	RCU_INIT_POINTER(ce->gem_context, ctx);
>  
> -	if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags))
> -		ce->ring = __intel_context_ring_size(SZ_16K);
> +	ce->ring_size = SZ_16K;
>  
>  	if (rcu_access_pointer(ctx->vm)) {
>  		struct i915_address_space *vm;
> diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c
> index 17cf2640b082b..342fa7daa08b5 100644
> --- a/drivers/gpu/drm/i915/gt/intel_context.c
> +++ b/drivers/gpu/drm/i915/gt/intel_context.c
> @@ -372,7 +372,8 @@ intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine)
>  	ce->engine = engine;
>  	ce->ops = engine->cops;
>  	ce->sseu = engine->sseu;
> -	ce->ring = __intel_context_ring_size(SZ_4K);
> +	ce->ring = NULL;
> +	ce->ring_size = SZ_4K;
>  
>  	ewma_runtime_init(&ce->runtime.avg);
>  
> diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h
> index f83a73a2b39fc..b10cbe8fee992 100644
> --- a/drivers/gpu/drm/i915/gt/intel_context.h
> +++ b/drivers/gpu/drm/i915/gt/intel_context.h
> @@ -175,11 +175,6 @@ int intel_context_prepare_remote_request(struct intel_context *ce,
>  
>  struct i915_request *intel_context_create_request(struct intel_context *ce);
>  
> -static inline struct intel_ring *__intel_context_ring_size(u64 sz)
> -{
> -	return u64_to_ptr(struct intel_ring, sz);
> -}
> -
>  static inline bool intel_context_is_barrier(const struct intel_context *ce)
>  {
>  	return test_bit(CONTEXT_BARRIER_BIT, &ce->flags);
> diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
> index ed8c447a7346b..90026c1771055 100644
> --- a/drivers/gpu/drm/i915/gt/intel_context_types.h
> +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
> @@ -82,6 +82,7 @@ struct intel_context {
>  	spinlock_t signal_lock; /* protects signals, the list of requests */
>  
>  	struct i915_vma *state;
> +	u32 ring_size;
>  	struct intel_ring *ring;
>  	struct intel_timeline *timeline;
>  
> diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
> index e86897cde9846..63193c80fb117 100644
> --- a/drivers/gpu/drm/i915/gt/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
> @@ -845,7 +845,7 @@ int lrc_alloc(struct intel_context *ce, struct intel_engine_cs *engine)
>  	if (IS_ERR(vma))
>  		return PTR_ERR(vma);
>  
> -	ring = intel_engine_create_ring(engine, (unsigned long)ce->ring);
> +	ring = intel_engine_create_ring(engine, ce->ring_size);
>  	if (IS_ERR(ring)) {
>  		err = PTR_ERR(ring);
>  		goto err_vma;
> diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> index 1081cd36a2bd3..01d9896dd4844 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> @@ -2793,7 +2793,7 @@ static int __live_preempt_ring(struct intel_engine_cs *engine,
>  			goto err_ce;
>  		}
>  
> -		tmp->ring = __intel_context_ring_size(ring_sz);
> +		tmp->ring_size = ring_sz;
>  
>  		err = intel_context_pin(tmp);
>  		if (err) {
> diff --git a/drivers/gpu/drm/i915/gt/selftest_mocs.c b/drivers/gpu/drm/i915/gt/selftest_mocs.c
> index e55a887d11e2b..f343fa5fd986f 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_mocs.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_mocs.c
> @@ -28,7 +28,7 @@ static struct intel_context *mocs_context_create(struct intel_engine_cs *engine)
>  		return ce;
>  
>  	/* We build large requests to read the registers from the ring */
> -	ce->ring = __intel_context_ring_size(SZ_16K);
> +	ce->ring_size = SZ_16K;
>  
>  	return ce;
>  }
> diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c
> index 9adbd9d147bea..7eedecfb86e59 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_timeline.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c
> @@ -874,7 +874,7 @@ static int create_watcher(struct hwsp_watcher *w,
>  	if (IS_ERR(ce))
>  		return PTR_ERR(ce);
>  
> -	ce->ring = __intel_context_ring_size(ringsz);
> +	ce->ring_size = ringsz;
>  	w->rq = intel_context_create_request(ce);
>  	intel_context_put(ce);
>  	if (IS_ERR(w->rq))
> diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
> index fc735692f21fb..99bc9fed6fbb6 100644
> --- a/drivers/gpu/drm/i915/gvt/scheduler.c
> +++ b/drivers/gpu/drm/i915/gvt/scheduler.c
> @@ -1409,11 +1409,8 @@ int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
>  		intel_context_set_single_submission(ce);
>  
>  		/* Max ring buffer size */
> -		if (!intel_uc_wants_guc_submission(&engine->gt->uc)) {
> -			const unsigned int ring_size = 512 * SZ_4K;
> -
> -			ce->ring = __intel_context_ring_size(ring_size);
> -		}
> +		if (!intel_uc_wants_guc_submission(&engine->gt->uc))
> +			ce->ring_size = 512 * SZ_4K;

A rather funny way of saying SZ_2M. Maybe fix that if you feel like. W/ or
w/o that:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

>  
>  		s->shadow[i] = ce;
>  	}
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 03/27] drm/i915: Drop I915_CONTEXT_PARAM_NO_ZEROMAP
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04  8:48     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  8:48 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:24AM -0500, Jason Ekstrand wrote:
> The idea behind this param is to support OpenCL drivers with relocations
> because OpenCL reserves 0x0 for NULL and, if we placed memory there, it
> would confuse CL kernels.  It was originally sent out as part of a patch
> series including libdrm [1] and Beignet [2] support.  However, the
> libdrm and Beignet patches never landed in their respective upstream
> projects so this API has never been used.  It's never been used in Mesa
> or any other driver, either.
> 
> Dropping this API allows us to delete a small bit of code.
> 
> [1]: https://lists.freedesktop.org/archives/intel-gfx/2015-May/067030.html
> [2]: https://lists.freedesktop.org/archives/intel-gfx/2015-May/067031.html
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Hm I forgot to r-b this last time around.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c      | 16 ++--------------
>  .../gpu/drm/i915/gem/i915_gem_context_types.h    |  1 -
>  drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c   |  8 --------
>  include/uapi/drm/i915_drm.h                      |  4 ++++
>  4 files changed, 6 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 2ba4c7e4011b4..44841db04301b 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1921,15 +1921,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>  	int ret = 0;
>  
>  	switch (args->param) {
> -	case I915_CONTEXT_PARAM_NO_ZEROMAP:
> -		if (args->size)
> -			ret = -EINVAL;
> -		else if (args->value)
> -			set_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
> -		else
> -			clear_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
> -		break;
> -
>  	case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
>  		if (args->size)
>  			ret = -EINVAL;
> @@ -1979,6 +1970,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>  		ret = set_persistence(ctx, args);
>  		break;
>  
> +	case I915_CONTEXT_PARAM_NO_ZEROMAP:
>  	case I915_CONTEXT_PARAM_BAN_PERIOD:
>  	case I915_CONTEXT_PARAM_RINGSIZE:
>  	default:
> @@ -2359,11 +2351,6 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
>  		return -ENOENT;
>  
>  	switch (args->param) {
> -	case I915_CONTEXT_PARAM_NO_ZEROMAP:
> -		args->size = 0;
> -		args->value = test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
> -		break;
> -
>  	case I915_CONTEXT_PARAM_GTT_SIZE:
>  		args->size = 0;
>  		rcu_read_lock();
> @@ -2411,6 +2398,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
>  		args->value = i915_gem_context_is_persistent(ctx);
>  		break;
>  
> +	case I915_CONTEXT_PARAM_NO_ZEROMAP:
>  	case I915_CONTEXT_PARAM_BAN_PERIOD:
>  	case I915_CONTEXT_PARAM_RINGSIZE:
>  	default:
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index 340473aa70de0..5ae71ec936f7c 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -129,7 +129,6 @@ struct i915_gem_context {
>  	 * @user_flags: small set of booleans controlled by the user
>  	 */
>  	unsigned long user_flags;
> -#define UCONTEXT_NO_ZEROMAP		0
>  #define UCONTEXT_NO_ERROR_CAPTURE	1
>  #define UCONTEXT_BANNABLE		2
>  #define UCONTEXT_RECOVERABLE		3
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> index 297143511f99b..b812f313422a9 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> @@ -290,7 +290,6 @@ struct i915_execbuffer {
>  	struct intel_context *reloc_context;
>  
>  	u64 invalid_flags; /** Set of execobj.flags that are invalid */
> -	u32 context_flags; /** Set of execobj.flags to insert from the ctx */
>  
>  	u64 batch_len; /** Length of batch within object */
>  	u32 batch_start_offset; /** Location within object of batch */
> @@ -541,9 +540,6 @@ eb_validate_vma(struct i915_execbuffer *eb,
>  			entry->flags |= EXEC_OBJECT_NEEDS_GTT | __EXEC_OBJECT_NEEDS_MAP;
>  	}
>  
> -	if (!(entry->flags & EXEC_OBJECT_PINNED))
> -		entry->flags |= eb->context_flags;
> -
>  	return 0;
>  }
>  
> @@ -750,10 +746,6 @@ static int eb_select_context(struct i915_execbuffer *eb)
>  	if (rcu_access_pointer(ctx->vm))
>  		eb->invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
>  
> -	eb->context_flags = 0;
> -	if (test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags))
> -		eb->context_flags |= __EXEC_OBJECT_NEEDS_BIAS;
> -
>  	return 0;
>  }
>  
> diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
> index 6eefbc6dec01f..a0aaa8298f28d 100644
> --- a/include/uapi/drm/i915_drm.h
> +++ b/include/uapi/drm/i915_drm.h
> @@ -1637,6 +1637,10 @@ struct drm_i915_gem_context_param {
>  	__u32 size;
>  	__u64 param;
>  #define I915_CONTEXT_PARAM_BAN_PERIOD	0x1
> +/* I915_CONTEXT_PARAM_NO_ZEROMAP has been removed.  On the off chance
> + * someone somewhere has attempted to use it, never re-use this context
> + * param number.
> + */
>  #define I915_CONTEXT_PARAM_NO_ZEROMAP	0x2
>  #define I915_CONTEXT_PARAM_GTT_SIZE	0x3
>  #define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE	0x4
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 03/27] drm/i915: Drop I915_CONTEXT_PARAM_NO_ZEROMAP
@ 2021-05-04  8:48     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  8:48 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:24AM -0500, Jason Ekstrand wrote:
> The idea behind this param is to support OpenCL drivers with relocations
> because OpenCL reserves 0x0 for NULL and, if we placed memory there, it
> would confuse CL kernels.  It was originally sent out as part of a patch
> series including libdrm [1] and Beignet [2] support.  However, the
> libdrm and Beignet patches never landed in their respective upstream
> projects so this API has never been used.  It's never been used in Mesa
> or any other driver, either.
> 
> Dropping this API allows us to delete a small bit of code.
> 
> [1]: https://lists.freedesktop.org/archives/intel-gfx/2015-May/067030.html
> [2]: https://lists.freedesktop.org/archives/intel-gfx/2015-May/067031.html
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Hm I forgot to r-b this last time around.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c      | 16 ++--------------
>  .../gpu/drm/i915/gem/i915_gem_context_types.h    |  1 -
>  drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c   |  8 --------
>  include/uapi/drm/i915_drm.h                      |  4 ++++
>  4 files changed, 6 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 2ba4c7e4011b4..44841db04301b 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1921,15 +1921,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>  	int ret = 0;
>  
>  	switch (args->param) {
> -	case I915_CONTEXT_PARAM_NO_ZEROMAP:
> -		if (args->size)
> -			ret = -EINVAL;
> -		else if (args->value)
> -			set_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
> -		else
> -			clear_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
> -		break;
> -
>  	case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
>  		if (args->size)
>  			ret = -EINVAL;
> @@ -1979,6 +1970,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>  		ret = set_persistence(ctx, args);
>  		break;
>  
> +	case I915_CONTEXT_PARAM_NO_ZEROMAP:
>  	case I915_CONTEXT_PARAM_BAN_PERIOD:
>  	case I915_CONTEXT_PARAM_RINGSIZE:
>  	default:
> @@ -2359,11 +2351,6 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
>  		return -ENOENT;
>  
>  	switch (args->param) {
> -	case I915_CONTEXT_PARAM_NO_ZEROMAP:
> -		args->size = 0;
> -		args->value = test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags);
> -		break;
> -
>  	case I915_CONTEXT_PARAM_GTT_SIZE:
>  		args->size = 0;
>  		rcu_read_lock();
> @@ -2411,6 +2398,7 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
>  		args->value = i915_gem_context_is_persistent(ctx);
>  		break;
>  
> +	case I915_CONTEXT_PARAM_NO_ZEROMAP:
>  	case I915_CONTEXT_PARAM_BAN_PERIOD:
>  	case I915_CONTEXT_PARAM_RINGSIZE:
>  	default:
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index 340473aa70de0..5ae71ec936f7c 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -129,7 +129,6 @@ struct i915_gem_context {
>  	 * @user_flags: small set of booleans controlled by the user
>  	 */
>  	unsigned long user_flags;
> -#define UCONTEXT_NO_ZEROMAP		0
>  #define UCONTEXT_NO_ERROR_CAPTURE	1
>  #define UCONTEXT_BANNABLE		2
>  #define UCONTEXT_RECOVERABLE		3
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> index 297143511f99b..b812f313422a9 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> @@ -290,7 +290,6 @@ struct i915_execbuffer {
>  	struct intel_context *reloc_context;
>  
>  	u64 invalid_flags; /** Set of execobj.flags that are invalid */
> -	u32 context_flags; /** Set of execobj.flags to insert from the ctx */
>  
>  	u64 batch_len; /** Length of batch within object */
>  	u32 batch_start_offset; /** Location within object of batch */
> @@ -541,9 +540,6 @@ eb_validate_vma(struct i915_execbuffer *eb,
>  			entry->flags |= EXEC_OBJECT_NEEDS_GTT | __EXEC_OBJECT_NEEDS_MAP;
>  	}
>  
> -	if (!(entry->flags & EXEC_OBJECT_PINNED))
> -		entry->flags |= eb->context_flags;
> -
>  	return 0;
>  }
>  
> @@ -750,10 +746,6 @@ static int eb_select_context(struct i915_execbuffer *eb)
>  	if (rcu_access_pointer(ctx->vm))
>  		eb->invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
>  
> -	eb->context_flags = 0;
> -	if (test_bit(UCONTEXT_NO_ZEROMAP, &ctx->user_flags))
> -		eb->context_flags |= __EXEC_OBJECT_NEEDS_BIAS;
> -
>  	return 0;
>  }
>  
> diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
> index 6eefbc6dec01f..a0aaa8298f28d 100644
> --- a/include/uapi/drm/i915_drm.h
> +++ b/include/uapi/drm/i915_drm.h
> @@ -1637,6 +1637,10 @@ struct drm_i915_gem_context_param {
>  	__u32 size;
>  	__u64 param;
>  #define I915_CONTEXT_PARAM_BAN_PERIOD	0x1
> +/* I915_CONTEXT_PARAM_NO_ZEROMAP has been removed.  On the off chance
> + * someone somewhere has attempted to use it, never re-use this context
> + * param number.
> + */
>  #define I915_CONTEXT_PARAM_NO_ZEROMAP	0x2
>  #define I915_CONTEXT_PARAM_GTT_SIZE	0x3
>  #define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE	0x4
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 06/27] drm/i915: Drop the CONTEXT_CLONE API
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04  8:50     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  8:50 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:27AM -0500, Jason Ekstrand wrote:
> This API allows one context to grab bits out of another context upon
> creation.  It can be used as a short-cut for setparam(getparam()) for
> things like I915_CONTEXT_PARAM_VM.  However, it's never been used by any
> real userspace.  It's used by a few IGT tests and that's it.  Since it
> doesn't add any real value (most of the stuff you can CLONE you can copy
> in other ways), drop it.
> 
> There is one thing that this API allows you to clone which you cannot
> clone via getparam/setparam: timelines.  However, timelines are an
> implementation detail of i915 and not really something that needs to be
> exposed to userspace.  Also, sharing timelines between contexts isn't
> obviously useful and supporting it has the potential to complicate i915
> internally.  It also doesn't add any functionality that the client can't
> get in other ways.  If a client really wants a shared timeline, they can
> use a syncobj and set it as an in and out fence on every submit.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

This aint gitlab MR, so please include a per-patch (and also per-revision)
changelog summary here. With that added:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 199 +-----------------
>  .../drm/i915/gt/intel_execlists_submission.c  |  28 ---
>  .../drm/i915/gt/intel_execlists_submission.h  |   3 -
>  include/uapi/drm/i915_drm.h                   |  16 +-
>  4 files changed, 6 insertions(+), 240 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index d6f342e605254..308a63f778faf 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1958,207 +1958,14 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
>  	return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
>  }
>  
> -static int clone_engines(struct i915_gem_context *dst,
> -			 struct i915_gem_context *src)
> +static int invalid_ext(struct i915_user_extension __user *ext, void *data)
>  {
> -	struct i915_gem_engines *clone, *e;
> -	bool user_engines;
> -	unsigned long n;
> -
> -	e = __context_engines_await(src, &user_engines);
> -	if (!e)
> -		return -ENOENT;
> -
> -	clone = alloc_engines(e->num_engines);
> -	if (!clone)
> -		goto err_unlock;
> -
> -	for (n = 0; n < e->num_engines; n++) {
> -		struct intel_engine_cs *engine;
> -
> -		if (!e->engines[n]) {
> -			clone->engines[n] = NULL;
> -			continue;
> -		}
> -		engine = e->engines[n]->engine;
> -
> -		/*
> -		 * Virtual engines are singletons; they can only exist
> -		 * inside a single context, because they embed their
> -		 * HW context... As each virtual context implies a single
> -		 * timeline (each engine can only dequeue a single request
> -		 * at any time), it would be surprising for two contexts
> -		 * to use the same engine. So let's create a copy of
> -		 * the virtual engine instead.
> -		 */
> -		if (intel_engine_is_virtual(engine))
> -			clone->engines[n] =
> -				intel_execlists_clone_virtual(engine);
> -		else
> -			clone->engines[n] = intel_context_create(engine);
> -		if (IS_ERR_OR_NULL(clone->engines[n])) {
> -			__free_engines(clone, n);
> -			goto err_unlock;
> -		}
> -
> -		intel_context_set_gem(clone->engines[n], dst);
> -	}
> -	clone->num_engines = n;
> -	i915_sw_fence_complete(&e->fence);
> -
> -	/* Serialised by constructor */
> -	engines_idle_release(dst, rcu_replace_pointer(dst->engines, clone, 1));
> -	if (user_engines)
> -		i915_gem_context_set_user_engines(dst);
> -	else
> -		i915_gem_context_clear_user_engines(dst);
> -	return 0;
> -
> -err_unlock:
> -	i915_sw_fence_complete(&e->fence);
> -	return -ENOMEM;
> -}
> -
> -static int clone_flags(struct i915_gem_context *dst,
> -		       struct i915_gem_context *src)
> -{
> -	dst->user_flags = src->user_flags;
> -	return 0;
> -}
> -
> -static int clone_schedattr(struct i915_gem_context *dst,
> -			   struct i915_gem_context *src)
> -{
> -	dst->sched = src->sched;
> -	return 0;
> -}
> -
> -static int clone_sseu(struct i915_gem_context *dst,
> -		      struct i915_gem_context *src)
> -{
> -	struct i915_gem_engines *e = i915_gem_context_lock_engines(src);
> -	struct i915_gem_engines *clone;
> -	unsigned long n;
> -	int err;
> -
> -	/* no locking required; sole access under constructor*/
> -	clone = __context_engines_static(dst);
> -	if (e->num_engines != clone->num_engines) {
> -		err = -EINVAL;
> -		goto unlock;
> -	}
> -
> -	for (n = 0; n < e->num_engines; n++) {
> -		struct intel_context *ce = e->engines[n];
> -
> -		if (clone->engines[n]->engine->class != ce->engine->class) {
> -			/* Must have compatible engine maps! */
> -			err = -EINVAL;
> -			goto unlock;
> -		}
> -
> -		/* serialises with set_sseu */
> -		err = intel_context_lock_pinned(ce);
> -		if (err)
> -			goto unlock;
> -
> -		clone->engines[n]->sseu = ce->sseu;
> -		intel_context_unlock_pinned(ce);
> -	}
> -
> -	err = 0;
> -unlock:
> -	i915_gem_context_unlock_engines(src);
> -	return err;
> -}
> -
> -static int clone_timeline(struct i915_gem_context *dst,
> -			  struct i915_gem_context *src)
> -{
> -	if (src->timeline)
> -		__assign_timeline(dst, src->timeline);
> -
> -	return 0;
> -}
> -
> -static int clone_vm(struct i915_gem_context *dst,
> -		    struct i915_gem_context *src)
> -{
> -	struct i915_address_space *vm;
> -	int err = 0;
> -
> -	if (!rcu_access_pointer(src->vm))
> -		return 0;
> -
> -	rcu_read_lock();
> -	vm = context_get_vm_rcu(src);
> -	rcu_read_unlock();
> -
> -	if (!mutex_lock_interruptible(&dst->mutex)) {
> -		__assign_ppgtt(dst, vm);
> -		mutex_unlock(&dst->mutex);
> -	} else {
> -		err = -EINTR;
> -	}
> -
> -	i915_vm_put(vm);
> -	return err;
> -}
> -
> -static int create_clone(struct i915_user_extension __user *ext, void *data)
> -{
> -	static int (* const fn[])(struct i915_gem_context *dst,
> -				  struct i915_gem_context *src) = {
> -#define MAP(x, y) [ilog2(I915_CONTEXT_CLONE_##x)] = y
> -		MAP(ENGINES, clone_engines),
> -		MAP(FLAGS, clone_flags),
> -		MAP(SCHEDATTR, clone_schedattr),
> -		MAP(SSEU, clone_sseu),
> -		MAP(TIMELINE, clone_timeline),
> -		MAP(VM, clone_vm),
> -#undef MAP
> -	};
> -	struct drm_i915_gem_context_create_ext_clone local;
> -	const struct create_ext *arg = data;
> -	struct i915_gem_context *dst = arg->ctx;
> -	struct i915_gem_context *src;
> -	int err, bit;
> -
> -	if (copy_from_user(&local, ext, sizeof(local)))
> -		return -EFAULT;
> -
> -	BUILD_BUG_ON(GENMASK(BITS_PER_TYPE(local.flags) - 1, ARRAY_SIZE(fn)) !=
> -		     I915_CONTEXT_CLONE_UNKNOWN);
> -
> -	if (local.flags & I915_CONTEXT_CLONE_UNKNOWN)
> -		return -EINVAL;
> -
> -	if (local.rsvd)
> -		return -EINVAL;
> -
> -	rcu_read_lock();
> -	src = __i915_gem_context_lookup_rcu(arg->fpriv, local.clone_id);
> -	rcu_read_unlock();
> -	if (!src)
> -		return -ENOENT;
> -
> -	GEM_BUG_ON(src == dst);
> -
> -	for (bit = 0; bit < ARRAY_SIZE(fn); bit++) {
> -		if (!(local.flags & BIT(bit)))
> -			continue;
> -
> -		err = fn[bit](dst, src);
> -		if (err)
> -			return err;
> -	}
> -
> -	return 0;
> +	return -EINVAL;
>  }
>  
>  static const i915_user_extension_fn create_extensions[] = {
>  	[I915_CONTEXT_CREATE_EXT_SETPARAM] = create_setparam,
> -	[I915_CONTEXT_CREATE_EXT_CLONE] = create_clone,
> +	[I915_CONTEXT_CREATE_EXT_CLONE] = invalid_ext,
>  };
>  
>  static bool client_is_banned(struct drm_i915_file_private *file_priv)
> diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> index de124870af44d..0e8c320927d15 100644
> --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> @@ -3736,34 +3736,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
>  	return ERR_PTR(err);
>  }
>  
> -struct intel_context *
> -intel_execlists_clone_virtual(struct intel_engine_cs *src)
> -{
> -	struct virtual_engine *se = to_virtual_engine(src);
> -	struct intel_context *dst;
> -
> -	dst = intel_execlists_create_virtual(se->siblings,
> -					     se->num_siblings);
> -	if (IS_ERR(dst))
> -		return dst;
> -
> -	if (se->num_bonds) {
> -		struct virtual_engine *de = to_virtual_engine(dst->engine);
> -
> -		de->bonds = kmemdup(se->bonds,
> -				    sizeof(*se->bonds) * se->num_bonds,
> -				    GFP_KERNEL);
> -		if (!de->bonds) {
> -			intel_context_put(dst);
> -			return ERR_PTR(-ENOMEM);
> -		}
> -
> -		de->num_bonds = se->num_bonds;
> -	}
> -
> -	return dst;
> -}
> -
>  int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
>  				     const struct intel_engine_cs *master,
>  				     const struct intel_engine_cs *sibling)
> diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> index fd61dae820e9e..bab3d37cf3f98 100644
> --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> @@ -36,9 +36,6 @@ struct intel_context *
>  intel_execlists_create_virtual(struct intel_engine_cs **siblings,
>  			       unsigned int count);
>  
> -struct intel_context *
> -intel_execlists_clone_virtual(struct intel_engine_cs *src);
> -
>  int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
>  				     const struct intel_engine_cs *master,
>  				     const struct intel_engine_cs *sibling);
> diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
> index a0aaa8298f28d..75a71b6756ed8 100644
> --- a/include/uapi/drm/i915_drm.h
> +++ b/include/uapi/drm/i915_drm.h
> @@ -1887,20 +1887,10 @@ struct drm_i915_gem_context_create_ext_setparam {
>  	struct drm_i915_gem_context_param param;
>  };
>  
> -struct drm_i915_gem_context_create_ext_clone {
> +/* This API has been removed.  On the off chance someone somewhere has
> + * attempted to use it, never re-use this extension number.
> + */
>  #define I915_CONTEXT_CREATE_EXT_CLONE 1
> -	struct i915_user_extension base;
> -	__u32 clone_id;
> -	__u32 flags;
> -#define I915_CONTEXT_CLONE_ENGINES	(1u << 0)
> -#define I915_CONTEXT_CLONE_FLAGS	(1u << 1)
> -#define I915_CONTEXT_CLONE_SCHEDATTR	(1u << 2)
> -#define I915_CONTEXT_CLONE_SSEU		(1u << 3)
> -#define I915_CONTEXT_CLONE_TIMELINE	(1u << 4)
> -#define I915_CONTEXT_CLONE_VM		(1u << 5)
> -#define I915_CONTEXT_CLONE_UNKNOWN -(I915_CONTEXT_CLONE_VM << 1)
> -	__u64 rsvd;
> -};
>  
>  struct drm_i915_gem_context_destroy {
>  	__u32 ctx_id;
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 06/27] drm/i915: Drop the CONTEXT_CLONE API
@ 2021-05-04  8:50     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  8:50 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:27AM -0500, Jason Ekstrand wrote:
> This API allows one context to grab bits out of another context upon
> creation.  It can be used as a short-cut for setparam(getparam()) for
> things like I915_CONTEXT_PARAM_VM.  However, it's never been used by any
> real userspace.  It's used by a few IGT tests and that's it.  Since it
> doesn't add any real value (most of the stuff you can CLONE you can copy
> in other ways), drop it.
> 
> There is one thing that this API allows you to clone which you cannot
> clone via getparam/setparam: timelines.  However, timelines are an
> implementation detail of i915 and not really something that needs to be
> exposed to userspace.  Also, sharing timelines between contexts isn't
> obviously useful and supporting it has the potential to complicate i915
> internally.  It also doesn't add any functionality that the client can't
> get in other ways.  If a client really wants a shared timeline, they can
> use a syncobj and set it as an in and out fence on every submit.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

This aint gitlab MR, so please include a per-patch (and also per-revision)
changelog summary here. With that added:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 199 +-----------------
>  .../drm/i915/gt/intel_execlists_submission.c  |  28 ---
>  .../drm/i915/gt/intel_execlists_submission.h  |   3 -
>  include/uapi/drm/i915_drm.h                   |  16 +-
>  4 files changed, 6 insertions(+), 240 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index d6f342e605254..308a63f778faf 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1958,207 +1958,14 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
>  	return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
>  }
>  
> -static int clone_engines(struct i915_gem_context *dst,
> -			 struct i915_gem_context *src)
> +static int invalid_ext(struct i915_user_extension __user *ext, void *data)
>  {
> -	struct i915_gem_engines *clone, *e;
> -	bool user_engines;
> -	unsigned long n;
> -
> -	e = __context_engines_await(src, &user_engines);
> -	if (!e)
> -		return -ENOENT;
> -
> -	clone = alloc_engines(e->num_engines);
> -	if (!clone)
> -		goto err_unlock;
> -
> -	for (n = 0; n < e->num_engines; n++) {
> -		struct intel_engine_cs *engine;
> -
> -		if (!e->engines[n]) {
> -			clone->engines[n] = NULL;
> -			continue;
> -		}
> -		engine = e->engines[n]->engine;
> -
> -		/*
> -		 * Virtual engines are singletons; they can only exist
> -		 * inside a single context, because they embed their
> -		 * HW context... As each virtual context implies a single
> -		 * timeline (each engine can only dequeue a single request
> -		 * at any time), it would be surprising for two contexts
> -		 * to use the same engine. So let's create a copy of
> -		 * the virtual engine instead.
> -		 */
> -		if (intel_engine_is_virtual(engine))
> -			clone->engines[n] =
> -				intel_execlists_clone_virtual(engine);
> -		else
> -			clone->engines[n] = intel_context_create(engine);
> -		if (IS_ERR_OR_NULL(clone->engines[n])) {
> -			__free_engines(clone, n);
> -			goto err_unlock;
> -		}
> -
> -		intel_context_set_gem(clone->engines[n], dst);
> -	}
> -	clone->num_engines = n;
> -	i915_sw_fence_complete(&e->fence);
> -
> -	/* Serialised by constructor */
> -	engines_idle_release(dst, rcu_replace_pointer(dst->engines, clone, 1));
> -	if (user_engines)
> -		i915_gem_context_set_user_engines(dst);
> -	else
> -		i915_gem_context_clear_user_engines(dst);
> -	return 0;
> -
> -err_unlock:
> -	i915_sw_fence_complete(&e->fence);
> -	return -ENOMEM;
> -}
> -
> -static int clone_flags(struct i915_gem_context *dst,
> -		       struct i915_gem_context *src)
> -{
> -	dst->user_flags = src->user_flags;
> -	return 0;
> -}
> -
> -static int clone_schedattr(struct i915_gem_context *dst,
> -			   struct i915_gem_context *src)
> -{
> -	dst->sched = src->sched;
> -	return 0;
> -}
> -
> -static int clone_sseu(struct i915_gem_context *dst,
> -		      struct i915_gem_context *src)
> -{
> -	struct i915_gem_engines *e = i915_gem_context_lock_engines(src);
> -	struct i915_gem_engines *clone;
> -	unsigned long n;
> -	int err;
> -
> -	/* no locking required; sole access under constructor*/
> -	clone = __context_engines_static(dst);
> -	if (e->num_engines != clone->num_engines) {
> -		err = -EINVAL;
> -		goto unlock;
> -	}
> -
> -	for (n = 0; n < e->num_engines; n++) {
> -		struct intel_context *ce = e->engines[n];
> -
> -		if (clone->engines[n]->engine->class != ce->engine->class) {
> -			/* Must have compatible engine maps! */
> -			err = -EINVAL;
> -			goto unlock;
> -		}
> -
> -		/* serialises with set_sseu */
> -		err = intel_context_lock_pinned(ce);
> -		if (err)
> -			goto unlock;
> -
> -		clone->engines[n]->sseu = ce->sseu;
> -		intel_context_unlock_pinned(ce);
> -	}
> -
> -	err = 0;
> -unlock:
> -	i915_gem_context_unlock_engines(src);
> -	return err;
> -}
> -
> -static int clone_timeline(struct i915_gem_context *dst,
> -			  struct i915_gem_context *src)
> -{
> -	if (src->timeline)
> -		__assign_timeline(dst, src->timeline);
> -
> -	return 0;
> -}
> -
> -static int clone_vm(struct i915_gem_context *dst,
> -		    struct i915_gem_context *src)
> -{
> -	struct i915_address_space *vm;
> -	int err = 0;
> -
> -	if (!rcu_access_pointer(src->vm))
> -		return 0;
> -
> -	rcu_read_lock();
> -	vm = context_get_vm_rcu(src);
> -	rcu_read_unlock();
> -
> -	if (!mutex_lock_interruptible(&dst->mutex)) {
> -		__assign_ppgtt(dst, vm);
> -		mutex_unlock(&dst->mutex);
> -	} else {
> -		err = -EINTR;
> -	}
> -
> -	i915_vm_put(vm);
> -	return err;
> -}
> -
> -static int create_clone(struct i915_user_extension __user *ext, void *data)
> -{
> -	static int (* const fn[])(struct i915_gem_context *dst,
> -				  struct i915_gem_context *src) = {
> -#define MAP(x, y) [ilog2(I915_CONTEXT_CLONE_##x)] = y
> -		MAP(ENGINES, clone_engines),
> -		MAP(FLAGS, clone_flags),
> -		MAP(SCHEDATTR, clone_schedattr),
> -		MAP(SSEU, clone_sseu),
> -		MAP(TIMELINE, clone_timeline),
> -		MAP(VM, clone_vm),
> -#undef MAP
> -	};
> -	struct drm_i915_gem_context_create_ext_clone local;
> -	const struct create_ext *arg = data;
> -	struct i915_gem_context *dst = arg->ctx;
> -	struct i915_gem_context *src;
> -	int err, bit;
> -
> -	if (copy_from_user(&local, ext, sizeof(local)))
> -		return -EFAULT;
> -
> -	BUILD_BUG_ON(GENMASK(BITS_PER_TYPE(local.flags) - 1, ARRAY_SIZE(fn)) !=
> -		     I915_CONTEXT_CLONE_UNKNOWN);
> -
> -	if (local.flags & I915_CONTEXT_CLONE_UNKNOWN)
> -		return -EINVAL;
> -
> -	if (local.rsvd)
> -		return -EINVAL;
> -
> -	rcu_read_lock();
> -	src = __i915_gem_context_lookup_rcu(arg->fpriv, local.clone_id);
> -	rcu_read_unlock();
> -	if (!src)
> -		return -ENOENT;
> -
> -	GEM_BUG_ON(src == dst);
> -
> -	for (bit = 0; bit < ARRAY_SIZE(fn); bit++) {
> -		if (!(local.flags & BIT(bit)))
> -			continue;
> -
> -		err = fn[bit](dst, src);
> -		if (err)
> -			return err;
> -	}
> -
> -	return 0;
> +	return -EINVAL;
>  }
>  
>  static const i915_user_extension_fn create_extensions[] = {
>  	[I915_CONTEXT_CREATE_EXT_SETPARAM] = create_setparam,
> -	[I915_CONTEXT_CREATE_EXT_CLONE] = create_clone,
> +	[I915_CONTEXT_CREATE_EXT_CLONE] = invalid_ext,
>  };
>  
>  static bool client_is_banned(struct drm_i915_file_private *file_priv)
> diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> index de124870af44d..0e8c320927d15 100644
> --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> @@ -3736,34 +3736,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
>  	return ERR_PTR(err);
>  }
>  
> -struct intel_context *
> -intel_execlists_clone_virtual(struct intel_engine_cs *src)
> -{
> -	struct virtual_engine *se = to_virtual_engine(src);
> -	struct intel_context *dst;
> -
> -	dst = intel_execlists_create_virtual(se->siblings,
> -					     se->num_siblings);
> -	if (IS_ERR(dst))
> -		return dst;
> -
> -	if (se->num_bonds) {
> -		struct virtual_engine *de = to_virtual_engine(dst->engine);
> -
> -		de->bonds = kmemdup(se->bonds,
> -				    sizeof(*se->bonds) * se->num_bonds,
> -				    GFP_KERNEL);
> -		if (!de->bonds) {
> -			intel_context_put(dst);
> -			return ERR_PTR(-ENOMEM);
> -		}
> -
> -		de->num_bonds = se->num_bonds;
> -	}
> -
> -	return dst;
> -}
> -
>  int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
>  				     const struct intel_engine_cs *master,
>  				     const struct intel_engine_cs *sibling)
> diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> index fd61dae820e9e..bab3d37cf3f98 100644
> --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> @@ -36,9 +36,6 @@ struct intel_context *
>  intel_execlists_create_virtual(struct intel_engine_cs **siblings,
>  			       unsigned int count);
>  
> -struct intel_context *
> -intel_execlists_clone_virtual(struct intel_engine_cs *src);
> -
>  int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
>  				     const struct intel_engine_cs *master,
>  				     const struct intel_engine_cs *sibling);
> diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
> index a0aaa8298f28d..75a71b6756ed8 100644
> --- a/include/uapi/drm/i915_drm.h
> +++ b/include/uapi/drm/i915_drm.h
> @@ -1887,20 +1887,10 @@ struct drm_i915_gem_context_create_ext_setparam {
>  	struct drm_i915_gem_context_param param;
>  };
>  
> -struct drm_i915_gem_context_create_ext_clone {
> +/* This API has been removed.  On the off chance someone somewhere has
> + * attempted to use it, never re-use this extension number.
> + */
>  #define I915_CONTEXT_CREATE_EXT_CLONE 1
> -	struct i915_user_extension base;
> -	__u32 clone_id;
> -	__u32 flags;
> -#define I915_CONTEXT_CLONE_ENGINES	(1u << 0)
> -#define I915_CONTEXT_CLONE_FLAGS	(1u << 1)
> -#define I915_CONTEXT_CLONE_SCHEDATTR	(1u << 2)
> -#define I915_CONTEXT_CLONE_SSEU		(1u << 3)
> -#define I915_CONTEXT_CLONE_TIMELINE	(1u << 4)
> -#define I915_CONTEXT_CLONE_VM		(1u << 5)
> -#define I915_CONTEXT_CLONE_UNKNOWN -(I915_CONTEXT_CLONE_VM << 1)
> -	__u64 rsvd;
> -};
>  
>  struct drm_i915_gem_context_destroy {
>  	__u32 ctx_id;
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 11/27] drm/i915/request: Remove the hook from await_execution
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04  8:55     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  8:55 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:32AM -0500, Jason Ekstrand wrote:
> This was only ever used for FENCE_SUBMIT automatic engine selection
> which was removed in the previous commit.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

I really how this is now split up and much more decipherable what's going
on. For the three patches leading to here including this one:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |  3 +-
>  drivers/gpu/drm/i915/i915_request.c           | 42 ++++---------------
>  drivers/gpu/drm/i915/i915_request.h           |  4 +-
>  3 files changed, 9 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> index efb2fa3522a42..7024adcd5cf15 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> @@ -3473,8 +3473,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
>  	if (in_fence) {
>  		if (args->flags & I915_EXEC_FENCE_SUBMIT)
>  			err = i915_request_await_execution(eb.request,
> -							   in_fence,
> -							   NULL);
> +							   in_fence);
>  		else
>  			err = i915_request_await_dma_fence(eb.request,
>  							   in_fence);
> diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> index bec9c3652188b..7e00218b8c105 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -49,7 +49,6 @@
>  struct execute_cb {
>  	struct irq_work work;
>  	struct i915_sw_fence *fence;
> -	void (*hook)(struct i915_request *rq, struct dma_fence *signal);
>  	struct i915_request *signal;
>  };
>  
> @@ -180,17 +179,6 @@ static void irq_execute_cb(struct irq_work *wrk)
>  	kmem_cache_free(global.slab_execute_cbs, cb);
>  }
>  
> -static void irq_execute_cb_hook(struct irq_work *wrk)
> -{
> -	struct execute_cb *cb = container_of(wrk, typeof(*cb), work);
> -
> -	cb->hook(container_of(cb->fence, struct i915_request, submit),
> -		 &cb->signal->fence);
> -	i915_request_put(cb->signal);
> -
> -	irq_execute_cb(wrk);
> -}
> -
>  static __always_inline void
>  __notify_execute_cb(struct i915_request *rq, bool (*fn)(struct irq_work *wrk))
>  {
> @@ -517,17 +505,12 @@ static bool __request_in_flight(const struct i915_request *signal)
>  static int
>  __await_execution(struct i915_request *rq,
>  		  struct i915_request *signal,
> -		  void (*hook)(struct i915_request *rq,
> -			       struct dma_fence *signal),
>  		  gfp_t gfp)
>  {
>  	struct execute_cb *cb;
>  
> -	if (i915_request_is_active(signal)) {
> -		if (hook)
> -			hook(rq, &signal->fence);
> +	if (i915_request_is_active(signal))
>  		return 0;
> -	}
>  
>  	cb = kmem_cache_alloc(global.slab_execute_cbs, gfp);
>  	if (!cb)
> @@ -537,12 +520,6 @@ __await_execution(struct i915_request *rq,
>  	i915_sw_fence_await(cb->fence);
>  	init_irq_work(&cb->work, irq_execute_cb);
>  
> -	if (hook) {
> -		cb->hook = hook;
> -		cb->signal = i915_request_get(signal);
> -		cb->work.func = irq_execute_cb_hook;
> -	}
> -
>  	/*
>  	 * Register the callback first, then see if the signaler is already
>  	 * active. This ensures that if we race with the
> @@ -1253,7 +1230,7 @@ emit_semaphore_wait(struct i915_request *to,
>  		goto await_fence;
>  
>  	/* Only submit our spinner after the signaler is running! */
> -	if (__await_execution(to, from, NULL, gfp))
> +	if (__await_execution(to, from, gfp))
>  		goto await_fence;
>  
>  	if (__emit_semaphore_wait(to, from, from->fence.seqno))
> @@ -1284,16 +1261,14 @@ static int intel_timeline_sync_set_start(struct intel_timeline *tl,
>  
>  static int
>  __i915_request_await_execution(struct i915_request *to,
> -			       struct i915_request *from,
> -			       void (*hook)(struct i915_request *rq,
> -					    struct dma_fence *signal))
> +			       struct i915_request *from)
>  {
>  	int err;
>  
>  	GEM_BUG_ON(intel_context_is_barrier(from->context));
>  
>  	/* Submit both requests at the same time */
> -	err = __await_execution(to, from, hook, I915_FENCE_GFP);
> +	err = __await_execution(to, from, I915_FENCE_GFP);
>  	if (err)
>  		return err;
>  
> @@ -1406,9 +1381,7 @@ i915_request_await_external(struct i915_request *rq, struct dma_fence *fence)
>  
>  int
>  i915_request_await_execution(struct i915_request *rq,
> -			     struct dma_fence *fence,
> -			     void (*hook)(struct i915_request *rq,
> -					  struct dma_fence *signal))
> +			     struct dma_fence *fence)
>  {
>  	struct dma_fence **child = &fence;
>  	unsigned int nchild = 1;
> @@ -1441,8 +1414,7 @@ i915_request_await_execution(struct i915_request *rq,
>  
>  		if (dma_fence_is_i915(fence))
>  			ret = __i915_request_await_execution(rq,
> -							     to_request(fence),
> -							     hook);
> +							     to_request(fence));
>  		else
>  			ret = i915_request_await_external(rq, fence);
>  		if (ret < 0)
> @@ -1468,7 +1440,7 @@ await_request_submit(struct i915_request *to, struct i915_request *from)
>  							&from->submit,
>  							I915_FENCE_GFP);
>  	else
> -		return __i915_request_await_execution(to, from, NULL);
> +		return __i915_request_await_execution(to, from);
>  }
>  
>  static int
> diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h
> index 270f6cd37650c..63b087a7f5707 100644
> --- a/drivers/gpu/drm/i915/i915_request.h
> +++ b/drivers/gpu/drm/i915/i915_request.h
> @@ -352,9 +352,7 @@ int i915_request_await_object(struct i915_request *to,
>  int i915_request_await_dma_fence(struct i915_request *rq,
>  				 struct dma_fence *fence);
>  int i915_request_await_execution(struct i915_request *rq,
> -				 struct dma_fence *fence,
> -				 void (*hook)(struct i915_request *rq,
> -					      struct dma_fence *signal));
> +				 struct dma_fence *fence);
>  
>  void i915_request_add(struct i915_request *rq);
>  
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 11/27] drm/i915/request: Remove the hook from await_execution
@ 2021-05-04  8:55     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  8:55 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:32AM -0500, Jason Ekstrand wrote:
> This was only ever used for FENCE_SUBMIT automatic engine selection
> which was removed in the previous commit.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

I really how this is now split up and much more decipherable what's going
on. For the three patches leading to here including this one:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |  3 +-
>  drivers/gpu/drm/i915/i915_request.c           | 42 ++++---------------
>  drivers/gpu/drm/i915/i915_request.h           |  4 +-
>  3 files changed, 9 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> index efb2fa3522a42..7024adcd5cf15 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> @@ -3473,8 +3473,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
>  	if (in_fence) {
>  		if (args->flags & I915_EXEC_FENCE_SUBMIT)
>  			err = i915_request_await_execution(eb.request,
> -							   in_fence,
> -							   NULL);
> +							   in_fence);
>  		else
>  			err = i915_request_await_dma_fence(eb.request,
>  							   in_fence);
> diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> index bec9c3652188b..7e00218b8c105 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -49,7 +49,6 @@
>  struct execute_cb {
>  	struct irq_work work;
>  	struct i915_sw_fence *fence;
> -	void (*hook)(struct i915_request *rq, struct dma_fence *signal);
>  	struct i915_request *signal;
>  };
>  
> @@ -180,17 +179,6 @@ static void irq_execute_cb(struct irq_work *wrk)
>  	kmem_cache_free(global.slab_execute_cbs, cb);
>  }
>  
> -static void irq_execute_cb_hook(struct irq_work *wrk)
> -{
> -	struct execute_cb *cb = container_of(wrk, typeof(*cb), work);
> -
> -	cb->hook(container_of(cb->fence, struct i915_request, submit),
> -		 &cb->signal->fence);
> -	i915_request_put(cb->signal);
> -
> -	irq_execute_cb(wrk);
> -}
> -
>  static __always_inline void
>  __notify_execute_cb(struct i915_request *rq, bool (*fn)(struct irq_work *wrk))
>  {
> @@ -517,17 +505,12 @@ static bool __request_in_flight(const struct i915_request *signal)
>  static int
>  __await_execution(struct i915_request *rq,
>  		  struct i915_request *signal,
> -		  void (*hook)(struct i915_request *rq,
> -			       struct dma_fence *signal),
>  		  gfp_t gfp)
>  {
>  	struct execute_cb *cb;
>  
> -	if (i915_request_is_active(signal)) {
> -		if (hook)
> -			hook(rq, &signal->fence);
> +	if (i915_request_is_active(signal))
>  		return 0;
> -	}
>  
>  	cb = kmem_cache_alloc(global.slab_execute_cbs, gfp);
>  	if (!cb)
> @@ -537,12 +520,6 @@ __await_execution(struct i915_request *rq,
>  	i915_sw_fence_await(cb->fence);
>  	init_irq_work(&cb->work, irq_execute_cb);
>  
> -	if (hook) {
> -		cb->hook = hook;
> -		cb->signal = i915_request_get(signal);
> -		cb->work.func = irq_execute_cb_hook;
> -	}
> -
>  	/*
>  	 * Register the callback first, then see if the signaler is already
>  	 * active. This ensures that if we race with the
> @@ -1253,7 +1230,7 @@ emit_semaphore_wait(struct i915_request *to,
>  		goto await_fence;
>  
>  	/* Only submit our spinner after the signaler is running! */
> -	if (__await_execution(to, from, NULL, gfp))
> +	if (__await_execution(to, from, gfp))
>  		goto await_fence;
>  
>  	if (__emit_semaphore_wait(to, from, from->fence.seqno))
> @@ -1284,16 +1261,14 @@ static int intel_timeline_sync_set_start(struct intel_timeline *tl,
>  
>  static int
>  __i915_request_await_execution(struct i915_request *to,
> -			       struct i915_request *from,
> -			       void (*hook)(struct i915_request *rq,
> -					    struct dma_fence *signal))
> +			       struct i915_request *from)
>  {
>  	int err;
>  
>  	GEM_BUG_ON(intel_context_is_barrier(from->context));
>  
>  	/* Submit both requests at the same time */
> -	err = __await_execution(to, from, hook, I915_FENCE_GFP);
> +	err = __await_execution(to, from, I915_FENCE_GFP);
>  	if (err)
>  		return err;
>  
> @@ -1406,9 +1381,7 @@ i915_request_await_external(struct i915_request *rq, struct dma_fence *fence)
>  
>  int
>  i915_request_await_execution(struct i915_request *rq,
> -			     struct dma_fence *fence,
> -			     void (*hook)(struct i915_request *rq,
> -					  struct dma_fence *signal))
> +			     struct dma_fence *fence)
>  {
>  	struct dma_fence **child = &fence;
>  	unsigned int nchild = 1;
> @@ -1441,8 +1414,7 @@ i915_request_await_execution(struct i915_request *rq,
>  
>  		if (dma_fence_is_i915(fence))
>  			ret = __i915_request_await_execution(rq,
> -							     to_request(fence),
> -							     hook);
> +							     to_request(fence));
>  		else
>  			ret = i915_request_await_external(rq, fence);
>  		if (ret < 0)
> @@ -1468,7 +1440,7 @@ await_request_submit(struct i915_request *to, struct i915_request *from)
>  							&from->submit,
>  							I915_FENCE_GFP);
>  	else
> -		return __i915_request_await_execution(to, from, NULL);
> +		return __i915_request_await_execution(to, from);
>  }
>  
>  static int
> diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h
> index 270f6cd37650c..63b087a7f5707 100644
> --- a/drivers/gpu/drm/i915/i915_request.h
> +++ b/drivers/gpu/drm/i915/i915_request.h
> @@ -352,9 +352,7 @@ int i915_request_await_object(struct i915_request *to,
>  int i915_request_await_dma_fence(struct i915_request *rq,
>  				 struct dma_fence *fence);
>  int i915_request_await_execution(struct i915_request *rq,
> -				 struct dma_fence *fence,
> -				 void (*hook)(struct i915_request *rq,
> -					      struct dma_fence *signal));
> +				 struct dma_fence *fence);
>  
>  void i915_request_add(struct i915_request *rq);
>  
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 10/27] drm/i915/gem: Remove engine auto-magic with FENCE_SUBMIT
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04  8:56     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  8:56 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:31AM -0500, Jason Ekstrand wrote:
> Even though FENCE_SUBMIT is only documented to wait until the request in
> the in-fence starts instead of waiting until it completes, it has a bit
> more magic than that.  If FENCE_SUBMIT is used to submit something to a
> balanced engine, we would wait to assign engines until the primary
> request was ready to start and then attempt to assign it to a different
> engine than the primary.  There is an IGT test which exercises this by
> submitting a primary batch to a specific VCS and then using FENCE_SUBMIT
> to submit a secondary which can run on any VCS and have i915 figure out
> which VCS to run it on such that they can run in parallel.
> 
> However, this functionality has never been used in the real world.  The
> media driver (the only user of FENCE_SUBMIT) always picks exactly two
> physical engines to bond and never asks us to pick which to use.

Maybe reference the specific igt you're break (and removing in the igt
series to match this) here. Just for the record and all that.
-Daniel

> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c  |  2 +-
>  drivers/gpu/drm/i915/gt/intel_engine_types.h    |  7 -------
>  .../drm/i915/gt/intel_execlists_submission.c    | 17 -----------------
>  3 files changed, 1 insertion(+), 25 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> index d640bba6ad9ab..efb2fa3522a42 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> @@ -3474,7 +3474,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
>  		if (args->flags & I915_EXEC_FENCE_SUBMIT)
>  			err = i915_request_await_execution(eb.request,
>  							   in_fence,
> -							   eb.engine->bond_execute);
> +							   NULL);
>  		else
>  			err = i915_request_await_dma_fence(eb.request,
>  							   in_fence);
> diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
> index 883bafc449024..68cfe5080325c 100644
> --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
> +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
> @@ -446,13 +446,6 @@ struct intel_engine_cs {
>  	 */
>  	void		(*submit_request)(struct i915_request *rq);
>  
> -	/*
> -	 * Called on signaling of a SUBMIT_FENCE, passing along the signaling
> -	 * request down to the bonded pairs.
> -	 */
> -	void            (*bond_execute)(struct i915_request *rq,
> -					struct dma_fence *signal);
> -
>  	/*
>  	 * Call when the priority on a request has changed and it and its
>  	 * dependencies may need rescheduling. Note the request itself may
> diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> index 14378b28169b7..635d6d2494d26 100644
> --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> @@ -3547,22 +3547,6 @@ static void virtual_submit_request(struct i915_request *rq)
>  	spin_unlock_irqrestore(&ve->base.active.lock, flags);
>  }
>  
> -static void
> -virtual_bond_execute(struct i915_request *rq, struct dma_fence *signal)
> -{
> -	intel_engine_mask_t allowed, exec;
> -
> -	allowed = ~to_request(signal)->engine->mask;
> -
> -	/* Restrict the bonded request to run on only the available engines */
> -	exec = READ_ONCE(rq->execution_mask);
> -	while (!try_cmpxchg(&rq->execution_mask, &exec, exec & allowed))
> -		;
> -
> -	/* Prevent the master from being re-run on the bonded engines */
> -	to_request(signal)->execution_mask &= ~allowed;
> -}
> -
>  struct intel_context *
>  intel_execlists_create_virtual(struct intel_engine_cs **siblings,
>  			       unsigned int count)
> @@ -3616,7 +3600,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
>  
>  	ve->base.schedule = i915_schedule;
>  	ve->base.submit_request = virtual_submit_request;
> -	ve->base.bond_execute = virtual_bond_execute;
>  
>  	INIT_LIST_HEAD(virtual_queue(ve));
>  	ve->base.execlists.queue_priority_hint = INT_MIN;
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 10/27] drm/i915/gem: Remove engine auto-magic with FENCE_SUBMIT
@ 2021-05-04  8:56     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  8:56 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:31AM -0500, Jason Ekstrand wrote:
> Even though FENCE_SUBMIT is only documented to wait until the request in
> the in-fence starts instead of waiting until it completes, it has a bit
> more magic than that.  If FENCE_SUBMIT is used to submit something to a
> balanced engine, we would wait to assign engines until the primary
> request was ready to start and then attempt to assign it to a different
> engine than the primary.  There is an IGT test which exercises this by
> submitting a primary batch to a specific VCS and then using FENCE_SUBMIT
> to submit a secondary which can run on any VCS and have i915 figure out
> which VCS to run it on such that they can run in parallel.
> 
> However, this functionality has never been used in the real world.  The
> media driver (the only user of FENCE_SUBMIT) always picks exactly two
> physical engines to bond and never asks us to pick which to use.

Maybe reference the specific igt you're break (and removing in the igt
series to match this) here. Just for the record and all that.
-Daniel

> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c  |  2 +-
>  drivers/gpu/drm/i915/gt/intel_engine_types.h    |  7 -------
>  .../drm/i915/gt/intel_execlists_submission.c    | 17 -----------------
>  3 files changed, 1 insertion(+), 25 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> index d640bba6ad9ab..efb2fa3522a42 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> @@ -3474,7 +3474,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
>  		if (args->flags & I915_EXEC_FENCE_SUBMIT)
>  			err = i915_request_await_execution(eb.request,
>  							   in_fence,
> -							   eb.engine->bond_execute);
> +							   NULL);
>  		else
>  			err = i915_request_await_dma_fence(eb.request,
>  							   in_fence);
> diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
> index 883bafc449024..68cfe5080325c 100644
> --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
> +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
> @@ -446,13 +446,6 @@ struct intel_engine_cs {
>  	 */
>  	void		(*submit_request)(struct i915_request *rq);
>  
> -	/*
> -	 * Called on signaling of a SUBMIT_FENCE, passing along the signaling
> -	 * request down to the bonded pairs.
> -	 */
> -	void            (*bond_execute)(struct i915_request *rq,
> -					struct dma_fence *signal);
> -
>  	/*
>  	 * Call when the priority on a request has changed and it and its
>  	 * dependencies may need rescheduling. Note the request itself may
> diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> index 14378b28169b7..635d6d2494d26 100644
> --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> @@ -3547,22 +3547,6 @@ static void virtual_submit_request(struct i915_request *rq)
>  	spin_unlock_irqrestore(&ve->base.active.lock, flags);
>  }
>  
> -static void
> -virtual_bond_execute(struct i915_request *rq, struct dma_fence *signal)
> -{
> -	intel_engine_mask_t allowed, exec;
> -
> -	allowed = ~to_request(signal)->engine->mask;
> -
> -	/* Restrict the bonded request to run on only the available engines */
> -	exec = READ_ONCE(rq->execution_mask);
> -	while (!try_cmpxchg(&rq->execution_mask, &exec, exec & allowed))
> -		;
> -
> -	/* Prevent the master from being re-run on the bonded engines */
> -	to_request(signal)->execution_mask &= ~allowed;
> -}
> -
>  struct intel_context *
>  intel_execlists_create_virtual(struct intel_engine_cs **siblings,
>  			       unsigned int count)
> @@ -3616,7 +3600,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
>  
>  	ve->base.schedule = i915_schedule;
>  	ve->base.submit_request = virtual_submit_request;
> -	ve->base.bond_execute = virtual_bond_execute;
>  
>  	INIT_LIST_HEAD(virtual_queue(ve));
>  	ve->base.execlists.queue_priority_hint = INT_MIN;
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 15/27] drm/i915: Add gem/i915_gem_context.h to the docs
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04  9:11     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  9:11 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:36AM -0500, Jason Ekstrand wrote:
> In order to prevent kernel doc warnings, also fill out docs for any
> missing fields and fix those that forgot the "@".
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  Documentation/gpu/i915.rst                    |  2 +
>  .../gpu/drm/i915/gem/i915_gem_context_types.h | 43 ++++++++++++++++---
>  2 files changed, 38 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst
> index 486c720f38907..0529e5183982e 100644
> --- a/Documentation/gpu/i915.rst
> +++ b/Documentation/gpu/i915.rst
> @@ -422,6 +422,8 @@ Batchbuffer Parsing
>  User Batchbuffer Execution
>  --------------------------
>  
> +.. kernel-doc:: drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +
>  .. kernel-doc:: drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>     :doc: User command execution
>  
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index df76767f0c41b..5f0673a2129f9 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -30,19 +30,39 @@ struct i915_address_space;
>  struct intel_timeline;
>  struct intel_ring;
>  
> +/**
> + * struct i915_gem_engines - A set of engines
> + */
>  struct i915_gem_engines {
>  	union {
> +		/** @link: Link in i915_gem_context::stale::engines */
>  		struct list_head link;
> +
> +		/** @rcu: RCU to use when freeing */
>  		struct rcu_head rcu;
>  	};
> +
> +	/** @fence: Fence used for delayed destruction of engines */
>  	struct i915_sw_fence fence;

I got derailed a bit appreciating the lifetime complexity here as
expressed in the callbacks for this. I hope this all simplifies?

Anyway patch looks good, or at least better than what we had.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> +
> +	/** @ctx: i915_gem_context backpointer */
>  	struct i915_gem_context *ctx;
> +
> +	/** @num_engines: Number of engines in this set */
>  	unsigned int num_engines;
> +
> +	/** @engines: Array of engines */
>  	struct intel_context *engines[];
>  };
>  
> +/**
> + * struct i915_gem_engines_iter - Iterator for an i915_gem_engines set
> + */
>  struct i915_gem_engines_iter {
> +	/** @idx: Index into i915_gem_engines::engines */
>  	unsigned int idx;
> +
> +	/** @engines: Engine set being iterated */
>  	const struct i915_gem_engines *engines;
>  };
>  
> @@ -53,10 +73,10 @@ struct i915_gem_engines_iter {
>   * logical hardware state for a particular client.
>   */
>  struct i915_gem_context {
> -	/** i915: i915 device backpointer */
> +	/** @i915: i915 device backpointer */
>  	struct drm_i915_private *i915;
>  
> -	/** file_priv: owning file descriptor */
> +	/** @file_priv: owning file descriptor */
>  	struct drm_i915_file_private *file_priv;
>  
>  	/**
> @@ -81,7 +101,9 @@ struct i915_gem_context {
>  	 * CONTEXT_USER_ENGINES flag is set).
>  	 */
>  	struct i915_gem_engines __rcu *engines;
> -	struct mutex engines_mutex; /* guards writes to engines */
> +
> +	/** @engines_mutex: guards writes to engines */
> +	struct mutex engines_mutex;
>  
>  	/**
>  	 * @syncobj: Shared timeline syncobj
> @@ -118,7 +140,7 @@ struct i915_gem_context {
>  	 */
>  	struct pid *pid;
>  
> -	/** link: place with &drm_i915_private.context_list */
> +	/** @link: place with &drm_i915_private.context_list */
>  	struct list_head link;
>  
>  	/**
> @@ -153,11 +175,13 @@ struct i915_gem_context {
>  #define CONTEXT_CLOSED			0
>  #define CONTEXT_USER_ENGINES		1
>  
> +	/** @mutex: guards everything that isn't engines or handles_vma */
>  	struct mutex mutex;
>  
> +	/** @sched: scheduler parameters */
>  	struct i915_sched_attr sched;
>  
> -	/** guilty_count: How many times this context has caused a GPU hang. */
> +	/** @guilty_count: How many times this context has caused a GPU hang. */
>  	atomic_t guilty_count;
>  	/**
>  	 * @active_count: How many times this context was active during a GPU
> @@ -171,15 +195,17 @@ struct i915_gem_context {
>  	unsigned long hang_timestamp[2];
>  #define CONTEXT_FAST_HANG_JIFFIES (120 * HZ) /* 3 hangs within 120s? Banned! */
>  
> -	/** remap_slice: Bitmask of cache lines that need remapping */
> +	/** @remap_slice: Bitmask of cache lines that need remapping */
>  	u8 remap_slice;
>  
>  	/**
> -	 * handles_vma: rbtree to look up our context specific obj/vma for
> +	 * @handles_vma: rbtree to look up our context specific obj/vma for
>  	 * the user handle. (user handles are per fd, but the binding is
>  	 * per vm, which may be one per context or shared with the global GTT)
>  	 */
>  	struct radix_tree_root handles_vma;
> +
> +	/** @lut_mutex: Locks handles_vma */
>  	struct mutex lut_mutex;
>  
>  	/**
> @@ -191,8 +217,11 @@ struct i915_gem_context {
>  	 */
>  	char name[TASK_COMM_LEN + 8];
>  
> +	/** @stale: tracks stale engines to be destroyed */
>  	struct {
> +		/** @lock: guards engines */
>  		spinlock_t lock;
> +		/** @engines: list of stale engines */
>  		struct list_head engines;
>  	} stale;
>  };
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 15/27] drm/i915: Add gem/i915_gem_context.h to the docs
@ 2021-05-04  9:11     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04  9:11 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:36AM -0500, Jason Ekstrand wrote:
> In order to prevent kernel doc warnings, also fill out docs for any
> missing fields and fix those that forgot the "@".
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  Documentation/gpu/i915.rst                    |  2 +
>  .../gpu/drm/i915/gem/i915_gem_context_types.h | 43 ++++++++++++++++---
>  2 files changed, 38 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst
> index 486c720f38907..0529e5183982e 100644
> --- a/Documentation/gpu/i915.rst
> +++ b/Documentation/gpu/i915.rst
> @@ -422,6 +422,8 @@ Batchbuffer Parsing
>  User Batchbuffer Execution
>  --------------------------
>  
> +.. kernel-doc:: drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +
>  .. kernel-doc:: drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
>     :doc: User command execution
>  
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index df76767f0c41b..5f0673a2129f9 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -30,19 +30,39 @@ struct i915_address_space;
>  struct intel_timeline;
>  struct intel_ring;
>  
> +/**
> + * struct i915_gem_engines - A set of engines
> + */
>  struct i915_gem_engines {
>  	union {
> +		/** @link: Link in i915_gem_context::stale::engines */
>  		struct list_head link;
> +
> +		/** @rcu: RCU to use when freeing */
>  		struct rcu_head rcu;
>  	};
> +
> +	/** @fence: Fence used for delayed destruction of engines */
>  	struct i915_sw_fence fence;

I got derailed a bit appreciating the lifetime complexity here as
expressed in the callbacks for this. I hope this all simplifies?

Anyway patch looks good, or at least better than what we had.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> +
> +	/** @ctx: i915_gem_context backpointer */
>  	struct i915_gem_context *ctx;
> +
> +	/** @num_engines: Number of engines in this set */
>  	unsigned int num_engines;
> +
> +	/** @engines: Array of engines */
>  	struct intel_context *engines[];
>  };
>  
> +/**
> + * struct i915_gem_engines_iter - Iterator for an i915_gem_engines set
> + */
>  struct i915_gem_engines_iter {
> +	/** @idx: Index into i915_gem_engines::engines */
>  	unsigned int idx;
> +
> +	/** @engines: Engine set being iterated */
>  	const struct i915_gem_engines *engines;
>  };
>  
> @@ -53,10 +73,10 @@ struct i915_gem_engines_iter {
>   * logical hardware state for a particular client.
>   */
>  struct i915_gem_context {
> -	/** i915: i915 device backpointer */
> +	/** @i915: i915 device backpointer */
>  	struct drm_i915_private *i915;
>  
> -	/** file_priv: owning file descriptor */
> +	/** @file_priv: owning file descriptor */
>  	struct drm_i915_file_private *file_priv;
>  
>  	/**
> @@ -81,7 +101,9 @@ struct i915_gem_context {
>  	 * CONTEXT_USER_ENGINES flag is set).
>  	 */
>  	struct i915_gem_engines __rcu *engines;
> -	struct mutex engines_mutex; /* guards writes to engines */
> +
> +	/** @engines_mutex: guards writes to engines */
> +	struct mutex engines_mutex;
>  
>  	/**
>  	 * @syncobj: Shared timeline syncobj
> @@ -118,7 +140,7 @@ struct i915_gem_context {
>  	 */
>  	struct pid *pid;
>  
> -	/** link: place with &drm_i915_private.context_list */
> +	/** @link: place with &drm_i915_private.context_list */
>  	struct list_head link;
>  
>  	/**
> @@ -153,11 +175,13 @@ struct i915_gem_context {
>  #define CONTEXT_CLOSED			0
>  #define CONTEXT_USER_ENGINES		1
>  
> +	/** @mutex: guards everything that isn't engines or handles_vma */
>  	struct mutex mutex;
>  
> +	/** @sched: scheduler parameters */
>  	struct i915_sched_attr sched;
>  
> -	/** guilty_count: How many times this context has caused a GPU hang. */
> +	/** @guilty_count: How many times this context has caused a GPU hang. */
>  	atomic_t guilty_count;
>  	/**
>  	 * @active_count: How many times this context was active during a GPU
> @@ -171,15 +195,17 @@ struct i915_gem_context {
>  	unsigned long hang_timestamp[2];
>  #define CONTEXT_FAST_HANG_JIFFIES (120 * HZ) /* 3 hangs within 120s? Banned! */
>  
> -	/** remap_slice: Bitmask of cache lines that need remapping */
> +	/** @remap_slice: Bitmask of cache lines that need remapping */
>  	u8 remap_slice;
>  
>  	/**
> -	 * handles_vma: rbtree to look up our context specific obj/vma for
> +	 * @handles_vma: rbtree to look up our context specific obj/vma for
>  	 * the user handle. (user handles are per fd, but the binding is
>  	 * per vm, which may be one per context or shared with the global GTT)
>  	 */
>  	struct radix_tree_root handles_vma;
> +
> +	/** @lut_mutex: Locks handles_vma */
>  	struct mutex lut_mutex;
>  
>  	/**
> @@ -191,8 +217,11 @@ struct i915_gem_context {
>  	 */
>  	char name[TASK_COMM_LEN + 8];
>  
> +	/** @stale: tracks stale engines to be destroyed */
>  	struct {
> +		/** @lock: guards engines */
>  		spinlock_t lock;
> +		/** @engines: list of stale engines */
>  		struct list_head engines;
>  	} stale;
>  };
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04 16:13     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 16:13 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:37AM -0500, Jason Ekstrand wrote:
> The current context uAPI allows for two methods of setting context
> parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
> former is allowed to be called at any time while the later happens as
> part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
> settable via the other.  While some params are fairly simple and setting
> them on a live context is harmless such the context priority, others are
> far trickier such as the VM or the set of engines.  In order to swap out
> the VM, for instance, we have to delay until all current in-flight work
> is complete, swap in the new VM, and then continue.  This leads to a
> plethora of potential race conditions we'd really rather avoid.
> 
> Unfortunately, both methods of setting the VM and engine set are in
> active use today so we can't simply disallow setting the VM or engine
> set vial SET_CONTEXT_PARAM.  In order to work around this wart, this
> commit adds a proto-context struct which contains all the context create
> parameters.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Per-patch changelog pls.

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 145 ++++++++++++++----
>  .../gpu/drm/i915/gem/i915_gem_context_types.h |  22 +++
>  .../gpu/drm/i915/gem/selftests/mock_context.c |  16 +-
>  3 files changed, 153 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 4835991898ac9..10bd1b6dd1774 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -191,6 +191,97 @@ static int validate_priority(struct drm_i915_private *i915,
>  	return 0;
>  }
>  
> +static void proto_context_close(struct i915_gem_proto_context *pc)
> +{
> +	if (pc->vm)
> +		i915_vm_put(pc->vm);
> +	kfree(pc);
> +}
> +
> +static int proto_context_set_persistence(struct drm_i915_private *i915,
> +					 struct i915_gem_proto_context *pc,
> +					 bool persist)
> +{
> +	if (persist) {
> +		/*
> +		 * Only contexts that are short-lived [that will expire or be
> +		 * reset] are allowed to survive past termination. We require
> +		 * hangcheck to ensure that the persistent requests are healthy.
> +		 */
> +		if (!i915->params.enable_hangcheck)
> +			return -EINVAL;
> +
> +		__set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);

Ok so I looked, and the reason __set_bit and friends is for endless
bitfields, i.e. where user_flags is an actually dynamically sized array.

Given that this is complete overkill I think fully open-coding the bitops
is the right bikeshed color choice. So

		user_flags &= UCONTEXT_PERSISTENCE;

> +	} else {
> +		/* To cancel a context we use "preempt-to-idle" */
> +		if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
> +			return -ENODEV;
> +
> +		/*
> +		 * If the cancel fails, we then need to reset, cleanly!
> +		 *
> +		 * If the per-engine reset fails, all hope is lost! We resort
> +		 * to a full GPU reset in that unlikely case, but realistically
> +		 * if the engine could not reset, the full reset does not fare
> +		 * much better. The damage has been done.
> +		 *
> +		 * However, if we cannot reset an engine by itself, we cannot
> +		 * cleanup a hanging persistent context without causing
> +		 * colateral damage, and we should not pretend we can by
> +		 * exposing the interface.
> +		 */
> +		if (!intel_has_reset_engine(&i915->gt))
> +			return -ENODEV;
> +
> +		__clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);

		user_flags &= ~UCONTEXT_PERSISTENCE;

Similar for all the others.

> +	}
> +
> +	return 0;
> +}
> +
> +static struct i915_gem_proto_context *
> +proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> +{
> +	struct i915_gem_proto_context *pc, *err;
> +
> +	pc = kzalloc(sizeof(*pc), GFP_KERNEL);
> +	if (!pc)
> +		return ERR_PTR(-ENOMEM);
> +
> +	if (HAS_FULL_PPGTT(i915)) {
> +		struct i915_ppgtt *ppgtt;
> +
> +		ppgtt = i915_ppgtt_create(&i915->gt);
> +		if (IS_ERR(ppgtt)) {
> +			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> +				PTR_ERR(ppgtt));
> +			err = ERR_CAST(ppgtt);
> +			goto proto_close;
> +		}
> +		pc->vm = &ppgtt->vm;

I'm not understanding why we're creating the default vm as part of the
proto context? If we end up setting one this is kinda just wasted
conditionals, and we're not really gaining in code simplicity. It's just
whether we create the default vm here (and might need to delete it) or
when we finalize the context in i915_gem_create_context().

Or am I missing something?

If it's cleaner overall I'm ok with this, just feels a bit silly.

> +	}
> +
> +	pc->user_flags = 0;
> +	__set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> +	__set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> +	proto_context_set_persistence(i915, pc, true);

So this I think is another case of trying too hard to share code, because
what this essentially does is pick the default through a _very_ contrived
way:
- we start out with false since we kzalloc, so everything is cleared
- we try to enable persistence, but we fail silently, so if the module
  options don't allow persistence we silently keep it at false

I think open-coding this condition would be a lot better. Also disabling
hangcheck isn't a thing anymore, but we still have code in it.

I think the right thing here is a patch which removes all occurences of
params.enable_hangcheck and replaces it with the default (which is true).

And then just set this default here directly, because not doing so would
randomly break some mesa depending how a modparam is set which otherwise
has 0 impact. Also I think the other code which checks this could end up
with a refcount underrun on !execlist platforms.

> +	pc->sched.priority = I915_PRIORITY_NORMAL;
> +
> +	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> +		if (!HAS_EXECLISTS(i915)) {
> +			err = ERR_PTR(-EINVAL);
> +			goto proto_close;
> +		}
> +		pc->single_timeline = true;
> +	}
> +
> +	return pc;
> +
> +proto_close:
> +	proto_context_close(pc);
> +	return err;
> +}
> +
>  static struct i915_address_space *
>  context_get_vm_rcu(struct i915_gem_context *ctx)
>  {
> @@ -660,7 +751,8 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
>  }
>  
>  static struct i915_gem_context *
> -__create_context(struct drm_i915_private *i915)
> +__create_context(struct drm_i915_private *i915,
> +		 const struct i915_gem_proto_context *pc)
>  {
>  	struct i915_gem_context *ctx;
>  	struct i915_gem_engines *e;
> @@ -673,7 +765,7 @@ __create_context(struct drm_i915_private *i915)
>  
>  	kref_init(&ctx->ref);
>  	ctx->i915 = i915;
> -	ctx->sched.priority = I915_PRIORITY_NORMAL;
> +	ctx->sched = pc->sched;
>  	mutex_init(&ctx->mutex);
>  	INIT_LIST_HEAD(&ctx->link);
>  
> @@ -696,9 +788,7 @@ __create_context(struct drm_i915_private *i915)
>  	 * is no remap info, it will be a NOP. */
>  	ctx->remap_slice = ALL_L3_SLICES(i915);
>  
> -	i915_gem_context_set_bannable(ctx);
> -	i915_gem_context_set_recoverable(ctx);
> -	__context_set_persistence(ctx, true /* cgroup hook? */);
> +	ctx->user_flags = pc->user_flags;
>  
>  	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
>  		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
> @@ -786,38 +876,23 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
>  }
>  
>  static struct i915_gem_context *
> -i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
> +i915_gem_create_context(struct drm_i915_private *i915,
> +			const struct i915_gem_proto_context *pc)
>  {
>  	struct i915_gem_context *ctx;
>  	int ret;
>  
> -	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
> -	    !HAS_EXECLISTS(i915))
> -		return ERR_PTR(-EINVAL);
> -
> -	ctx = __create_context(i915);
> +	ctx = __create_context(i915, pc);
>  	if (IS_ERR(ctx))
>  		return ctx;
>  
> -	if (HAS_FULL_PPGTT(i915)) {
> -		struct i915_ppgtt *ppgtt;
> -
> -		ppgtt = i915_ppgtt_create(&i915->gt);
> -		if (IS_ERR(ppgtt)) {
> -			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> -				PTR_ERR(ppgtt));
> -			context_close(ctx);
> -			return ERR_CAST(ppgtt);
> -		}
> -
> +	if (pc->vm) {
>  		mutex_lock(&ctx->mutex);
> -		__assign_ppgtt(ctx, &ppgtt->vm);
> +		__assign_ppgtt(ctx, pc->vm);
>  		mutex_unlock(&ctx->mutex);
> -
> -		i915_vm_put(&ppgtt->vm);
>  	}
>  
> -	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> +	if (pc->single_timeline) {
>  		ret = drm_syncobj_create(&ctx->syncobj,
>  					 DRM_SYNCOBJ_CREATE_SIGNALED,
>  					 NULL);
> @@ -883,6 +958,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>  			  struct drm_file *file)
>  {
>  	struct drm_i915_file_private *file_priv = file->driver_priv;
> +	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
>  	int err;
>  	u32 id;
> @@ -892,7 +968,14 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>  	/* 0 reserved for invalid/unassigned ppgtt */
>  	xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
>  
> -	ctx = i915_gem_create_context(i915, 0);
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc)) {
> +		err = PTR_ERR(pc);
> +		goto err;
> +	}
> +
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>  	if (IS_ERR(ctx)) {
>  		err = PTR_ERR(ctx);
>  		goto err;
> @@ -1885,6 +1968,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  {
>  	struct drm_i915_private *i915 = to_i915(dev);
>  	struct drm_i915_gem_context_create_ext *args = data;
> +	struct i915_gem_proto_context *pc;
>  	struct create_ext ext_data;
>  	int ret;
>  	u32 id;
> @@ -1907,7 +1991,12 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  		return -EIO;
>  	}
>  
> -	ext_data.ctx = i915_gem_create_context(i915, args->flags);
> +	pc = proto_context_create(i915, args->flags);
> +	if (IS_ERR(pc))
> +		return PTR_ERR(pc);
> +
> +	ext_data.ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>  	if (IS_ERR(ext_data.ctx))
>  		return PTR_ERR(ext_data.ctx);
>  
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index 5f0673a2129f9..0bf337b6d89ac 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -66,6 +66,28 @@ struct i915_gem_engines_iter {
>  	const struct i915_gem_engines *engines;
>  };
>  
> +/**
> + * struct i915_gem_proto_context - prototype context
> + *
> + * The struct i915_gem_proto_context represents the creation parameters for
> + * an i915_gem_context.  This is used to gather parameters provided either
> + * through creation flags or via SET_CONTEXT_PARAM so that, when we create
> + * the final i915_gem_context, those parameters can be immutable.
> + */
> +struct i915_gem_proto_context {
> +	/** @vm: See i915_gem_context::vm */
> +	struct i915_address_space *vm;
> +
> +	/** @user_flags: See i915_gem_context::user_flags */
> +	unsigned long user_flags;
> +
> +	/** @sched: See i915_gem_context::sched */
> +	struct i915_sched_attr sched;
> +
> +	/** @single_timeline: See See i915_gem_context::syncobj */
> +	bool single_timeline;
> +};
> +
>  /**
>   * struct i915_gem_context - client state
>   *
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index 51b5a3421b400..e0f512ef7f3c6 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -80,11 +80,17 @@ void mock_init_contexts(struct drm_i915_private *i915)
>  struct i915_gem_context *
>  live_context(struct drm_i915_private *i915, struct file *file)
>  {
> +	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
>  	int err;
>  	u32 id;
>  
> -	ctx = i915_gem_create_context(i915, 0);
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc))
> +		return ERR_CAST(pc);
> +
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>  	if (IS_ERR(ctx))
>  		return ctx;
>  
> @@ -142,8 +148,14 @@ struct i915_gem_context *
>  kernel_context(struct drm_i915_private *i915)
>  {
>  	struct i915_gem_context *ctx;
> +	struct i915_gem_proto_context *pc;
> +
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc))
> +		return ERR_CAST(pc);
>  
> -	ctx = i915_gem_create_context(i915, 0);
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);

I think at large still looks pretty good, but some polish needed.
-Daniel

>  	if (IS_ERR(ctx))
>  		return ctx;
>  
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct
@ 2021-05-04 16:13     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 16:13 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:37AM -0500, Jason Ekstrand wrote:
> The current context uAPI allows for two methods of setting context
> parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
> former is allowed to be called at any time while the later happens as
> part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
> settable via the other.  While some params are fairly simple and setting
> them on a live context is harmless such the context priority, others are
> far trickier such as the VM or the set of engines.  In order to swap out
> the VM, for instance, we have to delay until all current in-flight work
> is complete, swap in the new VM, and then continue.  This leads to a
> plethora of potential race conditions we'd really rather avoid.
> 
> Unfortunately, both methods of setting the VM and engine set are in
> active use today so we can't simply disallow setting the VM or engine
> set vial SET_CONTEXT_PARAM.  In order to work around this wart, this
> commit adds a proto-context struct which contains all the context create
> parameters.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Per-patch changelog pls.

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 145 ++++++++++++++----
>  .../gpu/drm/i915/gem/i915_gem_context_types.h |  22 +++
>  .../gpu/drm/i915/gem/selftests/mock_context.c |  16 +-
>  3 files changed, 153 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 4835991898ac9..10bd1b6dd1774 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -191,6 +191,97 @@ static int validate_priority(struct drm_i915_private *i915,
>  	return 0;
>  }
>  
> +static void proto_context_close(struct i915_gem_proto_context *pc)
> +{
> +	if (pc->vm)
> +		i915_vm_put(pc->vm);
> +	kfree(pc);
> +}
> +
> +static int proto_context_set_persistence(struct drm_i915_private *i915,
> +					 struct i915_gem_proto_context *pc,
> +					 bool persist)
> +{
> +	if (persist) {
> +		/*
> +		 * Only contexts that are short-lived [that will expire or be
> +		 * reset] are allowed to survive past termination. We require
> +		 * hangcheck to ensure that the persistent requests are healthy.
> +		 */
> +		if (!i915->params.enable_hangcheck)
> +			return -EINVAL;
> +
> +		__set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);

Ok so I looked, and the reason __set_bit and friends is for endless
bitfields, i.e. where user_flags is an actually dynamically sized array.

Given that this is complete overkill I think fully open-coding the bitops
is the right bikeshed color choice. So

		user_flags &= UCONTEXT_PERSISTENCE;

> +	} else {
> +		/* To cancel a context we use "preempt-to-idle" */
> +		if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
> +			return -ENODEV;
> +
> +		/*
> +		 * If the cancel fails, we then need to reset, cleanly!
> +		 *
> +		 * If the per-engine reset fails, all hope is lost! We resort
> +		 * to a full GPU reset in that unlikely case, but realistically
> +		 * if the engine could not reset, the full reset does not fare
> +		 * much better. The damage has been done.
> +		 *
> +		 * However, if we cannot reset an engine by itself, we cannot
> +		 * cleanup a hanging persistent context without causing
> +		 * colateral damage, and we should not pretend we can by
> +		 * exposing the interface.
> +		 */
> +		if (!intel_has_reset_engine(&i915->gt))
> +			return -ENODEV;
> +
> +		__clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);

		user_flags &= ~UCONTEXT_PERSISTENCE;

Similar for all the others.

> +	}
> +
> +	return 0;
> +}
> +
> +static struct i915_gem_proto_context *
> +proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> +{
> +	struct i915_gem_proto_context *pc, *err;
> +
> +	pc = kzalloc(sizeof(*pc), GFP_KERNEL);
> +	if (!pc)
> +		return ERR_PTR(-ENOMEM);
> +
> +	if (HAS_FULL_PPGTT(i915)) {
> +		struct i915_ppgtt *ppgtt;
> +
> +		ppgtt = i915_ppgtt_create(&i915->gt);
> +		if (IS_ERR(ppgtt)) {
> +			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> +				PTR_ERR(ppgtt));
> +			err = ERR_CAST(ppgtt);
> +			goto proto_close;
> +		}
> +		pc->vm = &ppgtt->vm;

I'm not understanding why we're creating the default vm as part of the
proto context? If we end up setting one this is kinda just wasted
conditionals, and we're not really gaining in code simplicity. It's just
whether we create the default vm here (and might need to delete it) or
when we finalize the context in i915_gem_create_context().

Or am I missing something?

If it's cleaner overall I'm ok with this, just feels a bit silly.

> +	}
> +
> +	pc->user_flags = 0;
> +	__set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> +	__set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> +	proto_context_set_persistence(i915, pc, true);

So this I think is another case of trying too hard to share code, because
what this essentially does is pick the default through a _very_ contrived
way:
- we start out with false since we kzalloc, so everything is cleared
- we try to enable persistence, but we fail silently, so if the module
  options don't allow persistence we silently keep it at false

I think open-coding this condition would be a lot better. Also disabling
hangcheck isn't a thing anymore, but we still have code in it.

I think the right thing here is a patch which removes all occurences of
params.enable_hangcheck and replaces it with the default (which is true).

And then just set this default here directly, because not doing so would
randomly break some mesa depending how a modparam is set which otherwise
has 0 impact. Also I think the other code which checks this could end up
with a refcount underrun on !execlist platforms.

> +	pc->sched.priority = I915_PRIORITY_NORMAL;
> +
> +	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> +		if (!HAS_EXECLISTS(i915)) {
> +			err = ERR_PTR(-EINVAL);
> +			goto proto_close;
> +		}
> +		pc->single_timeline = true;
> +	}
> +
> +	return pc;
> +
> +proto_close:
> +	proto_context_close(pc);
> +	return err;
> +}
> +
>  static struct i915_address_space *
>  context_get_vm_rcu(struct i915_gem_context *ctx)
>  {
> @@ -660,7 +751,8 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
>  }
>  
>  static struct i915_gem_context *
> -__create_context(struct drm_i915_private *i915)
> +__create_context(struct drm_i915_private *i915,
> +		 const struct i915_gem_proto_context *pc)
>  {
>  	struct i915_gem_context *ctx;
>  	struct i915_gem_engines *e;
> @@ -673,7 +765,7 @@ __create_context(struct drm_i915_private *i915)
>  
>  	kref_init(&ctx->ref);
>  	ctx->i915 = i915;
> -	ctx->sched.priority = I915_PRIORITY_NORMAL;
> +	ctx->sched = pc->sched;
>  	mutex_init(&ctx->mutex);
>  	INIT_LIST_HEAD(&ctx->link);
>  
> @@ -696,9 +788,7 @@ __create_context(struct drm_i915_private *i915)
>  	 * is no remap info, it will be a NOP. */
>  	ctx->remap_slice = ALL_L3_SLICES(i915);
>  
> -	i915_gem_context_set_bannable(ctx);
> -	i915_gem_context_set_recoverable(ctx);
> -	__context_set_persistence(ctx, true /* cgroup hook? */);
> +	ctx->user_flags = pc->user_flags;
>  
>  	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
>  		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
> @@ -786,38 +876,23 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
>  }
>  
>  static struct i915_gem_context *
> -i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
> +i915_gem_create_context(struct drm_i915_private *i915,
> +			const struct i915_gem_proto_context *pc)
>  {
>  	struct i915_gem_context *ctx;
>  	int ret;
>  
> -	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
> -	    !HAS_EXECLISTS(i915))
> -		return ERR_PTR(-EINVAL);
> -
> -	ctx = __create_context(i915);
> +	ctx = __create_context(i915, pc);
>  	if (IS_ERR(ctx))
>  		return ctx;
>  
> -	if (HAS_FULL_PPGTT(i915)) {
> -		struct i915_ppgtt *ppgtt;
> -
> -		ppgtt = i915_ppgtt_create(&i915->gt);
> -		if (IS_ERR(ppgtt)) {
> -			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> -				PTR_ERR(ppgtt));
> -			context_close(ctx);
> -			return ERR_CAST(ppgtt);
> -		}
> -
> +	if (pc->vm) {
>  		mutex_lock(&ctx->mutex);
> -		__assign_ppgtt(ctx, &ppgtt->vm);
> +		__assign_ppgtt(ctx, pc->vm);
>  		mutex_unlock(&ctx->mutex);
> -
> -		i915_vm_put(&ppgtt->vm);
>  	}
>  
> -	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> +	if (pc->single_timeline) {
>  		ret = drm_syncobj_create(&ctx->syncobj,
>  					 DRM_SYNCOBJ_CREATE_SIGNALED,
>  					 NULL);
> @@ -883,6 +958,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>  			  struct drm_file *file)
>  {
>  	struct drm_i915_file_private *file_priv = file->driver_priv;
> +	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
>  	int err;
>  	u32 id;
> @@ -892,7 +968,14 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>  	/* 0 reserved for invalid/unassigned ppgtt */
>  	xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
>  
> -	ctx = i915_gem_create_context(i915, 0);
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc)) {
> +		err = PTR_ERR(pc);
> +		goto err;
> +	}
> +
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>  	if (IS_ERR(ctx)) {
>  		err = PTR_ERR(ctx);
>  		goto err;
> @@ -1885,6 +1968,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  {
>  	struct drm_i915_private *i915 = to_i915(dev);
>  	struct drm_i915_gem_context_create_ext *args = data;
> +	struct i915_gem_proto_context *pc;
>  	struct create_ext ext_data;
>  	int ret;
>  	u32 id;
> @@ -1907,7 +1991,12 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  		return -EIO;
>  	}
>  
> -	ext_data.ctx = i915_gem_create_context(i915, args->flags);
> +	pc = proto_context_create(i915, args->flags);
> +	if (IS_ERR(pc))
> +		return PTR_ERR(pc);
> +
> +	ext_data.ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>  	if (IS_ERR(ext_data.ctx))
>  		return PTR_ERR(ext_data.ctx);
>  
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index 5f0673a2129f9..0bf337b6d89ac 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -66,6 +66,28 @@ struct i915_gem_engines_iter {
>  	const struct i915_gem_engines *engines;
>  };
>  
> +/**
> + * struct i915_gem_proto_context - prototype context
> + *
> + * The struct i915_gem_proto_context represents the creation parameters for
> + * an i915_gem_context.  This is used to gather parameters provided either
> + * through creation flags or via SET_CONTEXT_PARAM so that, when we create
> + * the final i915_gem_context, those parameters can be immutable.
> + */
> +struct i915_gem_proto_context {
> +	/** @vm: See i915_gem_context::vm */
> +	struct i915_address_space *vm;
> +
> +	/** @user_flags: See i915_gem_context::user_flags */
> +	unsigned long user_flags;
> +
> +	/** @sched: See i915_gem_context::sched */
> +	struct i915_sched_attr sched;
> +
> +	/** @single_timeline: See See i915_gem_context::syncobj */
> +	bool single_timeline;
> +};
> +
>  /**
>   * struct i915_gem_context - client state
>   *
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index 51b5a3421b400..e0f512ef7f3c6 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -80,11 +80,17 @@ void mock_init_contexts(struct drm_i915_private *i915)
>  struct i915_gem_context *
>  live_context(struct drm_i915_private *i915, struct file *file)
>  {
> +	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
>  	int err;
>  	u32 id;
>  
> -	ctx = i915_gem_create_context(i915, 0);
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc))
> +		return ERR_CAST(pc);
> +
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>  	if (IS_ERR(ctx))
>  		return ctx;
>  
> @@ -142,8 +148,14 @@ struct i915_gem_context *
>  kernel_context(struct drm_i915_private *i915)
>  {
>  	struct i915_gem_context *ctx;
> +	struct i915_gem_proto_context *pc;
> +
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc))
> +		return ERR_CAST(pc);
>  
> -	ctx = i915_gem_create_context(i915, 0);
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);

I think at large still looks pretty good, but some polish needed.
-Daniel

>  	if (IS_ERR(ctx))
>  		return ctx;
>  
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 17/27] drm/i915/gem: Rework error handling in default_engines
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04 16:17     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 16:17 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:38AM -0500, Jason Ekstrand wrote:
> Since free_engines works for partially constructed engine sets, we can
> use the usual goto pattern.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

I guess subsequent patches apply the same for the set_engines command and
__free_engines disappears? Otherwise feels a bit silly.

Anyway looks correct.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 10bd1b6dd1774..ce729e640bbf7 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -420,7 +420,7 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>  {
>  	const struct intel_gt *gt = &ctx->i915->gt;
>  	struct intel_engine_cs *engine;
> -	struct i915_gem_engines *e;
> +	struct i915_gem_engines *e, *err;
>  	enum intel_engine_id id;
>  
>  	e = alloc_engines(I915_NUM_ENGINES);
> @@ -438,18 +438,21 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>  
>  		ce = intel_context_create(engine);
>  		if (IS_ERR(ce)) {
> -			__free_engines(e, e->num_engines + 1);
> -			return ERR_CAST(ce);
> +			err = ERR_CAST(ce);
> +			goto free_engines;
>  		}
>  
>  		intel_context_set_gem(ce, ctx);
>  
>  		e->engines[engine->legacy_idx] = ce;
> -		e->num_engines = max(e->num_engines, engine->legacy_idx);
> +		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
>  	}
> -	e->num_engines++;
>  
>  	return e;
> +
> +free_engines:
> +	free_engines(e);
> +	return err;
>  }
>  
>  void i915_gem_context_release(struct kref *ref)
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 17/27] drm/i915/gem: Rework error handling in default_engines
@ 2021-05-04 16:17     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 16:17 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:38AM -0500, Jason Ekstrand wrote:
> Since free_engines works for partially constructed engine sets, we can
> use the usual goto pattern.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

I guess subsequent patches apply the same for the set_engines command and
__free_engines disappears? Otherwise feels a bit silly.

Anyway looks correct.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 10bd1b6dd1774..ce729e640bbf7 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -420,7 +420,7 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>  {
>  	const struct intel_gt *gt = &ctx->i915->gt;
>  	struct intel_engine_cs *engine;
> -	struct i915_gem_engines *e;
> +	struct i915_gem_engines *e, *err;
>  	enum intel_engine_id id;
>  
>  	e = alloc_engines(I915_NUM_ENGINES);
> @@ -438,18 +438,21 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>  
>  		ce = intel_context_create(engine);
>  		if (IS_ERR(ce)) {
> -			__free_engines(e, e->num_engines + 1);
> -			return ERR_CAST(ce);
> +			err = ERR_CAST(ce);
> +			goto free_engines;
>  		}
>  
>  		intel_context_set_gem(ce, ctx);
>  
>  		e->engines[engine->legacy_idx] = ce;
> -		e->num_engines = max(e->num_engines, engine->legacy_idx);
> +		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
>  	}
> -	e->num_engines++;
>  
>  	return e;
> +
> +free_engines:
> +	free_engines(e);
> +	return err;
>  }
>  
>  void i915_gem_context_release(struct kref *ref)
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04 19:00     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 19:00 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:39AM -0500, Jason Ekstrand wrote:
> For now this is a no-op because everyone passes in a null SSEU but it
> lets us get some of the error handling and selftest refactoring plumbed
> through.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

it is a bit icky that intel_context_set_gem also sets the sseu, feels a
bit like a layering violation, but welp I couldn't come up with a better
idea either.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 41 +++++++++++++++----
>  .../gpu/drm/i915/gem/selftests/mock_context.c |  6 ++-
>  2 files changed, 36 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index ce729e640bbf7..6dd50d669c5b9 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -320,9 +320,12 @@ context_get_vm_rcu(struct i915_gem_context *ctx)
>  	} while (1);
>  }
>  
> -static void intel_context_set_gem(struct intel_context *ce,
> -				  struct i915_gem_context *ctx)
> +static int intel_context_set_gem(struct intel_context *ce,
> +				 struct i915_gem_context *ctx,
> +				 struct intel_sseu sseu)
>  {
> +	int ret = 0;
> +
>  	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
>  	RCU_INIT_POINTER(ce->gem_context, ctx);
>  
> @@ -349,6 +352,12 @@ static void intel_context_set_gem(struct intel_context *ce,
>  
>  		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
>  	}
> +
> +	/* A valid SSEU has no zero fields */
> +	if (sseu.slice_mask && !WARN_ON(ce->engine->class != RENDER_CLASS))
> +		ret = intel_context_reconfigure_sseu(ce, sseu);
> +
> +	return ret;
>  }
>  
>  static void __free_engines(struct i915_gem_engines *e, unsigned int count)
> @@ -416,7 +425,8 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
>  	return e;
>  }
>  
> -static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> +static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> +						struct intel_sseu rcs_sseu)
>  {
>  	const struct intel_gt *gt = &ctx->i915->gt;
>  	struct intel_engine_cs *engine;
> @@ -429,6 +439,8 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>  
>  	for_each_engine(engine, gt, id) {
>  		struct intel_context *ce;
> +		struct intel_sseu sseu = {};
> +		int ret;
>  
>  		if (engine->legacy_idx == INVALID_ENGINE)
>  			continue;
> @@ -442,10 +454,18 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>  			goto free_engines;
>  		}
>  
> -		intel_context_set_gem(ce, ctx);
> -
>  		e->engines[engine->legacy_idx] = ce;
>  		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
> +
> +		if (engine->class == RENDER_CLASS)
> +			sseu = rcs_sseu;
> +
> +		ret = intel_context_set_gem(ce, ctx, sseu);
> +		if (ret) {
> +			err = ERR_PTR(ret);
> +			goto free_engines;
> +		}
> +
>  	}
>  
>  	return e;
> @@ -759,6 +779,7 @@ __create_context(struct drm_i915_private *i915,
>  {
>  	struct i915_gem_context *ctx;
>  	struct i915_gem_engines *e;
> +	struct intel_sseu null_sseu = {};
>  	int err;
>  	int i;
>  
> @@ -776,7 +797,7 @@ __create_context(struct drm_i915_private *i915,
>  	INIT_LIST_HEAD(&ctx->stale.engines);
>  
>  	mutex_init(&ctx->engines_mutex);
> -	e = default_engines(ctx);
> +	e = default_engines(ctx, null_sseu);
>  	if (IS_ERR(e)) {
>  		err = PTR_ERR(e);
>  		goto err_free;
> @@ -1544,6 +1565,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>  	struct intel_engine_cs *stack[16];
>  	struct intel_engine_cs **siblings;
>  	struct intel_context *ce;
> +	struct intel_sseu null_sseu = {};
>  	u16 num_siblings, idx;
>  	unsigned int n;
>  	int err;
> @@ -1616,7 +1638,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>  		goto out_siblings;
>  	}
>  
> -	intel_context_set_gem(ce, set->ctx);
> +	intel_context_set_gem(ce, set->ctx, null_sseu);
>  
>  	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
>  		intel_context_put(ce);
> @@ -1724,6 +1746,7 @@ set_engines(struct i915_gem_context *ctx,
>  	struct drm_i915_private *i915 = ctx->i915;
>  	struct i915_context_param_engines __user *user =
>  		u64_to_user_ptr(args->value);
> +	struct intel_sseu null_sseu = {};
>  	struct set_engines set = { .ctx = ctx };
>  	unsigned int num_engines, n;
>  	u64 extensions;
> @@ -1733,7 +1756,7 @@ set_engines(struct i915_gem_context *ctx,
>  		if (!i915_gem_context_user_engines(ctx))
>  			return 0;
>  
> -		set.engines = default_engines(ctx);
> +		set.engines = default_engines(ctx, null_sseu);
>  		if (IS_ERR(set.engines))
>  			return PTR_ERR(set.engines);
>  
> @@ -1790,7 +1813,7 @@ set_engines(struct i915_gem_context *ctx,
>  			return PTR_ERR(ce);
>  		}
>  
> -		intel_context_set_gem(ce, ctx);
> +		intel_context_set_gem(ce, ctx, null_sseu);
>  
>  		set.engines->engines[n] = ce;
>  	}
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index e0f512ef7f3c6..cbeefd060e97b 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -14,6 +14,7 @@ mock_context(struct drm_i915_private *i915,
>  {
>  	struct i915_gem_context *ctx;
>  	struct i915_gem_engines *e;
> +	struct intel_sseu null_sseu = {};
>  
>  	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>  	if (!ctx)
> @@ -31,7 +32,7 @@ mock_context(struct drm_i915_private *i915,
>  	i915_gem_context_set_persistence(ctx);
>  
>  	mutex_init(&ctx->engines_mutex);
> -	e = default_engines(ctx);
> +	e = default_engines(ctx, null_sseu);
>  	if (IS_ERR(e))
>  		goto err_free;
>  	RCU_INIT_POINTER(ctx->engines, e);
> @@ -112,6 +113,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>  {
>  	struct i915_gem_engines *engines;
>  	struct i915_gem_context *ctx;
> +	struct intel_sseu null_sseu = {};
>  	struct intel_context *ce;
>  
>  	engines = alloc_engines(1);
> @@ -130,7 +132,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>  		return ERR_CAST(ce);
>  	}
>  
> -	intel_context_set_gem(ce, ctx);
> +	intel_context_set_gem(ce, ctx, null_sseu);
>  	engines->engines[0] = ce;
>  	engines->num_engines = 1;
>  
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem
@ 2021-05-04 19:00     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 19:00 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:39AM -0500, Jason Ekstrand wrote:
> For now this is a no-op because everyone passes in a null SSEU but it
> lets us get some of the error handling and selftest refactoring plumbed
> through.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

it is a bit icky that intel_context_set_gem also sets the sseu, feels a
bit like a layering violation, but welp I couldn't come up with a better
idea either.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 41 +++++++++++++++----
>  .../gpu/drm/i915/gem/selftests/mock_context.c |  6 ++-
>  2 files changed, 36 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index ce729e640bbf7..6dd50d669c5b9 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -320,9 +320,12 @@ context_get_vm_rcu(struct i915_gem_context *ctx)
>  	} while (1);
>  }
>  
> -static void intel_context_set_gem(struct intel_context *ce,
> -				  struct i915_gem_context *ctx)
> +static int intel_context_set_gem(struct intel_context *ce,
> +				 struct i915_gem_context *ctx,
> +				 struct intel_sseu sseu)
>  {
> +	int ret = 0;
> +
>  	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
>  	RCU_INIT_POINTER(ce->gem_context, ctx);
>  
> @@ -349,6 +352,12 @@ static void intel_context_set_gem(struct intel_context *ce,
>  
>  		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
>  	}
> +
> +	/* A valid SSEU has no zero fields */
> +	if (sseu.slice_mask && !WARN_ON(ce->engine->class != RENDER_CLASS))
> +		ret = intel_context_reconfigure_sseu(ce, sseu);
> +
> +	return ret;
>  }
>  
>  static void __free_engines(struct i915_gem_engines *e, unsigned int count)
> @@ -416,7 +425,8 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
>  	return e;
>  }
>  
> -static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> +static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> +						struct intel_sseu rcs_sseu)
>  {
>  	const struct intel_gt *gt = &ctx->i915->gt;
>  	struct intel_engine_cs *engine;
> @@ -429,6 +439,8 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>  
>  	for_each_engine(engine, gt, id) {
>  		struct intel_context *ce;
> +		struct intel_sseu sseu = {};
> +		int ret;
>  
>  		if (engine->legacy_idx == INVALID_ENGINE)
>  			continue;
> @@ -442,10 +454,18 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>  			goto free_engines;
>  		}
>  
> -		intel_context_set_gem(ce, ctx);
> -
>  		e->engines[engine->legacy_idx] = ce;
>  		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
> +
> +		if (engine->class == RENDER_CLASS)
> +			sseu = rcs_sseu;
> +
> +		ret = intel_context_set_gem(ce, ctx, sseu);
> +		if (ret) {
> +			err = ERR_PTR(ret);
> +			goto free_engines;
> +		}
> +
>  	}
>  
>  	return e;
> @@ -759,6 +779,7 @@ __create_context(struct drm_i915_private *i915,
>  {
>  	struct i915_gem_context *ctx;
>  	struct i915_gem_engines *e;
> +	struct intel_sseu null_sseu = {};
>  	int err;
>  	int i;
>  
> @@ -776,7 +797,7 @@ __create_context(struct drm_i915_private *i915,
>  	INIT_LIST_HEAD(&ctx->stale.engines);
>  
>  	mutex_init(&ctx->engines_mutex);
> -	e = default_engines(ctx);
> +	e = default_engines(ctx, null_sseu);
>  	if (IS_ERR(e)) {
>  		err = PTR_ERR(e);
>  		goto err_free;
> @@ -1544,6 +1565,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>  	struct intel_engine_cs *stack[16];
>  	struct intel_engine_cs **siblings;
>  	struct intel_context *ce;
> +	struct intel_sseu null_sseu = {};
>  	u16 num_siblings, idx;
>  	unsigned int n;
>  	int err;
> @@ -1616,7 +1638,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>  		goto out_siblings;
>  	}
>  
> -	intel_context_set_gem(ce, set->ctx);
> +	intel_context_set_gem(ce, set->ctx, null_sseu);
>  
>  	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
>  		intel_context_put(ce);
> @@ -1724,6 +1746,7 @@ set_engines(struct i915_gem_context *ctx,
>  	struct drm_i915_private *i915 = ctx->i915;
>  	struct i915_context_param_engines __user *user =
>  		u64_to_user_ptr(args->value);
> +	struct intel_sseu null_sseu = {};
>  	struct set_engines set = { .ctx = ctx };
>  	unsigned int num_engines, n;
>  	u64 extensions;
> @@ -1733,7 +1756,7 @@ set_engines(struct i915_gem_context *ctx,
>  		if (!i915_gem_context_user_engines(ctx))
>  			return 0;
>  
> -		set.engines = default_engines(ctx);
> +		set.engines = default_engines(ctx, null_sseu);
>  		if (IS_ERR(set.engines))
>  			return PTR_ERR(set.engines);
>  
> @@ -1790,7 +1813,7 @@ set_engines(struct i915_gem_context *ctx,
>  			return PTR_ERR(ce);
>  		}
>  
> -		intel_context_set_gem(ce, ctx);
> +		intel_context_set_gem(ce, ctx, null_sseu);
>  
>  		set.engines->engines[n] = ce;
>  	}
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index e0f512ef7f3c6..cbeefd060e97b 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -14,6 +14,7 @@ mock_context(struct drm_i915_private *i915,
>  {
>  	struct i915_gem_context *ctx;
>  	struct i915_gem_engines *e;
> +	struct intel_sseu null_sseu = {};
>  
>  	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>  	if (!ctx)
> @@ -31,7 +32,7 @@ mock_context(struct drm_i915_private *i915,
>  	i915_gem_context_set_persistence(ctx);
>  
>  	mutex_init(&ctx->engines_mutex);
> -	e = default_engines(ctx);
> +	e = default_engines(ctx, null_sseu);
>  	if (IS_ERR(e))
>  		goto err_free;
>  	RCU_INIT_POINTER(ctx->engines, e);
> @@ -112,6 +113,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>  {
>  	struct i915_gem_engines *engines;
>  	struct i915_gem_context *ctx;
> +	struct intel_sseu null_sseu = {};
>  	struct intel_context *ce;
>  
>  	engines = alloc_engines(1);
> @@ -130,7 +132,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>  		return ERR_CAST(ce);
>  	}
>  
> -	intel_context_set_gem(ce, ctx);
> +	intel_context_set_gem(ce, ctx, null_sseu);
>  	engines->engines[0] = ce;
>  	engines->num_engines = 1;
>  
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04 20:33     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 20:33 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:40AM -0500, Jason Ekstrand wrote:
> This means that the proto-context needs to grow support for engine
> configuration information as well as setparam logic.  Fortunately, we'll
> be deleting a lot of setparam logic on the primary context shortly so it
> will hopefully balance out.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
>  .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
>  2 files changed, 587 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 6dd50d669c5b9..aa4edfbf7ed48 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
>  
>  static void proto_context_close(struct i915_gem_proto_context *pc)
>  {
> +	int i;
> +
>  	if (pc->vm)
>  		i915_vm_put(pc->vm);
> +	if (pc->user_engines) {
> +		for (i = 0; i < pc->num_user_engines; i++)
> +			kfree(pc->user_engines[i].siblings);
> +		kfree(pc->user_engines);

		free_engines(&pc->user_engines);

Maybe even stuff that if check into free_engines. Except I realized this
is proto engines here now :-(

> +	}
>  	kfree(pc);
>  }
>  
> @@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
>  	if (!pc)
>  		return ERR_PTR(-ENOMEM);
>  
> +	pc->num_user_engines = -1;
> +	pc->user_engines = NULL;
> +
>  	if (HAS_FULL_PPGTT(i915)) {
>  		struct i915_ppgtt *ppgtt;
>  
> @@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
>  	return err;
>  }
>  
> +static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
> +			    struct i915_gem_proto_context *pc,
> +			    const struct drm_i915_gem_context_param *args)
> +{
> +	struct i915_address_space *vm;
> +
> +	if (args->size)
> +		return -EINVAL;
> +
> +	if (!pc->vm)
> +		return -ENODEV;
> +
> +	if (upper_32_bits(args->value))
> +		return -ENOENT;
> +
> +	rcu_read_lock();
> +	vm = xa_load(&fpriv->vm_xa, args->value);
> +	if (vm && !kref_get_unless_zero(&vm->ref))
> +		vm = NULL;
> +	rcu_read_unlock();

vm lookup helpers would be nice I guess, but perhaps something that
vm_bind patches should do.

> +	if (!vm)
> +		return -ENOENT;
> +
> +	i915_vm_put(pc->vm);

Ah I guess I've found why you went with "pc->vm is always set". *shrug*

> +	pc->vm = vm;
> +
> +	return 0;
> +}
> +
> +struct set_proto_ctx_engines {
> +	struct drm_i915_private *i915;
> +	unsigned num_engines;
> +	struct i915_gem_proto_engine *engines;
> +};
> +
> +static int
> +set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
> +			      void *data)
> +{
> +	struct i915_context_engines_load_balance __user *ext =
> +		container_of_user(base, typeof(*ext), base);
> +	const struct set_proto_ctx_engines *set = data;
> +	struct drm_i915_private *i915 = set->i915;
> +	struct intel_engine_cs **siblings;
> +	u16 num_siblings, idx;
> +	unsigned int n;
> +	int err;
> +
> +	if (!HAS_EXECLISTS(i915))
> +		return -ENODEV;
> +
> +	if (intel_uc_uses_guc_submission(&i915->gt.uc))
> +		return -ENODEV; /* not implement yet */
> +
> +	if (get_user(idx, &ext->engine_index))
> +		return -EFAULT;
> +
> +	if (idx >= set->num_engines) {
> +		drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> +			idx, set->num_engines);
> +		return -EINVAL;
> +	}
> +
> +	idx = array_index_nospec(idx, set->num_engines);
> +	if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
> +		drm_dbg(&i915->drm,
> +			"Invalid placement[%d], already occupied\n", idx);
> +		return -EEXIST;
> +	}
> +
> +	if (get_user(num_siblings, &ext->num_siblings))
> +		return -EFAULT;
> +
> +	err = check_user_mbz(&ext->flags);
> +	if (err)
> +		return err;
> +
> +	err = check_user_mbz(&ext->mbz64);
> +	if (err)
> +		return err;
> +
> +	if (num_siblings == 0)
> +		return 0;

You deleted the on-stack siblings micro-optimization.

I'm shocked.

> +
> +	siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);

If you want to pay back your micro-opt budget: GFP_TEMPORARY.

But then I realized much wiser heads than me removed this in 2017 from the
kernel! That commit is a rather interesting story btw, if you're bored:

commit 0ee931c4e31a5efb134c76440405e9219f896e33
Author: Michal Hocko <mhocko@suse.com>
Date:   Wed Sep 13 16:28:29 2017 -0700

    mm: treewide: remove GFP_TEMPORARY allocation flag

> +	if (!siblings)
> +		return -ENOMEM;
> +
> +	for (n = 0; n < num_siblings; n++) {
> +		struct i915_engine_class_instance ci;
> +
> +		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> +			err = -EFAULT;
> +			goto err_siblings;
> +		}
> +
> +		siblings[n] = intel_engine_lookup_user(i915,
> +						       ci.engine_class,
> +						       ci.engine_instance);

intel_engine_user.c

...

Maybe I should just stop looking.

> +		if (!siblings[n]) {
> +			drm_dbg(&i915->drm,
> +				"Invalid sibling[%d]: { class:%d, inst:%d }\n",
> +				n, ci.engine_class, ci.engine_instance);
> +			err = -EINVAL;
> +			goto err_siblings;
> +		}
> +	}
> +
> +	if (num_siblings == 1) {
> +		set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> +		set->engines[idx].engine = siblings[0];
> +		kfree(siblings);
> +	} else {
> +		set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
> +		set->engines[idx].num_siblings = num_siblings;
> +		set->engines[idx].siblings = siblings;
> +	}
> +
> +	return 0;
> +
> +err_siblings:
> +	kfree(siblings);
> +
> +	return err;
> +}
> +
> +static int
> +set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
> +{
> +	struct i915_context_engines_bond __user *ext =
> +		container_of_user(base, typeof(*ext), base);
> +	const struct set_proto_ctx_engines *set = data;
> +	struct drm_i915_private *i915 = set->i915;
> +	struct i915_engine_class_instance ci;
> +	struct intel_engine_cs *master;
> +	u16 idx, num_bonds;
> +	int err, n;
> +
> +	if (get_user(idx, &ext->virtual_index))
> +		return -EFAULT;
> +
> +	if (idx >= set->num_engines) {
> +		drm_dbg(&i915->drm,
> +			"Invalid index for virtual engine: %d >= %d\n",
> +			idx, set->num_engines);
> +		return -EINVAL;
> +	}
> +
> +	idx = array_index_nospec(idx, set->num_engines);
> +	if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
> +		drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> +		return -EINVAL;
> +	}
> +
> +	if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
> +		drm_dbg(&i915->drm,
> +			"Bonding with virtual engines not allowed\n");
> +		return -EINVAL;
> +	}
> +
> +	err = check_user_mbz(&ext->flags);
> +	if (err)
> +		return err;
> +
> +	for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> +		err = check_user_mbz(&ext->mbz64[n]);
> +		if (err)
> +			return err;
> +	}
> +
> +	if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> +		return -EFAULT;
> +
> +	master = intel_engine_lookup_user(i915,
> +					  ci.engine_class,
> +					  ci.engine_instance);
> +	if (!master) {

It's 100% orthogonal annoyance, but maybe we can start the "what's a good
name here" discussion.

I'm thinking s/master/first/ and s/slave/subsequent/ that reflect how this
is actually used on the execbuf side. But then this entire bonded
extension is so disconnected from the actual use-case, maybe we should
just sun-set it before we bother.

Since we might need to keep the execlist backend implementation the
renaming might still be needed.

> +		drm_dbg(&i915->drm,
> +			"Unrecognised master engine: { class:%u, instance:%u }\n",
> +			ci.engine_class, ci.engine_instance);
> +		return -EINVAL;
> +	}
> +
> +	if (get_user(num_bonds, &ext->num_bonds))
> +		return -EFAULT;
> +
> +	for (n = 0; n < num_bonds; n++) {
> +		struct intel_engine_cs *bond;
> +
> +		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> +			return -EFAULT;
> +
> +		bond = intel_engine_lookup_user(i915,
> +						ci.engine_class,
> +						ci.engine_instance);
> +		if (!bond) {
> +			drm_dbg(&i915->drm,
> +				"Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> +				n, ci.engine_class, ci.engine_instance);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
> +	[I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
> +	[I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
> +};
> +
> +static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
> +			         struct i915_gem_proto_context *pc,
> +			         const struct drm_i915_gem_context_param *args)
> +{
> +	struct drm_i915_private *i915 = fpriv->dev_priv;
> +	struct set_proto_ctx_engines set = { .i915 = i915 };
> +	struct i915_context_param_engines __user *user =
> +		u64_to_user_ptr(args->value);
> +	unsigned int n;
> +	u64 extensions;
> +	int err;
> +
> +	if (!args->size) {
> +		kfree(pc->user_engines);
> +		pc->num_user_engines = -1;

Is this case actually used by actual userspace, or just more stuff igt
loved to do?

If so more uapi to ditch, and check in an igt that it's rejected.

Plus standard !args->size handling here with appropriate drm_debug line
and all that.

> +		pc->user_engines = NULL;
> +		memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
> +		return 0;
> +	}
> +
> +	BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));

I frankly don't know what this is checking, but it also looks harmless.

> +	if (args->size < sizeof(*user) ||
> +	    !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> +		drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> +			args->size);
> +		return -EINVAL;
> +	}
> +
> +	set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> +	/* RING_MASK has no shift so we can use it directly here */
> +	if (set.num_engines > I915_EXEC_RING_MASK + 1)
> +		return -EINVAL;
> +
> +	set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
> +	if (!set.engines)
> +		return -ENOMEM;
> +
> +	for (n = 0; n < set.num_engines; n++) {
> +		struct i915_engine_class_instance ci;
> +		struct intel_engine_cs *engine;
> +
> +		if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> +			kfree(set.engines);
> +			return -EFAULT;
> +		}
> +
> +		memset(&set.engines[n], 0, sizeof(set.engines[n]));
> +
> +		if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> +		    ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
> +			continue;
> +
> +		engine = intel_engine_lookup_user(i915,
> +						  ci.engine_class,
> +						  ci.engine_instance);
> +		if (!engine) {
> +			drm_dbg(&i915->drm,
> +				"Invalid engine[%d]: { class:%d, instance:%d }\n",
> +				n, ci.engine_class, ci.engine_instance);
> +			kfree(set.engines);
> +			return -ENOENT;
> +		}
> +
> +		set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> +		set.engines[n].engine = engine;
> +	}
> +
> +	err = -EFAULT;
> +	if (!get_user(extensions, &user->extensions))
> +		err = i915_user_extensions(u64_to_user_ptr(extensions),
> +					   set_proto_ctx_engines_extensions,
> +					   ARRAY_SIZE(set_proto_ctx_engines_extensions),
> +					   &set);
> +	if (err) {
> +		kfree(set.engines);
> +		return err;
> +	}
> +
> +	kfree(pc->user_engines);

Both of these kfree potentially leak engines[].siblings. I think you need
to extract a proto_context_free_engines helper and use that 2x here and
once at the very top in proto_context_close().

> +	pc->num_user_engines = set.num_engines;
> +	pc->user_engines = set.engines;
> +
> +	return 0;
> +}
> +
> +static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
> +			      struct i915_gem_proto_context *pc,
> +			      struct drm_i915_gem_context_param *args)
> +{
> +	struct drm_i915_private *i915 = fpriv->dev_priv;
> +	struct drm_i915_gem_context_param_sseu user_sseu;
> +	struct intel_sseu *sseu;
> +	int ret;
> +
> +	if (args->size < sizeof(user_sseu))
> +		return -EINVAL;
> +
> +	if (!IS_GEN(i915, 11))
> +		return -ENODEV;
> +
> +	if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
> +			   sizeof(user_sseu)))
> +		return -EFAULT;
> +
> +	if (user_sseu.rsvd)
> +		return -EINVAL;
> +
> +	if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
> +		return -EINVAL;
> +
> +	if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
> +		return -EINVAL;
> +
> +	if (pc->num_user_engines >= 0) {
> +		int idx = user_sseu.engine.engine_instance;
> +		struct i915_gem_proto_engine *pe;
> +
> +		if (idx >= pc->num_user_engines)
> +			return -EINVAL;
> +
> +		pe = &pc->user_engines[idx];
> +
> +		/* Only render engine supports RPCS configuration. */
> +		if (pe->engine->class != RENDER_CLASS)
> +			return -EINVAL;
> +
> +		sseu = &pe->sseu;
> +	} else {
> +		/* Only render engine supports RPCS configuration. */
> +		if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
> +			return -EINVAL;
> +
> +		/* There is only one render engine */
> +		if (user_sseu.engine.engine_instance != 0)
> +			return -EINVAL;
> +
> +		sseu = &pc->legacy_rcs_sseu;
> +	}

I think this faithfully rebuilds the convoluted and I think largely
accidental semantics of SSEU for all combinations of ordering against
set_engines.

Maybe add a commit message note about this particular kind of fun here. I
don't think a code comment is warranted since I don't think I've seen a
userspace rely on how sseu interacts with set_engines


> +
> +	ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
> +	if (ret)
> +		return ret;
> +
> +	args->size = sizeof(user_sseu);
> +
> +	return 0;
> +}
> +
> +static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
> +			       struct i915_gem_proto_context *pc,
> +			       struct drm_i915_gem_context_param *args)
> +{
> +	int ret = 0;
> +
> +	switch (args->param) {
> +	case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
> +		if (args->size)
> +			ret = -EINVAL;
> +		else if (args->value)
> +			__set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> +		else
> +			__clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);

Open code please and double check I caught them all ...

> +		break;
> +
> +	case I915_CONTEXT_PARAM_BANNABLE:
> +		if (args->size)
> +			ret = -EINVAL;
> +		else if (!capable(CAP_SYS_ADMIN) && !args->value)
> +			ret = -EPERM;
> +		else if (args->value)
> +			__set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> +		else
> +			__clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> +		break;
> +
> +	case I915_CONTEXT_PARAM_RECOVERABLE:
> +		if (args->size)
> +			ret = -EINVAL;
> +		else if (args->value)
> +			__set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> +		else
> +			__clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> +		break;
> +
> +	case I915_CONTEXT_PARAM_PRIORITY:
> +		ret = validate_priority(fpriv->dev_priv, args);
> +		if (!ret)
> +			pc->sched.priority = args->value;
> +		break;
> +
> +	case I915_CONTEXT_PARAM_SSEU:
> +		ret = set_proto_ctx_sseu(fpriv, pc, args);
> +		break;
> +
> +	case I915_CONTEXT_PARAM_VM:
> +		ret = set_proto_ctx_vm(fpriv, pc, args);
> +		break;
> +
> +	case I915_CONTEXT_PARAM_ENGINES:
> +		ret = set_proto_ctx_engines(fpriv, pc, args);
> +		break;
> +
> +	case I915_CONTEXT_PARAM_PERSISTENCE:
> +		if (args->size)
> +			ret = -EINVAL;
> +		else if (args->value)
> +			__set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> +		else
> +			__clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);

I think we have a nice mess here. You created this
proto_context_set_persistence helper, but don't use it here. Oversight?

Aside from the validation fun around persistence, but that's better
discussed in another patch I think.

> +		break;
> +
> +	case I915_CONTEXT_PARAM_NO_ZEROMAP:
> +	case I915_CONTEXT_PARAM_BAN_PERIOD:
> +	case I915_CONTEXT_PARAM_RINGSIZE:
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
>  static struct i915_address_space *
>  context_get_vm_rcu(struct i915_gem_context *ctx)
>  {
> @@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
>  	return err;
>  }
>  
> +static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
> +					     unsigned int num_engines,
> +					     struct i915_gem_proto_engine *pe)
> +{
> +	struct i915_gem_engines *e, *err;
> +	unsigned int n;
> +
> +	e = alloc_engines(num_engines);
> +	for (n = 0; n < num_engines; n++) {
> +		struct intel_context *ce;
> +		int ret;
> +
> +		switch (pe[n].type) {
> +		case I915_GEM_ENGINE_TYPE_PHYSICAL:
> +			ce = intel_context_create(pe[n].engine);
> +			break;
> +
> +		case I915_GEM_ENGINE_TYPE_BALANCED:
> +			ce = intel_execlists_create_virtual(pe[n].siblings,
> +							    pe[n].num_siblings);
> +			break;
> +
> +		case I915_GEM_ENGINE_TYPE_INVALID:
> +		default:
> +			GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
> +			continue;
> +		}
> +
> +		if (IS_ERR(ce)) {
> +			err = ERR_CAST(ce);
> +			goto free_engines;
> +		}
> +
> +		e->engines[n] = ce;
> +
> +		ret = intel_context_set_gem(ce, ctx, pe->sseu);
> +		if (ret) {
> +			err = ERR_PTR(ret);
> +			goto free_engines;
> +		}
> +	}
> +	e->num_engines = num_engines;
> +
> +	return e;
> +
> +free_engines:
> +	free_engines(e);
> +	return err;
> +}
> +
>  void i915_gem_context_release(struct kref *ref)
>  {
>  	struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
> @@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
>  {
>  	struct i915_gem_context *ctx;
>  	struct i915_gem_engines *e;
> -	struct intel_sseu null_sseu = {};
>  	int err;
>  	int i;
>  
> @@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
>  	INIT_LIST_HEAD(&ctx->stale.engines);
>  
>  	mutex_init(&ctx->engines_mutex);
> -	e = default_engines(ctx, null_sseu);
> +	e = default_engines(ctx, pc->legacy_rcs_sseu);
>  	if (IS_ERR(e)) {
>  		err = PTR_ERR(e);
>  		goto err_free;
> @@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
>  		mutex_unlock(&ctx->mutex);
>  	}
>  
> +	if (pc->num_user_engines >= 0) {
> +		struct i915_gem_engines *engines;
> +
> +		engines = user_engines(ctx, pc->num_user_engines,
> +				       pc->user_engines);
> +		if (IS_ERR(engines)) {
> +			context_close(ctx);
> +			return ERR_CAST(engines);
> +		}
> +
> +		mutex_lock(&ctx->engines_mutex);
> +		i915_gem_context_set_user_engines(ctx);
> +		engines = rcu_replace_pointer(ctx->engines, engines, 1);
> +		mutex_unlock(&ctx->engines_mutex);

More locking code to ditch I guess.

> +
> +		free_engines(engines);

Also I guess we shouldn't first create the legacy engines for this case?

> +	}
> +
>  	if (pc->single_timeline) {
>  		ret = drm_syncobj_create(&ctx->syncobj,
>  					 DRM_SYNCOBJ_CREATE_SIGNALED,
> @@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>  }
>  
>  struct create_ext {
> -	struct i915_gem_context *ctx;
> +	struct i915_gem_proto_context *pc;
>  	struct drm_i915_file_private *fpriv;
>  };
>  
> @@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
>  	if (local.param.ctx_id)
>  		return -EINVAL;
>  
> -	return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> +	return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
>  }
>  
>  static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> @@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  {
>  	struct drm_i915_private *i915 = to_i915(dev);
>  	struct drm_i915_gem_context_create_ext *args = data;
> -	struct i915_gem_proto_context *pc;
> +	struct i915_gem_context *ctx;
>  	struct create_ext ext_data;
>  	int ret;
>  	u32 id;
> @@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  		return -EIO;
>  	}
>  
> -	pc = proto_context_create(i915, args->flags);
> -	if (IS_ERR(pc))
> -		return PTR_ERR(pc);
> -
> -	ext_data.ctx = i915_gem_create_context(i915, pc);
> -	proto_context_close(pc);
> -	if (IS_ERR(ext_data.ctx))
> -		return PTR_ERR(ext_data.ctx);
> +	ext_data.pc = proto_context_create(i915, args->flags);
> +	if (IS_ERR(ext_data.pc))
> +		return PTR_ERR(ext_data.pc);
>  
>  	if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
>  		ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
>  					   create_extensions,
>  					   ARRAY_SIZE(create_extensions),
>  					   &ext_data);
> -		if (ret)
> -			goto err_ctx;
> +		if (ret) {
> +			proto_context_close(ext_data.pc);
> +			return ret;
> +		}
>  	}
>  
> -	ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
> +	ctx = i915_gem_create_context(i915, ext_data.pc);
> +	proto_context_close(ext_data.pc);
> +	if (IS_ERR(ctx))
> +		return PTR_ERR(ctx);
> +
> +	ret = gem_context_register(ctx, ext_data.fpriv, &id);
>  	if (ret < 0)
>  		goto err_ctx;
>  
> @@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  	return 0;
>  
>  err_ctx:
> -	context_close(ext_data.ctx);
> +	context_close(ctx);
>  	return ret;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index 0bf337b6d89ac..2ac341f805c8f 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
>  	const struct i915_gem_engines *engines;
>  };
>  
> +/**
> + * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
> + */
> +enum i915_gem_engine_type {
> +	/** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
> +	I915_GEM_ENGINE_TYPE_INVALID = 0,
> +
> +	/** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
> +	I915_GEM_ENGINE_TYPE_PHYSICAL,
> +
> +	/** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
> +	I915_GEM_ENGINE_TYPE_BALANCED,
> +};
> +
> +/**
> + * struct i915_gem_proto_engine - prototype engine
> + *
> + * This struct describes an engine that a context may contain.  Engines
> + * have three types:
> + *
> + *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
> + *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
> + *    use them by the user results in -EINVAL.  They are also useful during
> + *    proto-context construction because the client may create invalid
> + *    engines and then set them up later as bonded engines.
> + *
> + *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
> + *    i915_gem_proto_engine::engine.
> + *
> + *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
> + *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
> + */
> +struct i915_gem_proto_engine {
> +	/** @type: Type of this engine */
> +	enum i915_gem_engine_type type;
> +
> +	/** @engine: Engine, for physical */
> +	struct intel_engine_cs *engine;
> +
> +	/** @num_siblings: Number of balanced siblings */
> +	unsigned int num_siblings;
> +
> +	/** @siblings: Balanced siblings */
> +	struct intel_engine_cs **siblings;
> +
> +	/** @sseu: Client-set SSEU parameters */
> +	struct intel_sseu sseu;
> +};
> +
>  /**
>   * struct i915_gem_proto_context - prototype context
>   *
> @@ -84,6 +133,15 @@ struct i915_gem_proto_context {
>  	/** @sched: See i915_gem_context::sched */
>  	struct i915_sched_attr sched;
>  
> +	/** @num_user_engines: Number of user-specified engines or -1 */
> +	int num_user_engines;
> +
> +	/** @user_engines: User-specified engines */
> +	struct i915_gem_proto_engine *user_engines;
> +
> +	/** @sseu: Client-set SSEU parameters for the legacy RCS */
> +	struct intel_sseu legacy_rcs_sseu;
> +
>  	/** @single_timeline: See See i915_gem_context::syncobj */
>  	bool single_timeline;
>  };
> -- 
> 2.31.1

Man is this all nasty. Since I don't want to re-review the entire pile,
assuming we figure out solutions to all the real issues I've raised (and
not the snarky bikesheds) this is

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
@ 2021-05-04 20:33     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 20:33 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:40AM -0500, Jason Ekstrand wrote:
> This means that the proto-context needs to grow support for engine
> configuration information as well as setparam logic.  Fortunately, we'll
> be deleting a lot of setparam logic on the primary context shortly so it
> will hopefully balance out.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
>  .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
>  2 files changed, 587 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 6dd50d669c5b9..aa4edfbf7ed48 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
>  
>  static void proto_context_close(struct i915_gem_proto_context *pc)
>  {
> +	int i;
> +
>  	if (pc->vm)
>  		i915_vm_put(pc->vm);
> +	if (pc->user_engines) {
> +		for (i = 0; i < pc->num_user_engines; i++)
> +			kfree(pc->user_engines[i].siblings);
> +		kfree(pc->user_engines);

		free_engines(&pc->user_engines);

Maybe even stuff that if check into free_engines. Except I realized this
is proto engines here now :-(

> +	}
>  	kfree(pc);
>  }
>  
> @@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
>  	if (!pc)
>  		return ERR_PTR(-ENOMEM);
>  
> +	pc->num_user_engines = -1;
> +	pc->user_engines = NULL;
> +
>  	if (HAS_FULL_PPGTT(i915)) {
>  		struct i915_ppgtt *ppgtt;
>  
> @@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
>  	return err;
>  }
>  
> +static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
> +			    struct i915_gem_proto_context *pc,
> +			    const struct drm_i915_gem_context_param *args)
> +{
> +	struct i915_address_space *vm;
> +
> +	if (args->size)
> +		return -EINVAL;
> +
> +	if (!pc->vm)
> +		return -ENODEV;
> +
> +	if (upper_32_bits(args->value))
> +		return -ENOENT;
> +
> +	rcu_read_lock();
> +	vm = xa_load(&fpriv->vm_xa, args->value);
> +	if (vm && !kref_get_unless_zero(&vm->ref))
> +		vm = NULL;
> +	rcu_read_unlock();

vm lookup helpers would be nice I guess, but perhaps something that
vm_bind patches should do.

> +	if (!vm)
> +		return -ENOENT;
> +
> +	i915_vm_put(pc->vm);

Ah I guess I've found why you went with "pc->vm is always set". *shrug*

> +	pc->vm = vm;
> +
> +	return 0;
> +}
> +
> +struct set_proto_ctx_engines {
> +	struct drm_i915_private *i915;
> +	unsigned num_engines;
> +	struct i915_gem_proto_engine *engines;
> +};
> +
> +static int
> +set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
> +			      void *data)
> +{
> +	struct i915_context_engines_load_balance __user *ext =
> +		container_of_user(base, typeof(*ext), base);
> +	const struct set_proto_ctx_engines *set = data;
> +	struct drm_i915_private *i915 = set->i915;
> +	struct intel_engine_cs **siblings;
> +	u16 num_siblings, idx;
> +	unsigned int n;
> +	int err;
> +
> +	if (!HAS_EXECLISTS(i915))
> +		return -ENODEV;
> +
> +	if (intel_uc_uses_guc_submission(&i915->gt.uc))
> +		return -ENODEV; /* not implement yet */
> +
> +	if (get_user(idx, &ext->engine_index))
> +		return -EFAULT;
> +
> +	if (idx >= set->num_engines) {
> +		drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> +			idx, set->num_engines);
> +		return -EINVAL;
> +	}
> +
> +	idx = array_index_nospec(idx, set->num_engines);
> +	if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
> +		drm_dbg(&i915->drm,
> +			"Invalid placement[%d], already occupied\n", idx);
> +		return -EEXIST;
> +	}
> +
> +	if (get_user(num_siblings, &ext->num_siblings))
> +		return -EFAULT;
> +
> +	err = check_user_mbz(&ext->flags);
> +	if (err)
> +		return err;
> +
> +	err = check_user_mbz(&ext->mbz64);
> +	if (err)
> +		return err;
> +
> +	if (num_siblings == 0)
> +		return 0;

You deleted the on-stack siblings micro-optimization.

I'm shocked.

> +
> +	siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);

If you want to pay back your micro-opt budget: GFP_TEMPORARY.

But then I realized much wiser heads than me removed this in 2017 from the
kernel! That commit is a rather interesting story btw, if you're bored:

commit 0ee931c4e31a5efb134c76440405e9219f896e33
Author: Michal Hocko <mhocko@suse.com>
Date:   Wed Sep 13 16:28:29 2017 -0700

    mm: treewide: remove GFP_TEMPORARY allocation flag

> +	if (!siblings)
> +		return -ENOMEM;
> +
> +	for (n = 0; n < num_siblings; n++) {
> +		struct i915_engine_class_instance ci;
> +
> +		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> +			err = -EFAULT;
> +			goto err_siblings;
> +		}
> +
> +		siblings[n] = intel_engine_lookup_user(i915,
> +						       ci.engine_class,
> +						       ci.engine_instance);

intel_engine_user.c

...

Maybe I should just stop looking.

> +		if (!siblings[n]) {
> +			drm_dbg(&i915->drm,
> +				"Invalid sibling[%d]: { class:%d, inst:%d }\n",
> +				n, ci.engine_class, ci.engine_instance);
> +			err = -EINVAL;
> +			goto err_siblings;
> +		}
> +	}
> +
> +	if (num_siblings == 1) {
> +		set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> +		set->engines[idx].engine = siblings[0];
> +		kfree(siblings);
> +	} else {
> +		set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
> +		set->engines[idx].num_siblings = num_siblings;
> +		set->engines[idx].siblings = siblings;
> +	}
> +
> +	return 0;
> +
> +err_siblings:
> +	kfree(siblings);
> +
> +	return err;
> +}
> +
> +static int
> +set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
> +{
> +	struct i915_context_engines_bond __user *ext =
> +		container_of_user(base, typeof(*ext), base);
> +	const struct set_proto_ctx_engines *set = data;
> +	struct drm_i915_private *i915 = set->i915;
> +	struct i915_engine_class_instance ci;
> +	struct intel_engine_cs *master;
> +	u16 idx, num_bonds;
> +	int err, n;
> +
> +	if (get_user(idx, &ext->virtual_index))
> +		return -EFAULT;
> +
> +	if (idx >= set->num_engines) {
> +		drm_dbg(&i915->drm,
> +			"Invalid index for virtual engine: %d >= %d\n",
> +			idx, set->num_engines);
> +		return -EINVAL;
> +	}
> +
> +	idx = array_index_nospec(idx, set->num_engines);
> +	if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
> +		drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> +		return -EINVAL;
> +	}
> +
> +	if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
> +		drm_dbg(&i915->drm,
> +			"Bonding with virtual engines not allowed\n");
> +		return -EINVAL;
> +	}
> +
> +	err = check_user_mbz(&ext->flags);
> +	if (err)
> +		return err;
> +
> +	for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> +		err = check_user_mbz(&ext->mbz64[n]);
> +		if (err)
> +			return err;
> +	}
> +
> +	if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> +		return -EFAULT;
> +
> +	master = intel_engine_lookup_user(i915,
> +					  ci.engine_class,
> +					  ci.engine_instance);
> +	if (!master) {

It's 100% orthogonal annoyance, but maybe we can start the "what's a good
name here" discussion.

I'm thinking s/master/first/ and s/slave/subsequent/ that reflect how this
is actually used on the execbuf side. But then this entire bonded
extension is so disconnected from the actual use-case, maybe we should
just sun-set it before we bother.

Since we might need to keep the execlist backend implementation the
renaming might still be needed.

> +		drm_dbg(&i915->drm,
> +			"Unrecognised master engine: { class:%u, instance:%u }\n",
> +			ci.engine_class, ci.engine_instance);
> +		return -EINVAL;
> +	}
> +
> +	if (get_user(num_bonds, &ext->num_bonds))
> +		return -EFAULT;
> +
> +	for (n = 0; n < num_bonds; n++) {
> +		struct intel_engine_cs *bond;
> +
> +		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> +			return -EFAULT;
> +
> +		bond = intel_engine_lookup_user(i915,
> +						ci.engine_class,
> +						ci.engine_instance);
> +		if (!bond) {
> +			drm_dbg(&i915->drm,
> +				"Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> +				n, ci.engine_class, ci.engine_instance);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
> +	[I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
> +	[I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
> +};
> +
> +static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
> +			         struct i915_gem_proto_context *pc,
> +			         const struct drm_i915_gem_context_param *args)
> +{
> +	struct drm_i915_private *i915 = fpriv->dev_priv;
> +	struct set_proto_ctx_engines set = { .i915 = i915 };
> +	struct i915_context_param_engines __user *user =
> +		u64_to_user_ptr(args->value);
> +	unsigned int n;
> +	u64 extensions;
> +	int err;
> +
> +	if (!args->size) {
> +		kfree(pc->user_engines);
> +		pc->num_user_engines = -1;

Is this case actually used by actual userspace, or just more stuff igt
loved to do?

If so more uapi to ditch, and check in an igt that it's rejected.

Plus standard !args->size handling here with appropriate drm_debug line
and all that.

> +		pc->user_engines = NULL;
> +		memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
> +		return 0;
> +	}
> +
> +	BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));

I frankly don't know what this is checking, but it also looks harmless.

> +	if (args->size < sizeof(*user) ||
> +	    !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> +		drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> +			args->size);
> +		return -EINVAL;
> +	}
> +
> +	set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> +	/* RING_MASK has no shift so we can use it directly here */
> +	if (set.num_engines > I915_EXEC_RING_MASK + 1)
> +		return -EINVAL;
> +
> +	set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
> +	if (!set.engines)
> +		return -ENOMEM;
> +
> +	for (n = 0; n < set.num_engines; n++) {
> +		struct i915_engine_class_instance ci;
> +		struct intel_engine_cs *engine;
> +
> +		if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> +			kfree(set.engines);
> +			return -EFAULT;
> +		}
> +
> +		memset(&set.engines[n], 0, sizeof(set.engines[n]));
> +
> +		if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> +		    ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
> +			continue;
> +
> +		engine = intel_engine_lookup_user(i915,
> +						  ci.engine_class,
> +						  ci.engine_instance);
> +		if (!engine) {
> +			drm_dbg(&i915->drm,
> +				"Invalid engine[%d]: { class:%d, instance:%d }\n",
> +				n, ci.engine_class, ci.engine_instance);
> +			kfree(set.engines);
> +			return -ENOENT;
> +		}
> +
> +		set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> +		set.engines[n].engine = engine;
> +	}
> +
> +	err = -EFAULT;
> +	if (!get_user(extensions, &user->extensions))
> +		err = i915_user_extensions(u64_to_user_ptr(extensions),
> +					   set_proto_ctx_engines_extensions,
> +					   ARRAY_SIZE(set_proto_ctx_engines_extensions),
> +					   &set);
> +	if (err) {
> +		kfree(set.engines);
> +		return err;
> +	}
> +
> +	kfree(pc->user_engines);

Both of these kfree potentially leak engines[].siblings. I think you need
to extract a proto_context_free_engines helper and use that 2x here and
once at the very top in proto_context_close().

> +	pc->num_user_engines = set.num_engines;
> +	pc->user_engines = set.engines;
> +
> +	return 0;
> +}
> +
> +static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
> +			      struct i915_gem_proto_context *pc,
> +			      struct drm_i915_gem_context_param *args)
> +{
> +	struct drm_i915_private *i915 = fpriv->dev_priv;
> +	struct drm_i915_gem_context_param_sseu user_sseu;
> +	struct intel_sseu *sseu;
> +	int ret;
> +
> +	if (args->size < sizeof(user_sseu))
> +		return -EINVAL;
> +
> +	if (!IS_GEN(i915, 11))
> +		return -ENODEV;
> +
> +	if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
> +			   sizeof(user_sseu)))
> +		return -EFAULT;
> +
> +	if (user_sseu.rsvd)
> +		return -EINVAL;
> +
> +	if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
> +		return -EINVAL;
> +
> +	if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
> +		return -EINVAL;
> +
> +	if (pc->num_user_engines >= 0) {
> +		int idx = user_sseu.engine.engine_instance;
> +		struct i915_gem_proto_engine *pe;
> +
> +		if (idx >= pc->num_user_engines)
> +			return -EINVAL;
> +
> +		pe = &pc->user_engines[idx];
> +
> +		/* Only render engine supports RPCS configuration. */
> +		if (pe->engine->class != RENDER_CLASS)
> +			return -EINVAL;
> +
> +		sseu = &pe->sseu;
> +	} else {
> +		/* Only render engine supports RPCS configuration. */
> +		if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
> +			return -EINVAL;
> +
> +		/* There is only one render engine */
> +		if (user_sseu.engine.engine_instance != 0)
> +			return -EINVAL;
> +
> +		sseu = &pc->legacy_rcs_sseu;
> +	}

I think this faithfully rebuilds the convoluted and I think largely
accidental semantics of SSEU for all combinations of ordering against
set_engines.

Maybe add a commit message note about this particular kind of fun here. I
don't think a code comment is warranted since I don't think I've seen a
userspace rely on how sseu interacts with set_engines


> +
> +	ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
> +	if (ret)
> +		return ret;
> +
> +	args->size = sizeof(user_sseu);
> +
> +	return 0;
> +}
> +
> +static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
> +			       struct i915_gem_proto_context *pc,
> +			       struct drm_i915_gem_context_param *args)
> +{
> +	int ret = 0;
> +
> +	switch (args->param) {
> +	case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
> +		if (args->size)
> +			ret = -EINVAL;
> +		else if (args->value)
> +			__set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> +		else
> +			__clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);

Open code please and double check I caught them all ...

> +		break;
> +
> +	case I915_CONTEXT_PARAM_BANNABLE:
> +		if (args->size)
> +			ret = -EINVAL;
> +		else if (!capable(CAP_SYS_ADMIN) && !args->value)
> +			ret = -EPERM;
> +		else if (args->value)
> +			__set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> +		else
> +			__clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> +		break;
> +
> +	case I915_CONTEXT_PARAM_RECOVERABLE:
> +		if (args->size)
> +			ret = -EINVAL;
> +		else if (args->value)
> +			__set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> +		else
> +			__clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> +		break;
> +
> +	case I915_CONTEXT_PARAM_PRIORITY:
> +		ret = validate_priority(fpriv->dev_priv, args);
> +		if (!ret)
> +			pc->sched.priority = args->value;
> +		break;
> +
> +	case I915_CONTEXT_PARAM_SSEU:
> +		ret = set_proto_ctx_sseu(fpriv, pc, args);
> +		break;
> +
> +	case I915_CONTEXT_PARAM_VM:
> +		ret = set_proto_ctx_vm(fpriv, pc, args);
> +		break;
> +
> +	case I915_CONTEXT_PARAM_ENGINES:
> +		ret = set_proto_ctx_engines(fpriv, pc, args);
> +		break;
> +
> +	case I915_CONTEXT_PARAM_PERSISTENCE:
> +		if (args->size)
> +			ret = -EINVAL;
> +		else if (args->value)
> +			__set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> +		else
> +			__clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);

I think we have a nice mess here. You created this
proto_context_set_persistence helper, but don't use it here. Oversight?

Aside from the validation fun around persistence, but that's better
discussed in another patch I think.

> +		break;
> +
> +	case I915_CONTEXT_PARAM_NO_ZEROMAP:
> +	case I915_CONTEXT_PARAM_BAN_PERIOD:
> +	case I915_CONTEXT_PARAM_RINGSIZE:
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
>  static struct i915_address_space *
>  context_get_vm_rcu(struct i915_gem_context *ctx)
>  {
> @@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
>  	return err;
>  }
>  
> +static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
> +					     unsigned int num_engines,
> +					     struct i915_gem_proto_engine *pe)
> +{
> +	struct i915_gem_engines *e, *err;
> +	unsigned int n;
> +
> +	e = alloc_engines(num_engines);
> +	for (n = 0; n < num_engines; n++) {
> +		struct intel_context *ce;
> +		int ret;
> +
> +		switch (pe[n].type) {
> +		case I915_GEM_ENGINE_TYPE_PHYSICAL:
> +			ce = intel_context_create(pe[n].engine);
> +			break;
> +
> +		case I915_GEM_ENGINE_TYPE_BALANCED:
> +			ce = intel_execlists_create_virtual(pe[n].siblings,
> +							    pe[n].num_siblings);
> +			break;
> +
> +		case I915_GEM_ENGINE_TYPE_INVALID:
> +		default:
> +			GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
> +			continue;
> +		}
> +
> +		if (IS_ERR(ce)) {
> +			err = ERR_CAST(ce);
> +			goto free_engines;
> +		}
> +
> +		e->engines[n] = ce;
> +
> +		ret = intel_context_set_gem(ce, ctx, pe->sseu);
> +		if (ret) {
> +			err = ERR_PTR(ret);
> +			goto free_engines;
> +		}
> +	}
> +	e->num_engines = num_engines;
> +
> +	return e;
> +
> +free_engines:
> +	free_engines(e);
> +	return err;
> +}
> +
>  void i915_gem_context_release(struct kref *ref)
>  {
>  	struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
> @@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
>  {
>  	struct i915_gem_context *ctx;
>  	struct i915_gem_engines *e;
> -	struct intel_sseu null_sseu = {};
>  	int err;
>  	int i;
>  
> @@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
>  	INIT_LIST_HEAD(&ctx->stale.engines);
>  
>  	mutex_init(&ctx->engines_mutex);
> -	e = default_engines(ctx, null_sseu);
> +	e = default_engines(ctx, pc->legacy_rcs_sseu);
>  	if (IS_ERR(e)) {
>  		err = PTR_ERR(e);
>  		goto err_free;
> @@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
>  		mutex_unlock(&ctx->mutex);
>  	}
>  
> +	if (pc->num_user_engines >= 0) {
> +		struct i915_gem_engines *engines;
> +
> +		engines = user_engines(ctx, pc->num_user_engines,
> +				       pc->user_engines);
> +		if (IS_ERR(engines)) {
> +			context_close(ctx);
> +			return ERR_CAST(engines);
> +		}
> +
> +		mutex_lock(&ctx->engines_mutex);
> +		i915_gem_context_set_user_engines(ctx);
> +		engines = rcu_replace_pointer(ctx->engines, engines, 1);
> +		mutex_unlock(&ctx->engines_mutex);

More locking code to ditch I guess.

> +
> +		free_engines(engines);

Also I guess we shouldn't first create the legacy engines for this case?

> +	}
> +
>  	if (pc->single_timeline) {
>  		ret = drm_syncobj_create(&ctx->syncobj,
>  					 DRM_SYNCOBJ_CREATE_SIGNALED,
> @@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>  }
>  
>  struct create_ext {
> -	struct i915_gem_context *ctx;
> +	struct i915_gem_proto_context *pc;
>  	struct drm_i915_file_private *fpriv;
>  };
>  
> @@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
>  	if (local.param.ctx_id)
>  		return -EINVAL;
>  
> -	return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> +	return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
>  }
>  
>  static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> @@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  {
>  	struct drm_i915_private *i915 = to_i915(dev);
>  	struct drm_i915_gem_context_create_ext *args = data;
> -	struct i915_gem_proto_context *pc;
> +	struct i915_gem_context *ctx;
>  	struct create_ext ext_data;
>  	int ret;
>  	u32 id;
> @@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  		return -EIO;
>  	}
>  
> -	pc = proto_context_create(i915, args->flags);
> -	if (IS_ERR(pc))
> -		return PTR_ERR(pc);
> -
> -	ext_data.ctx = i915_gem_create_context(i915, pc);
> -	proto_context_close(pc);
> -	if (IS_ERR(ext_data.ctx))
> -		return PTR_ERR(ext_data.ctx);
> +	ext_data.pc = proto_context_create(i915, args->flags);
> +	if (IS_ERR(ext_data.pc))
> +		return PTR_ERR(ext_data.pc);
>  
>  	if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
>  		ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
>  					   create_extensions,
>  					   ARRAY_SIZE(create_extensions),
>  					   &ext_data);
> -		if (ret)
> -			goto err_ctx;
> +		if (ret) {
> +			proto_context_close(ext_data.pc);
> +			return ret;
> +		}
>  	}
>  
> -	ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
> +	ctx = i915_gem_create_context(i915, ext_data.pc);
> +	proto_context_close(ext_data.pc);
> +	if (IS_ERR(ctx))
> +		return PTR_ERR(ctx);
> +
> +	ret = gem_context_register(ctx, ext_data.fpriv, &id);
>  	if (ret < 0)
>  		goto err_ctx;
>  
> @@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  	return 0;
>  
>  err_ctx:
> -	context_close(ext_data.ctx);
> +	context_close(ctx);
>  	return ret;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index 0bf337b6d89ac..2ac341f805c8f 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
>  	const struct i915_gem_engines *engines;
>  };
>  
> +/**
> + * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
> + */
> +enum i915_gem_engine_type {
> +	/** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
> +	I915_GEM_ENGINE_TYPE_INVALID = 0,
> +
> +	/** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
> +	I915_GEM_ENGINE_TYPE_PHYSICAL,
> +
> +	/** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
> +	I915_GEM_ENGINE_TYPE_BALANCED,
> +};
> +
> +/**
> + * struct i915_gem_proto_engine - prototype engine
> + *
> + * This struct describes an engine that a context may contain.  Engines
> + * have three types:
> + *
> + *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
> + *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
> + *    use them by the user results in -EINVAL.  They are also useful during
> + *    proto-context construction because the client may create invalid
> + *    engines and then set them up later as bonded engines.
> + *
> + *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
> + *    i915_gem_proto_engine::engine.
> + *
> + *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
> + *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
> + */
> +struct i915_gem_proto_engine {
> +	/** @type: Type of this engine */
> +	enum i915_gem_engine_type type;
> +
> +	/** @engine: Engine, for physical */
> +	struct intel_engine_cs *engine;
> +
> +	/** @num_siblings: Number of balanced siblings */
> +	unsigned int num_siblings;
> +
> +	/** @siblings: Balanced siblings */
> +	struct intel_engine_cs **siblings;
> +
> +	/** @sseu: Client-set SSEU parameters */
> +	struct intel_sseu sseu;
> +};
> +
>  /**
>   * struct i915_gem_proto_context - prototype context
>   *
> @@ -84,6 +133,15 @@ struct i915_gem_proto_context {
>  	/** @sched: See i915_gem_context::sched */
>  	struct i915_sched_attr sched;
>  
> +	/** @num_user_engines: Number of user-specified engines or -1 */
> +	int num_user_engines;
> +
> +	/** @user_engines: User-specified engines */
> +	struct i915_gem_proto_engine *user_engines;
> +
> +	/** @sseu: Client-set SSEU parameters for the legacy RCS */
> +	struct intel_sseu legacy_rcs_sseu;
> +
>  	/** @single_timeline: See See i915_gem_context::syncobj */
>  	bool single_timeline;
>  };
> -- 
> 2.31.1

Man is this all nasty. Since I don't want to re-review the entire pile,
assuming we figure out solutions to all the real issues I've raised (and
not the snarky bikesheds) this is

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 22/27] drm/i915/gem: Delay context creation
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04 20:53     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 20:53 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:43AM -0500, Jason Ekstrand wrote:
> The current context uAPI allows for two methods of setting context
> parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
> former is allowed to be called at any time while the later happens as
> part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
> settable via the other.  While some params are fairly simple and setting
> them on a live context is harmless such the context priority, others are
> far trickier such as the VM or the set of engines.  In order to swap out
> the VM, for instance, we have to delay until all current in-flight work
> is complete, swap in the new VM, and then continue.  This leads to a
> plethora of potential race conditions we'd really rather avoid.
> 
> In previous patches, we added a i915_gem_proto_context struct which is
> capable of storing and tracking all such create parameters.  This commit
> delays the creation of the actual context until after the client is done
> configuring it with SET_CONTEXT_PARAM.  From the perspective of the
> client, it has the same u32 context ID the whole time.  From the
> perspective of i915, however, it's an i915_gem_proto_context right up
> until the point where we attempt to do something which the proto-context
> can't handle at which point the real context gets created.
> 
> This is accomplished via a little xarray dance.  When GEM_CONTEXT_CREATE
> is called, we create a proto-context, reserve a slot in context_xa but
> leave it NULL, the proto-context in the corresponding slot in
> proto_context_xa.  Then, whenever we go to look up a context, we first
> check context_xa.  If it's there, we return the i915_gem_context and
> we're done.  If it's not, we look in proto_context_xa and, if we find it
> there, we create the actual context and kill the proto-context.
> 
> In order for this dance to work properly, everything which ever touches
> a proto-context is guarded by drm_i915_file_private::proto_context_lock,
> including context creation.  Yes, this means context creation now takes
> a giant global lock but it can't really be helped and that should never
> be on any driver's fast-path anyway.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 211 ++++++++++++++----
>  drivers/gpu/drm/i915/gem/i915_gem_context.h   |   3 +
>  .../gpu/drm/i915/gem/i915_gem_context_types.h |  54 +++++
>  .../gpu/drm/i915/gem/selftests/mock_context.c |   5 +-
>  drivers/gpu/drm/i915/i915_drv.h               |  24 +-
>  5 files changed, 239 insertions(+), 58 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 06d413eef01a3..f0e7ce6b979b4 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -292,6 +292,42 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
>  	return err;
>  }
>  
> +static int proto_context_register_locked(struct drm_i915_file_private *fpriv,
> +					 struct i915_gem_proto_context *pc,
> +					 u32 *id)
> +{
> +	int ret;
> +	void *old;
> +
> +	lockdep_assert_held(&fpriv->proto_context_lock);
> +
> +	ret = xa_alloc(&fpriv->context_xa, id, NULL, xa_limit_32b, GFP_KERNEL);
> +	if (ret)
> +		return ret;
> +
> +	old = xa_store(&fpriv->proto_context_xa, *id, pc, GFP_KERNEL);
> +	if (xa_is_err(old)) {
> +		xa_erase(&fpriv->context_xa, *id);
> +		return xa_err(old);
> +	}
> +	GEM_BUG_ON(old);

A bit brutal, since worst case we just leaked something. I'd only go with
WARN_ON. This isn't userspace, dying should be optional to make debugging
easier (paranoid people reboot the machine on both anyway).

> +
> +	return 0;
> +}
> +
> +static int proto_context_register(struct drm_i915_file_private *fpriv,
> +				  struct i915_gem_proto_context *pc,
> +				  u32 *id)
> +{
> +	int ret;
> +
> +	mutex_lock(&fpriv->proto_context_lock);
> +	ret = proto_context_register_locked(fpriv, pc, id);
> +	mutex_unlock(&fpriv->proto_context_lock);
> +
> +	return ret;
> +}
> +
>  static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
>  			    struct i915_gem_proto_context *pc,
>  			    const struct drm_i915_gem_context_param *args)
> @@ -1452,12 +1488,12 @@ void i915_gem_init__contexts(struct drm_i915_private *i915)
>  	init_contexts(&i915->gem.contexts);
>  }
>  
> -static int gem_context_register(struct i915_gem_context *ctx,
> -				struct drm_i915_file_private *fpriv,
> -				u32 *id)
> +static void gem_context_register(struct i915_gem_context *ctx,
> +				 struct drm_i915_file_private *fpriv,
> +				 u32 id)
>  {
>  	struct drm_i915_private *i915 = ctx->i915;
> -	int ret;
> +	void *old;
>  
>  	ctx->file_priv = fpriv;
>  
> @@ -1466,19 +1502,12 @@ static int gem_context_register(struct i915_gem_context *ctx,
>  		 current->comm, pid_nr(ctx->pid));
>  
>  	/* And finally expose ourselves to userspace via the idr */
> -	ret = xa_alloc(&fpriv->context_xa, id, ctx, xa_limit_32b, GFP_KERNEL);
> -	if (ret)
> -		goto err_pid;
> +	old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL);
> +	GEM_BUG_ON(old);

Same here about WARN_ON preferred.

Also this can actually happen if you race and don't hold
proto_context_lock sufficiently, so another lockdep_assert_held for this
function would be good I think.

Otoh if that means too much fake lock taking in like context_open then
maybe let's not do the lockdep_assert_held but instead perhaps a comment?
Or maybe do the lockdep_assert_held for id != 0 only.


>  
>  	spin_lock(&i915->gem.contexts.lock);
>  	list_add_tail(&ctx->link, &i915->gem.contexts.list);
>  	spin_unlock(&i915->gem.contexts.lock);
> -
> -	return 0;
> -
> -err_pid:
> -	put_pid(fetch_and_zero(&ctx->pid));
> -	return ret;
>  }
>  
>  int i915_gem_context_open(struct drm_i915_private *i915,
> @@ -1488,9 +1517,12 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>  	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
>  	int err;
> -	u32 id;
>  
> -	xa_init_flags(&file_priv->context_xa, XA_FLAGS_ALLOC);
> +	mutex_init(&file_priv->proto_context_lock);
> +	xa_init_flags(&file_priv->proto_context_xa, XA_FLAGS_ALLOC);
> +
> +	/* 0 reserved for the default context */
> +	xa_init_flags(&file_priv->context_xa, XA_FLAGS_ALLOC1);
>  
>  	/* 0 reserved for invalid/unassigned ppgtt */
>  	xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
> @@ -1508,28 +1540,31 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>  		goto err;
>  	}
>  
> -	err = gem_context_register(ctx, file_priv, &id);
> -	if (err < 0)
> -		goto err_ctx;
> +	gem_context_register(ctx, file_priv, 0);
>  
> -	GEM_BUG_ON(id);
>  	return 0;
>  
> -err_ctx:
> -	context_close(ctx);
>  err:
>  	xa_destroy(&file_priv->vm_xa);
>  	xa_destroy(&file_priv->context_xa);
> +	xa_destroy(&file_priv->proto_context_xa);
> +	mutex_destroy(&file_priv->proto_context_lock);
>  	return err;
>  }
>  
>  void i915_gem_context_close(struct drm_file *file)
>  {
>  	struct drm_i915_file_private *file_priv = file->driver_priv;
> +	struct i915_gem_proto_context *pc;
>  	struct i915_address_space *vm;
>  	struct i915_gem_context *ctx;
>  	unsigned long idx;
>  
> +	xa_for_each(&file_priv->proto_context_xa, idx, pc)
> +		proto_context_close(pc);
> +	xa_destroy(&file_priv->proto_context_xa);
> +	mutex_destroy(&file_priv->proto_context_lock);
> +
>  	xa_for_each(&file_priv->context_xa, idx, ctx)
>  		context_close(ctx);
>  	xa_destroy(&file_priv->context_xa);
> @@ -2490,12 +2525,73 @@ static bool client_is_banned(struct drm_i915_file_private *file_priv)
>  	return atomic_read(&file_priv->ban_score) >= I915_CLIENT_SCORE_BANNED;
>  }
>  
> +static inline struct i915_gem_context *
> +__context_lookup(struct drm_i915_file_private *file_priv, u32 id)
> +{
> +	struct i915_gem_context *ctx;
> +
> +	rcu_read_lock();
> +	ctx = xa_load(&file_priv->context_xa, id);
> +	if (ctx && !kref_get_unless_zero(&ctx->ref))
> +		ctx = NULL;
> +	rcu_read_unlock();
> +
> +	return ctx;
> +}
> +
> +struct i915_gem_context *
> +lazy_create_context_locked(struct drm_i915_file_private *file_priv,
> +			   struct i915_gem_proto_context *pc, u32 id)
> +{
> +	struct i915_gem_context *ctx;
> +	void *old;
> +
> +	lockdep_assert_held(&file_priv->proto_context_lock);
> +
> +	ctx = i915_gem_create_context(file_priv->dev_priv, pc);
> +	if (IS_ERR(ctx))
> +		return ctx;
> +
> +	gem_context_register(ctx, file_priv, id);
> +
> +	old = xa_erase(&file_priv->proto_context_xa, id);
> +	GEM_BUG_ON(old != pc);
> +	proto_context_close(pc);
> +
> +	/* One for the xarray and one for the caller */
> +	return i915_gem_context_get(ctx);
> +}
> +
> +struct i915_gem_context *
> +i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
> +{
> +	struct i915_gem_proto_context *pc;
> +	struct i915_gem_context *ctx;
> +
> +	ctx = __context_lookup(file_priv, id);
> +	if (ctx)
> +		return ctx;
> +
> +	mutex_lock(&file_priv->proto_context_lock);
> +	/* Try one more time under the lock */
> +	ctx = __context_lookup(file_priv, id);
> +	if (!ctx) {
> +		pc = xa_load(&file_priv->proto_context_xa, id);
> +		if (!pc)
> +			ctx = ERR_PTR(-ENOENT);
> +		else
> +			ctx = lazy_create_context_locked(file_priv, pc, id);
> +	}
> +	mutex_unlock(&file_priv->proto_context_lock);
> +
> +	return ctx;
> +}
> +
>  int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  				  struct drm_file *file)
>  {
>  	struct drm_i915_private *i915 = to_i915(dev);
>  	struct drm_i915_gem_context_create_ext *args = data;
> -	struct i915_gem_context *ctx;
>  	struct create_ext ext_data;
>  	int ret;
>  	u32 id;
> @@ -2527,28 +2623,21 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  					   create_extensions,
>  					   ARRAY_SIZE(create_extensions),
>  					   &ext_data);
> -		if (ret) {
> -			proto_context_close(ext_data.pc);
> -			return ret;
> -		}
> +		if (ret)
> +			goto err_pc;
>  	}
>  
> -	ctx = i915_gem_create_context(i915, ext_data.pc);
> -	proto_context_close(ext_data.pc);
> -	if (IS_ERR(ctx))
> -		return PTR_ERR(ctx);
> -
> -	ret = gem_context_register(ctx, ext_data.fpriv, &id);
> +	ret = proto_context_register(ext_data.fpriv, ext_data.pc, &id);
>  	if (ret < 0)
> -		goto err_ctx;
> +		goto err_pc;
>  
>  	args->ctx_id = id;
>  	drm_dbg(&i915->drm, "HW context %d created\n", args->ctx_id);
>  
>  	return 0;
>  
> -err_ctx:
> -	context_close(ctx);
> +err_pc:
> +	proto_context_close(ext_data.pc);
>  	return ret;
>  }
>  
> @@ -2557,6 +2646,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
>  {
>  	struct drm_i915_gem_context_destroy *args = data;
>  	struct drm_i915_file_private *file_priv = file->driver_priv;
> +	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
>  
>  	if (args->pad != 0)
> @@ -2565,11 +2655,21 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
>  	if (!args->ctx_id)
>  		return -ENOENT;
>  
> +	mutex_lock(&file_priv->proto_context_lock);
>  	ctx = xa_erase(&file_priv->context_xa, args->ctx_id);
> -	if (!ctx)
> +	pc = xa_erase(&file_priv->proto_context_xa, args->ctx_id);
> +	mutex_unlock(&file_priv->proto_context_lock);
> +
> +	if (!ctx && !pc)
>  		return -ENOENT;
> +	GEM_WARN_ON(ctx && pc);
> +
> +	if (pc)
> +		proto_context_close(pc);
> +
> +	if (ctx)
> +		context_close(ctx);
>  
> -	context_close(ctx);
>  	return 0;
>  }
>  
> @@ -2702,16 +2802,41 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
>  {
>  	struct drm_i915_file_private *file_priv = file->driver_priv;
>  	struct drm_i915_gem_context_param *args = data;
> +	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
> -	int ret;
> +	int ret = 0;
>  
> -	ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
> -	if (IS_ERR(ctx))
> -		return PTR_ERR(ctx);
> +	ctx = __context_lookup(file_priv, args->ctx_id);
> +	if (ctx)
> +		goto set_ctx_param;
>  
> -	ret = ctx_setparam(file_priv, ctx, args);
> +	mutex_lock(&file_priv->proto_context_lock);
> +	ctx = __context_lookup(file_priv, args->ctx_id);
> +	if (ctx)
> +		goto unlock;
> +
> +	pc = xa_load(&file_priv->proto_context_xa, args->ctx_id);
> +	if (!pc) {
> +		ret = -ENOENT;
> +		goto unlock;
> +	}
> +
> +	/* FIXME: We should consider disallowing SET_CONTEXT_PARAM for most
> +	 * things on future platforms.  Clients should be using
> +	 * CONTEXT_CREATE_EXT_PARAM instead.
> +	 */
> +	ret = set_proto_ctx_param(file_priv, pc, args);
> +
> +unlock:
> +	mutex_unlock(&file_priv->proto_context_lock);
> +
> +set_ctx_param:
> +	if (!ret && ctx)
> +		ret = ctx_setparam(file_priv, ctx, args);
> +
> +	if (ctx)
> +		i915_gem_context_put(ctx);
>  
> -	i915_gem_context_put(ctx);
>  	return ret;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.h b/drivers/gpu/drm/i915/gem/i915_gem_context.h
> index b5c908f3f4f22..20411db84914a 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.h
> @@ -133,6 +133,9 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
>  int i915_gem_context_reset_stats_ioctl(struct drm_device *dev, void *data,
>  				       struct drm_file *file);
>  
> +struct i915_gem_context *
> +i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id);
> +
>  static inline struct i915_gem_context *
>  i915_gem_context_get(struct i915_gem_context *ctx)
>  {
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index 2ac341f805c8f..b673061f4f5ba 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -122,6 +122,60 @@ struct i915_gem_proto_engine {
>   * an i915_gem_context.  This is used to gather parameters provided either
>   * through creation flags or via SET_CONTEXT_PARAM so that, when we create
>   * the final i915_gem_context, those parameters can be immutable.
> + *
> + * The context uAPI allows for two methods of setting context parameters:
> + * SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The former is
> + * allowed to be called at any time while the later happens as part of
> + * GEM_CONTEXT_CREATE.  When these were initially added, Currently,

							    ^ lowercase

> + * everything settable via one is settable via the other.  While some
> + * params are fairly simple and setting them on a live context is harmless
> + * such the context priority, others are far trickier such as the VM or the

      such _as_ 

> + * set of engines.  To avoid some truly nasty race conditions, we don't
> + * allow setting the VM or the set of engines on live contexts.
> + *
> + * The way we dealt with this without breaking older userspace that sets
> + * the VM or engine set via SET_CONTEXT_PARAM is to delay the creation of
> + * the actual context until after the client is done configuring it with
> + * SET_CONTEXT_PARAM.  From the perspective of the client, it has the same
> + * u32 context ID the whole time.  From the perspective of i915, however,
> + * it's an i915_gem_proto_context right up until the point where we attempt
> + * to do something which the proto-context can't handle at which point the
> + * real context gets created.
> + *
> + * This is accomplished via a little xarray dance.  When GEM_CONTEXT_CREATE
> + * is called, we create a proto-context, reserve a slot in context_xa but
> + * leave it NULL, the proto-context in the corresponding slot in
> + * proto_context_xa.  Then, whenever we go to look up a context, we first
> + * check context_xa.  If it's there, we return the i915_gem_context and
> + * we're done.  If it's not, we look in proto_context_xa and, if we find it
> + * there, we create the actual context and kill the proto-context.

Maybe stuff this into the kerneldoc for the lookup function and just put a
pointer to that in here instead? It hyperlinks in the html output, and in
the text you can follow with cscope or similar. And it's closer to where
the future devs probably need that information.

Minimally at least reference the lookup function here for that link
goodness :-)

> + *
> + * At the time we made this change (April, 2021), we did a fairly complete

s/fairly//

We might have screwed up, but we don't aim to break uapi with
intentionally sloppy work :-P

> + * audit of existing userspace to ensure this wouldn't break anything:
> + *
> + *  - Mesa/i965 didn't use the engines or VM APIs at all
> + *
> + *  - Mesa/ANV used the engines API but via CONTEXT_CREATE_EXT_SETPARAM and
> + *    didn't use the VM API.
> + *
> + *  - Mesa/iris didn't use the engines or VM APIs at all
> + *
> + *  - The open-source compute-runtime didn't yet use the engines API but
> + *    did use the VM API via SET_CONTEXT_PARAM.  However, CONTEXT_SETPARAM
> + *    was always the second ioctl on that context, immediately following
> + *    GEM_CONTEXT_CREATE.
> + *
> + *  - The media driver sets engines and bonding/balancing via
> + *    SET_CONTEXT_PARAM.  However, CONTEXT_SETPARAM to set the VM was
> + *    always the second ioctl on that context, immediately following
> + *    GEM_CONTEXT_CREATE and setting engines immediately followed that.
> + *
> + * In order for this dance to work properly, any modification to an
> + * i915_gem_proto_context that is exposed to the client via
> + * drm_i915_file_private::proto_context_xa must be guarded by
> + * drm_i915_file_private::proto_context_lock.  The exception is when a
> + * proto-context has not yet been exposed such as when handling
> + * CONTEXT_CREATE_SET_PARAM during GEM_CONTEXT_CREATE.
>   */
>  struct i915_gem_proto_context {
>  	/** @vm: See i915_gem_context::vm */
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index cbeefd060e97b..61aaac4a334cf 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -81,6 +81,7 @@ void mock_init_contexts(struct drm_i915_private *i915)
>  struct i915_gem_context *
>  live_context(struct drm_i915_private *i915, struct file *file)
>  {
> +	struct drm_i915_file_private *fpriv = to_drm_file(file)->driver_priv;
>  	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
>  	int err;
> @@ -97,10 +98,12 @@ live_context(struct drm_i915_private *i915, struct file *file)
>  
>  	i915_gem_context_set_no_error_capture(ctx);
>  
> -	err = gem_context_register(ctx, to_drm_file(file)->driver_priv, &id);
> +	err = xa_alloc(&fpriv->context_xa, &id, NULL, xa_limit_32b, GFP_KERNEL);
>  	if (err < 0)
>  		goto err_ctx;
>  
> +	gem_context_register(ctx, fpriv, id);
> +
>  	return ctx;
>  
>  err_ctx:
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 004ed0e59c999..2b323b986dbab 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -200,6 +200,16 @@ struct drm_i915_file_private {
>  		struct rcu_head rcu;
>  	};
>  
> +	/** @proto_context_lock: Guards all i915_gem_proto_context operations

For multi-line kerneldoc we generally put a newline after /**\n I didn't
even know this parses :-) The single-line variant is kinda special.

> +	 *
> +	 * See i915_gem_proto_context.
> +	 */
> +	struct mutex proto_context_lock;
> +
> +	/** @proto_context_xa: xarray of i915_gem_proto_context */
> +	struct xarray proto_context_xa;
> +
> +	/** @context_xa: xarray of fully created i915_gem_context */
>  	struct xarray context_xa;
>  	struct xarray vm_xa;
>  
> @@ -1840,20 +1850,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
>  
>  struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags);
>  
> -static inline struct i915_gem_context *
> -i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
> -{
> -	struct i915_gem_context *ctx;
> -
> -	rcu_read_lock();
> -	ctx = xa_load(&file_priv->context_xa, id);
> -	if (ctx && !kref_get_unless_zero(&ctx->ref))
> -		ctx = NULL;
> -	rcu_read_unlock();
> -
> -	return ctx ? ctx : ERR_PTR(-ENOENT);
> -}
> -
>  /* i915_gem_evict.c */
>  int __must_check i915_gem_evict_something(struct i915_address_space *vm,
>  					  u64 min_size, u64 alignment,

All I could find was bikesheds to bring to this party.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 22/27] drm/i915/gem: Delay context creation
@ 2021-05-04 20:53     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 20:53 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:43AM -0500, Jason Ekstrand wrote:
> The current context uAPI allows for two methods of setting context
> parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
> former is allowed to be called at any time while the later happens as
> part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
> settable via the other.  While some params are fairly simple and setting
> them on a live context is harmless such the context priority, others are
> far trickier such as the VM or the set of engines.  In order to swap out
> the VM, for instance, we have to delay until all current in-flight work
> is complete, swap in the new VM, and then continue.  This leads to a
> plethora of potential race conditions we'd really rather avoid.
> 
> In previous patches, we added a i915_gem_proto_context struct which is
> capable of storing and tracking all such create parameters.  This commit
> delays the creation of the actual context until after the client is done
> configuring it with SET_CONTEXT_PARAM.  From the perspective of the
> client, it has the same u32 context ID the whole time.  From the
> perspective of i915, however, it's an i915_gem_proto_context right up
> until the point where we attempt to do something which the proto-context
> can't handle at which point the real context gets created.
> 
> This is accomplished via a little xarray dance.  When GEM_CONTEXT_CREATE
> is called, we create a proto-context, reserve a slot in context_xa but
> leave it NULL, the proto-context in the corresponding slot in
> proto_context_xa.  Then, whenever we go to look up a context, we first
> check context_xa.  If it's there, we return the i915_gem_context and
> we're done.  If it's not, we look in proto_context_xa and, if we find it
> there, we create the actual context and kill the proto-context.
> 
> In order for this dance to work properly, everything which ever touches
> a proto-context is guarded by drm_i915_file_private::proto_context_lock,
> including context creation.  Yes, this means context creation now takes
> a giant global lock but it can't really be helped and that should never
> be on any driver's fast-path anyway.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 211 ++++++++++++++----
>  drivers/gpu/drm/i915/gem/i915_gem_context.h   |   3 +
>  .../gpu/drm/i915/gem/i915_gem_context_types.h |  54 +++++
>  .../gpu/drm/i915/gem/selftests/mock_context.c |   5 +-
>  drivers/gpu/drm/i915/i915_drv.h               |  24 +-
>  5 files changed, 239 insertions(+), 58 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 06d413eef01a3..f0e7ce6b979b4 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -292,6 +292,42 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
>  	return err;
>  }
>  
> +static int proto_context_register_locked(struct drm_i915_file_private *fpriv,
> +					 struct i915_gem_proto_context *pc,
> +					 u32 *id)
> +{
> +	int ret;
> +	void *old;
> +
> +	lockdep_assert_held(&fpriv->proto_context_lock);
> +
> +	ret = xa_alloc(&fpriv->context_xa, id, NULL, xa_limit_32b, GFP_KERNEL);
> +	if (ret)
> +		return ret;
> +
> +	old = xa_store(&fpriv->proto_context_xa, *id, pc, GFP_KERNEL);
> +	if (xa_is_err(old)) {
> +		xa_erase(&fpriv->context_xa, *id);
> +		return xa_err(old);
> +	}
> +	GEM_BUG_ON(old);

A bit brutal, since worst case we just leaked something. I'd only go with
WARN_ON. This isn't userspace, dying should be optional to make debugging
easier (paranoid people reboot the machine on both anyway).

> +
> +	return 0;
> +}
> +
> +static int proto_context_register(struct drm_i915_file_private *fpriv,
> +				  struct i915_gem_proto_context *pc,
> +				  u32 *id)
> +{
> +	int ret;
> +
> +	mutex_lock(&fpriv->proto_context_lock);
> +	ret = proto_context_register_locked(fpriv, pc, id);
> +	mutex_unlock(&fpriv->proto_context_lock);
> +
> +	return ret;
> +}
> +
>  static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
>  			    struct i915_gem_proto_context *pc,
>  			    const struct drm_i915_gem_context_param *args)
> @@ -1452,12 +1488,12 @@ void i915_gem_init__contexts(struct drm_i915_private *i915)
>  	init_contexts(&i915->gem.contexts);
>  }
>  
> -static int gem_context_register(struct i915_gem_context *ctx,
> -				struct drm_i915_file_private *fpriv,
> -				u32 *id)
> +static void gem_context_register(struct i915_gem_context *ctx,
> +				 struct drm_i915_file_private *fpriv,
> +				 u32 id)
>  {
>  	struct drm_i915_private *i915 = ctx->i915;
> -	int ret;
> +	void *old;
>  
>  	ctx->file_priv = fpriv;
>  
> @@ -1466,19 +1502,12 @@ static int gem_context_register(struct i915_gem_context *ctx,
>  		 current->comm, pid_nr(ctx->pid));
>  
>  	/* And finally expose ourselves to userspace via the idr */
> -	ret = xa_alloc(&fpriv->context_xa, id, ctx, xa_limit_32b, GFP_KERNEL);
> -	if (ret)
> -		goto err_pid;
> +	old = xa_store(&fpriv->context_xa, id, ctx, GFP_KERNEL);
> +	GEM_BUG_ON(old);

Same here about WARN_ON preferred.

Also this can actually happen if you race and don't hold
proto_context_lock sufficiently, so another lockdep_assert_held for this
function would be good I think.

Otoh if that means too much fake lock taking in like context_open then
maybe let's not do the lockdep_assert_held but instead perhaps a comment?
Or maybe do the lockdep_assert_held for id != 0 only.


>  
>  	spin_lock(&i915->gem.contexts.lock);
>  	list_add_tail(&ctx->link, &i915->gem.contexts.list);
>  	spin_unlock(&i915->gem.contexts.lock);
> -
> -	return 0;
> -
> -err_pid:
> -	put_pid(fetch_and_zero(&ctx->pid));
> -	return ret;
>  }
>  
>  int i915_gem_context_open(struct drm_i915_private *i915,
> @@ -1488,9 +1517,12 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>  	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
>  	int err;
> -	u32 id;
>  
> -	xa_init_flags(&file_priv->context_xa, XA_FLAGS_ALLOC);
> +	mutex_init(&file_priv->proto_context_lock);
> +	xa_init_flags(&file_priv->proto_context_xa, XA_FLAGS_ALLOC);
> +
> +	/* 0 reserved for the default context */
> +	xa_init_flags(&file_priv->context_xa, XA_FLAGS_ALLOC1);
>  
>  	/* 0 reserved for invalid/unassigned ppgtt */
>  	xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
> @@ -1508,28 +1540,31 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>  		goto err;
>  	}
>  
> -	err = gem_context_register(ctx, file_priv, &id);
> -	if (err < 0)
> -		goto err_ctx;
> +	gem_context_register(ctx, file_priv, 0);
>  
> -	GEM_BUG_ON(id);
>  	return 0;
>  
> -err_ctx:
> -	context_close(ctx);
>  err:
>  	xa_destroy(&file_priv->vm_xa);
>  	xa_destroy(&file_priv->context_xa);
> +	xa_destroy(&file_priv->proto_context_xa);
> +	mutex_destroy(&file_priv->proto_context_lock);
>  	return err;
>  }
>  
>  void i915_gem_context_close(struct drm_file *file)
>  {
>  	struct drm_i915_file_private *file_priv = file->driver_priv;
> +	struct i915_gem_proto_context *pc;
>  	struct i915_address_space *vm;
>  	struct i915_gem_context *ctx;
>  	unsigned long idx;
>  
> +	xa_for_each(&file_priv->proto_context_xa, idx, pc)
> +		proto_context_close(pc);
> +	xa_destroy(&file_priv->proto_context_xa);
> +	mutex_destroy(&file_priv->proto_context_lock);
> +
>  	xa_for_each(&file_priv->context_xa, idx, ctx)
>  		context_close(ctx);
>  	xa_destroy(&file_priv->context_xa);
> @@ -2490,12 +2525,73 @@ static bool client_is_banned(struct drm_i915_file_private *file_priv)
>  	return atomic_read(&file_priv->ban_score) >= I915_CLIENT_SCORE_BANNED;
>  }
>  
> +static inline struct i915_gem_context *
> +__context_lookup(struct drm_i915_file_private *file_priv, u32 id)
> +{
> +	struct i915_gem_context *ctx;
> +
> +	rcu_read_lock();
> +	ctx = xa_load(&file_priv->context_xa, id);
> +	if (ctx && !kref_get_unless_zero(&ctx->ref))
> +		ctx = NULL;
> +	rcu_read_unlock();
> +
> +	return ctx;
> +}
> +
> +struct i915_gem_context *
> +lazy_create_context_locked(struct drm_i915_file_private *file_priv,
> +			   struct i915_gem_proto_context *pc, u32 id)
> +{
> +	struct i915_gem_context *ctx;
> +	void *old;
> +
> +	lockdep_assert_held(&file_priv->proto_context_lock);
> +
> +	ctx = i915_gem_create_context(file_priv->dev_priv, pc);
> +	if (IS_ERR(ctx))
> +		return ctx;
> +
> +	gem_context_register(ctx, file_priv, id);
> +
> +	old = xa_erase(&file_priv->proto_context_xa, id);
> +	GEM_BUG_ON(old != pc);
> +	proto_context_close(pc);
> +
> +	/* One for the xarray and one for the caller */
> +	return i915_gem_context_get(ctx);
> +}
> +
> +struct i915_gem_context *
> +i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
> +{
> +	struct i915_gem_proto_context *pc;
> +	struct i915_gem_context *ctx;
> +
> +	ctx = __context_lookup(file_priv, id);
> +	if (ctx)
> +		return ctx;
> +
> +	mutex_lock(&file_priv->proto_context_lock);
> +	/* Try one more time under the lock */
> +	ctx = __context_lookup(file_priv, id);
> +	if (!ctx) {
> +		pc = xa_load(&file_priv->proto_context_xa, id);
> +		if (!pc)
> +			ctx = ERR_PTR(-ENOENT);
> +		else
> +			ctx = lazy_create_context_locked(file_priv, pc, id);
> +	}
> +	mutex_unlock(&file_priv->proto_context_lock);
> +
> +	return ctx;
> +}
> +
>  int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  				  struct drm_file *file)
>  {
>  	struct drm_i915_private *i915 = to_i915(dev);
>  	struct drm_i915_gem_context_create_ext *args = data;
> -	struct i915_gem_context *ctx;
>  	struct create_ext ext_data;
>  	int ret;
>  	u32 id;
> @@ -2527,28 +2623,21 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>  					   create_extensions,
>  					   ARRAY_SIZE(create_extensions),
>  					   &ext_data);
> -		if (ret) {
> -			proto_context_close(ext_data.pc);
> -			return ret;
> -		}
> +		if (ret)
> +			goto err_pc;
>  	}
>  
> -	ctx = i915_gem_create_context(i915, ext_data.pc);
> -	proto_context_close(ext_data.pc);
> -	if (IS_ERR(ctx))
> -		return PTR_ERR(ctx);
> -
> -	ret = gem_context_register(ctx, ext_data.fpriv, &id);
> +	ret = proto_context_register(ext_data.fpriv, ext_data.pc, &id);
>  	if (ret < 0)
> -		goto err_ctx;
> +		goto err_pc;
>  
>  	args->ctx_id = id;
>  	drm_dbg(&i915->drm, "HW context %d created\n", args->ctx_id);
>  
>  	return 0;
>  
> -err_ctx:
> -	context_close(ctx);
> +err_pc:
> +	proto_context_close(ext_data.pc);
>  	return ret;
>  }
>  
> @@ -2557,6 +2646,7 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
>  {
>  	struct drm_i915_gem_context_destroy *args = data;
>  	struct drm_i915_file_private *file_priv = file->driver_priv;
> +	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
>  
>  	if (args->pad != 0)
> @@ -2565,11 +2655,21 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
>  	if (!args->ctx_id)
>  		return -ENOENT;
>  
> +	mutex_lock(&file_priv->proto_context_lock);
>  	ctx = xa_erase(&file_priv->context_xa, args->ctx_id);
> -	if (!ctx)
> +	pc = xa_erase(&file_priv->proto_context_xa, args->ctx_id);
> +	mutex_unlock(&file_priv->proto_context_lock);
> +
> +	if (!ctx && !pc)
>  		return -ENOENT;
> +	GEM_WARN_ON(ctx && pc);
> +
> +	if (pc)
> +		proto_context_close(pc);
> +
> +	if (ctx)
> +		context_close(ctx);
>  
> -	context_close(ctx);
>  	return 0;
>  }
>  
> @@ -2702,16 +2802,41 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
>  {
>  	struct drm_i915_file_private *file_priv = file->driver_priv;
>  	struct drm_i915_gem_context_param *args = data;
> +	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
> -	int ret;
> +	int ret = 0;
>  
> -	ctx = i915_gem_context_lookup(file_priv, args->ctx_id);
> -	if (IS_ERR(ctx))
> -		return PTR_ERR(ctx);
> +	ctx = __context_lookup(file_priv, args->ctx_id);
> +	if (ctx)
> +		goto set_ctx_param;
>  
> -	ret = ctx_setparam(file_priv, ctx, args);
> +	mutex_lock(&file_priv->proto_context_lock);
> +	ctx = __context_lookup(file_priv, args->ctx_id);
> +	if (ctx)
> +		goto unlock;
> +
> +	pc = xa_load(&file_priv->proto_context_xa, args->ctx_id);
> +	if (!pc) {
> +		ret = -ENOENT;
> +		goto unlock;
> +	}
> +
> +	/* FIXME: We should consider disallowing SET_CONTEXT_PARAM for most
> +	 * things on future platforms.  Clients should be using
> +	 * CONTEXT_CREATE_EXT_PARAM instead.
> +	 */
> +	ret = set_proto_ctx_param(file_priv, pc, args);
> +
> +unlock:
> +	mutex_unlock(&file_priv->proto_context_lock);
> +
> +set_ctx_param:
> +	if (!ret && ctx)
> +		ret = ctx_setparam(file_priv, ctx, args);
> +
> +	if (ctx)
> +		i915_gem_context_put(ctx);
>  
> -	i915_gem_context_put(ctx);
>  	return ret;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.h b/drivers/gpu/drm/i915/gem/i915_gem_context.h
> index b5c908f3f4f22..20411db84914a 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.h
> @@ -133,6 +133,9 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
>  int i915_gem_context_reset_stats_ioctl(struct drm_device *dev, void *data,
>  				       struct drm_file *file);
>  
> +struct i915_gem_context *
> +i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id);
> +
>  static inline struct i915_gem_context *
>  i915_gem_context_get(struct i915_gem_context *ctx)
>  {
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index 2ac341f805c8f..b673061f4f5ba 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -122,6 +122,60 @@ struct i915_gem_proto_engine {
>   * an i915_gem_context.  This is used to gather parameters provided either
>   * through creation flags or via SET_CONTEXT_PARAM so that, when we create
>   * the final i915_gem_context, those parameters can be immutable.
> + *
> + * The context uAPI allows for two methods of setting context parameters:
> + * SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The former is
> + * allowed to be called at any time while the later happens as part of
> + * GEM_CONTEXT_CREATE.  When these were initially added, Currently,

							    ^ lowercase

> + * everything settable via one is settable via the other.  While some
> + * params are fairly simple and setting them on a live context is harmless
> + * such the context priority, others are far trickier such as the VM or the

      such _as_ 

> + * set of engines.  To avoid some truly nasty race conditions, we don't
> + * allow setting the VM or the set of engines on live contexts.
> + *
> + * The way we dealt with this without breaking older userspace that sets
> + * the VM or engine set via SET_CONTEXT_PARAM is to delay the creation of
> + * the actual context until after the client is done configuring it with
> + * SET_CONTEXT_PARAM.  From the perspective of the client, it has the same
> + * u32 context ID the whole time.  From the perspective of i915, however,
> + * it's an i915_gem_proto_context right up until the point where we attempt
> + * to do something which the proto-context can't handle at which point the
> + * real context gets created.
> + *
> + * This is accomplished via a little xarray dance.  When GEM_CONTEXT_CREATE
> + * is called, we create a proto-context, reserve a slot in context_xa but
> + * leave it NULL, the proto-context in the corresponding slot in
> + * proto_context_xa.  Then, whenever we go to look up a context, we first
> + * check context_xa.  If it's there, we return the i915_gem_context and
> + * we're done.  If it's not, we look in proto_context_xa and, if we find it
> + * there, we create the actual context and kill the proto-context.

Maybe stuff this into the kerneldoc for the lookup function and just put a
pointer to that in here instead? It hyperlinks in the html output, and in
the text you can follow with cscope or similar. And it's closer to where
the future devs probably need that information.

Minimally at least reference the lookup function here for that link
goodness :-)

> + *
> + * At the time we made this change (April, 2021), we did a fairly complete

s/fairly//

We might have screwed up, but we don't aim to break uapi with
intentionally sloppy work :-P

> + * audit of existing userspace to ensure this wouldn't break anything:
> + *
> + *  - Mesa/i965 didn't use the engines or VM APIs at all
> + *
> + *  - Mesa/ANV used the engines API but via CONTEXT_CREATE_EXT_SETPARAM and
> + *    didn't use the VM API.
> + *
> + *  - Mesa/iris didn't use the engines or VM APIs at all
> + *
> + *  - The open-source compute-runtime didn't yet use the engines API but
> + *    did use the VM API via SET_CONTEXT_PARAM.  However, CONTEXT_SETPARAM
> + *    was always the second ioctl on that context, immediately following
> + *    GEM_CONTEXT_CREATE.
> + *
> + *  - The media driver sets engines and bonding/balancing via
> + *    SET_CONTEXT_PARAM.  However, CONTEXT_SETPARAM to set the VM was
> + *    always the second ioctl on that context, immediately following
> + *    GEM_CONTEXT_CREATE and setting engines immediately followed that.
> + *
> + * In order for this dance to work properly, any modification to an
> + * i915_gem_proto_context that is exposed to the client via
> + * drm_i915_file_private::proto_context_xa must be guarded by
> + * drm_i915_file_private::proto_context_lock.  The exception is when a
> + * proto-context has not yet been exposed such as when handling
> + * CONTEXT_CREATE_SET_PARAM during GEM_CONTEXT_CREATE.
>   */
>  struct i915_gem_proto_context {
>  	/** @vm: See i915_gem_context::vm */
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index cbeefd060e97b..61aaac4a334cf 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -81,6 +81,7 @@ void mock_init_contexts(struct drm_i915_private *i915)
>  struct i915_gem_context *
>  live_context(struct drm_i915_private *i915, struct file *file)
>  {
> +	struct drm_i915_file_private *fpriv = to_drm_file(file)->driver_priv;
>  	struct i915_gem_proto_context *pc;
>  	struct i915_gem_context *ctx;
>  	int err;
> @@ -97,10 +98,12 @@ live_context(struct drm_i915_private *i915, struct file *file)
>  
>  	i915_gem_context_set_no_error_capture(ctx);
>  
> -	err = gem_context_register(ctx, to_drm_file(file)->driver_priv, &id);
> +	err = xa_alloc(&fpriv->context_xa, &id, NULL, xa_limit_32b, GFP_KERNEL);
>  	if (err < 0)
>  		goto err_ctx;
>  
> +	gem_context_register(ctx, fpriv, id);
> +
>  	return ctx;
>  
>  err_ctx:
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 004ed0e59c999..2b323b986dbab 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -200,6 +200,16 @@ struct drm_i915_file_private {
>  		struct rcu_head rcu;
>  	};
>  
> +	/** @proto_context_lock: Guards all i915_gem_proto_context operations

For multi-line kerneldoc we generally put a newline after /**\n I didn't
even know this parses :-) The single-line variant is kinda special.

> +	 *
> +	 * See i915_gem_proto_context.
> +	 */
> +	struct mutex proto_context_lock;
> +
> +	/** @proto_context_xa: xarray of i915_gem_proto_context */
> +	struct xarray proto_context_xa;
> +
> +	/** @context_xa: xarray of fully created i915_gem_context */
>  	struct xarray context_xa;
>  	struct xarray vm_xa;
>  
> @@ -1840,20 +1850,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
>  
>  struct dma_buf *i915_gem_prime_export(struct drm_gem_object *gem_obj, int flags);
>  
> -static inline struct i915_gem_context *
> -i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
> -{
> -	struct i915_gem_context *ctx;
> -
> -	rcu_read_lock();
> -	ctx = xa_load(&file_priv->context_xa, id);
> -	if (ctx && !kref_get_unless_zero(&ctx->ref))
> -		ctx = NULL;
> -	rcu_read_unlock();
> -
> -	return ctx ? ctx : ERR_PTR(-ENOENT);
> -}
> -
>  /* i915_gem_evict.c */
>  int __must_check i915_gem_evict_something(struct i915_address_space *vm,
>  					  u64 min_size, u64 alignment,

All I could find was bikesheds to bring to this party.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 22/27] drm/i915/gem: Delay context creation
  2021-05-03 19:38     ` kernel test robot
  (?)
@ 2021-05-04 20:53       ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 20:53 UTC (permalink / raw)
  To: kernel test robot; +Cc: intel-gfx, kbuild-all, dri-devel, Jason Ekstrand

On Tue, May 04, 2021 at 03:38:06AM +0800, kernel test robot wrote:
> Hi Jason,
> 
> Thank you for the patch! Yet something to improve:
> 
> [auto build test ERROR on drm-intel/for-linux-next]
> [also build test ERROR on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
> [cannot apply to tegra-drm/drm/tegra/for-next v5.12]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
> 
> url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
> base:   git://anongit.freedesktop.org/drm-intel for-linux-next
> config: i386-randconfig-r013-20210503 (attached as .config)
> compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
> reproduce (this is a W=1 build):
>         # https://github.com/0day-ci/linux/commit/66ce6ce447515a302711a65f731d1e6f66abdcdc
>         git remote add linux-review https://github.com/0day-ci/linux
>         git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
>         git checkout 66ce6ce447515a302711a65f731d1e6f66abdcdc
>         # save the attached .config to linux build tree
>         make W=1 W=1 ARCH=i386 
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
> 
> All errors (new ones prefixed by >>):
> 
> >> drivers/gpu/drm/i915/gem/i915_gem_context.c:2543:1: error: no previous prototype for 'lazy_create_context_locked' [-Werror=missing-prototypes]
>     2543 | lazy_create_context_locked(struct drm_i915_file_private *file_priv,
>          | ^~~~~~~~~~~~~~~~~~~~~~~~~~
>    cc1: all warnings being treated as errors

Ah you missed the static, and I missed that in review. That one should be
fixed :-)
-Daniel

> 
> 
> vim +/lazy_create_context_locked +2543 drivers/gpu/drm/i915/gem/i915_gem_context.c
> 
>   2541	
>   2542	struct i915_gem_context *
> > 2543	lazy_create_context_locked(struct drm_i915_file_private *file_priv,
>   2544				   struct i915_gem_proto_context *pc, u32 id)
>   2545	{
>   2546		struct i915_gem_context *ctx;
>   2547		void *old;
>   2548	
>   2549		lockdep_assert_held(&file_priv->proto_context_lock);
>   2550	
>   2551		ctx = i915_gem_create_context(file_priv->dev_priv, pc);
>   2552		if (IS_ERR(ctx))
>   2553			return ctx;
>   2554	
>   2555		gem_context_register(ctx, file_priv, id);
>   2556	
>   2557		old = xa_erase(&file_priv->proto_context_xa, id);
>   2558		GEM_BUG_ON(old != pc);
>   2559		proto_context_close(pc);
>   2560	
>   2561		/* One for the xarray and one for the caller */
>   2562		return i915_gem_context_get(ctx);
>   2563	}
>   2564	
> 
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org


> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 22/27] drm/i915/gem: Delay context creation
@ 2021-05-04 20:53       ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 20:53 UTC (permalink / raw)
  To: kernel test robot; +Cc: intel-gfx, kbuild-all, dri-devel

On Tue, May 04, 2021 at 03:38:06AM +0800, kernel test robot wrote:
> Hi Jason,
> 
> Thank you for the patch! Yet something to improve:
> 
> [auto build test ERROR on drm-intel/for-linux-next]
> [also build test ERROR on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
> [cannot apply to tegra-drm/drm/tegra/for-next v5.12]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
> 
> url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
> base:   git://anongit.freedesktop.org/drm-intel for-linux-next
> config: i386-randconfig-r013-20210503 (attached as .config)
> compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
> reproduce (this is a W=1 build):
>         # https://github.com/0day-ci/linux/commit/66ce6ce447515a302711a65f731d1e6f66abdcdc
>         git remote add linux-review https://github.com/0day-ci/linux
>         git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
>         git checkout 66ce6ce447515a302711a65f731d1e6f66abdcdc
>         # save the attached .config to linux build tree
>         make W=1 W=1 ARCH=i386 
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
> 
> All errors (new ones prefixed by >>):
> 
> >> drivers/gpu/drm/i915/gem/i915_gem_context.c:2543:1: error: no previous prototype for 'lazy_create_context_locked' [-Werror=missing-prototypes]
>     2543 | lazy_create_context_locked(struct drm_i915_file_private *file_priv,
>          | ^~~~~~~~~~~~~~~~~~~~~~~~~~
>    cc1: all warnings being treated as errors

Ah you missed the static, and I missed that in review. That one should be
fixed :-)
-Daniel

> 
> 
> vim +/lazy_create_context_locked +2543 drivers/gpu/drm/i915/gem/i915_gem_context.c
> 
>   2541	
>   2542	struct i915_gem_context *
> > 2543	lazy_create_context_locked(struct drm_i915_file_private *file_priv,
>   2544				   struct i915_gem_proto_context *pc, u32 id)
>   2545	{
>   2546		struct i915_gem_context *ctx;
>   2547		void *old;
>   2548	
>   2549		lockdep_assert_held(&file_priv->proto_context_lock);
>   2550	
>   2551		ctx = i915_gem_create_context(file_priv->dev_priv, pc);
>   2552		if (IS_ERR(ctx))
>   2553			return ctx;
>   2554	
>   2555		gem_context_register(ctx, file_priv, id);
>   2556	
>   2557		old = xa_erase(&file_priv->proto_context_xa, id);
>   2558		GEM_BUG_ON(old != pc);
>   2559		proto_context_close(pc);
>   2560	
>   2561		/* One for the xarray and one for the caller */
>   2562		return i915_gem_context_get(ctx);
>   2563	}
>   2564	
> 
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org


> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 22/27] drm/i915/gem: Delay context creation
@ 2021-05-04 20:53       ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 20:53 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 3176 bytes --]

On Tue, May 04, 2021 at 03:38:06AM +0800, kernel test robot wrote:
> Hi Jason,
> 
> Thank you for the patch! Yet something to improve:
> 
> [auto build test ERROR on drm-intel/for-linux-next]
> [also build test ERROR on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
> [cannot apply to tegra-drm/drm/tegra/for-next v5.12]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
> 
> url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
> base:   git://anongit.freedesktop.org/drm-intel for-linux-next
> config: i386-randconfig-r013-20210503 (attached as .config)
> compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
> reproduce (this is a W=1 build):
>         # https://github.com/0day-ci/linux/commit/66ce6ce447515a302711a65f731d1e6f66abdcdc
>         git remote add linux-review https://github.com/0day-ci/linux
>         git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
>         git checkout 66ce6ce447515a302711a65f731d1e6f66abdcdc
>         # save the attached .config to linux build tree
>         make W=1 W=1 ARCH=i386 
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>
> 
> All errors (new ones prefixed by >>):
> 
> >> drivers/gpu/drm/i915/gem/i915_gem_context.c:2543:1: error: no previous prototype for 'lazy_create_context_locked' [-Werror=missing-prototypes]
>     2543 | lazy_create_context_locked(struct drm_i915_file_private *file_priv,
>          | ^~~~~~~~~~~~~~~~~~~~~~~~~~
>    cc1: all warnings being treated as errors

Ah you missed the static, and I missed that in review. That one should be
fixed :-)
-Daniel

> 
> 
> vim +/lazy_create_context_locked +2543 drivers/gpu/drm/i915/gem/i915_gem_context.c
> 
>   2541	
>   2542	struct i915_gem_context *
> > 2543	lazy_create_context_locked(struct drm_i915_file_private *file_priv,
>   2544				   struct i915_gem_proto_context *pc, u32 id)
>   2545	{
>   2546		struct i915_gem_context *ctx;
>   2547		void *old;
>   2548	
>   2549		lockdep_assert_held(&file_priv->proto_context_lock);
>   2550	
>   2551		ctx = i915_gem_create_context(file_priv->dev_priv, pc);
>   2552		if (IS_ERR(ctx))
>   2553			return ctx;
>   2554	
>   2555		gem_context_register(ctx, file_priv, id);
>   2556	
>   2557		old = xa_erase(&file_priv->proto_context_xa, id);
>   2558		GEM_BUG_ON(old != pc);
>   2559		proto_context_close(pc);
>   2560	
>   2561		/* One for the xarray and one for the caller */
>   2562		return i915_gem_context_get(ctx);
>   2563	}
>   2564	
> 
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org


> _______________________________________________
> dri-devel mailing list
> dri-devel(a)lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts
  2021-05-03 18:52     ` kernel test robot
  (?)
@ 2021-05-04 21:00       ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 21:00 UTC (permalink / raw)
  To: kernel test robot; +Cc: intel-gfx, kbuild-all, dri-devel, Jason Ekstrand

On Tue, May 04, 2021 at 02:52:03AM +0800, kernel test robot wrote:
> Hi Jason,
> 
> Thank you for the patch! Perhaps something to improve:
> 
> [auto build test WARNING on drm-intel/for-linux-next]
> [also build test WARNING on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
> [cannot apply to tegra-drm/drm/tegra/for-next drm/drm-next v5.12]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
> 
> url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
> base:   git://anongit.freedesktop.org/drm-intel for-linux-next
> config: i386-randconfig-s002-20210503 (attached as .config)
> compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
> reproduce:
>         # apt-get install sparse
>         # sparse version: v0.6.3-341-g8af24329-dirty
>         # https://github.com/0day-ci/linux/commit/6af12f5ca765ecd59075344f3be4c4c0b68ef95e
>         git remote add linux-review https://github.com/0day-ci/linux
>         git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
>         git checkout 6af12f5ca765ecd59075344f3be4c4c0b68ef95e
>         # save the attached .config to linux build tree
>         make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' W=1 ARCH=i386 
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>

Just from staring at this I have no idea, so I guess you have to
reproduce. What sparse does is primarily check these special bit and
pointer values the kernel has, like __rcu and __user, where you need
special functions to access them. But since the code is using
rcu_dereference I have no idea what the complaint is about.
-Daniel

> 
> 
> sparse warnings: (new ones prefixed by >>)
>    drivers/gpu/drm/i915/gt/intel_reset.c:1329:5: sparse: sparse: context imbalance in 'intel_gt_reset_trylock' - different lock contexts for basic block
>    drivers/gpu/drm/i915/gt/intel_reset.c: note: in included file:
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/gt/intel_execlists_submission.c: note: in included file (through drivers/gpu/drm/i915/selftests/igt_spinner.h, drivers/gpu/drm/i915/gt/selftest_execlists.c):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/gem/i915_gem_object.c: note: in included file:
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
>    drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space [noderef] __rcu *
>    drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/i915_gem_gtt.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_gem_gtt.c):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/i915_vma.c: note: in included file:
> >> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space *
>    drivers/gpu/drm/i915/i915_vma.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_vma.c):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> 
> vim +163 drivers/gpu/drm/i915/gem/i915_gem_context.h
> 
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  156  
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  157  static inline struct i915_address_space *
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  158  i915_gem_context_get_vm_rcu(struct i915_gem_context *ctx)
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  159  {
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  160  	struct i915_address_space *vm;
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  161  
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  162  	rcu_read_lock();
> a4e7ccdac38ec8 Chris Wilson 2019-10-04 @163  	vm = rcu_dereference(ctx->vm);
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  164  	if (!vm)
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  165  		vm = &ctx->i915->ggtt.vm;
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  166  	vm = i915_vm_get(vm);
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  167  	rcu_read_unlock();
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  168  
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  169  	return vm;
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  170  }
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  171  
> 
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org


> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts
@ 2021-05-04 21:00       ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 21:00 UTC (permalink / raw)
  To: kernel test robot; +Cc: intel-gfx, kbuild-all, dri-devel

On Tue, May 04, 2021 at 02:52:03AM +0800, kernel test robot wrote:
> Hi Jason,
> 
> Thank you for the patch! Perhaps something to improve:
> 
> [auto build test WARNING on drm-intel/for-linux-next]
> [also build test WARNING on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
> [cannot apply to tegra-drm/drm/tegra/for-next drm/drm-next v5.12]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
> 
> url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
> base:   git://anongit.freedesktop.org/drm-intel for-linux-next
> config: i386-randconfig-s002-20210503 (attached as .config)
> compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
> reproduce:
>         # apt-get install sparse
>         # sparse version: v0.6.3-341-g8af24329-dirty
>         # https://github.com/0day-ci/linux/commit/6af12f5ca765ecd59075344f3be4c4c0b68ef95e
>         git remote add linux-review https://github.com/0day-ci/linux
>         git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
>         git checkout 6af12f5ca765ecd59075344f3be4c4c0b68ef95e
>         # save the attached .config to linux build tree
>         make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' W=1 ARCH=i386 
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>

Just from staring at this I have no idea, so I guess you have to
reproduce. What sparse does is primarily check these special bit and
pointer values the kernel has, like __rcu and __user, where you need
special functions to access them. But since the code is using
rcu_dereference I have no idea what the complaint is about.
-Daniel

> 
> 
> sparse warnings: (new ones prefixed by >>)
>    drivers/gpu/drm/i915/gt/intel_reset.c:1329:5: sparse: sparse: context imbalance in 'intel_gt_reset_trylock' - different lock contexts for basic block
>    drivers/gpu/drm/i915/gt/intel_reset.c: note: in included file:
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/gt/intel_execlists_submission.c: note: in included file (through drivers/gpu/drm/i915/selftests/igt_spinner.h, drivers/gpu/drm/i915/gt/selftest_execlists.c):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/gem/i915_gem_object.c: note: in included file:
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
>    drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space [noderef] __rcu *
>    drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/i915_gem_gtt.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_gem_gtt.c):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/i915_vma.c: note: in included file:
> >> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space *
>    drivers/gpu/drm/i915/i915_vma.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_vma.c):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> 
> vim +163 drivers/gpu/drm/i915/gem/i915_gem_context.h
> 
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  156  
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  157  static inline struct i915_address_space *
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  158  i915_gem_context_get_vm_rcu(struct i915_gem_context *ctx)
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  159  {
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  160  	struct i915_address_space *vm;
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  161  
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  162  	rcu_read_lock();
> a4e7ccdac38ec8 Chris Wilson 2019-10-04 @163  	vm = rcu_dereference(ctx->vm);
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  164  	if (!vm)
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  165  		vm = &ctx->i915->ggtt.vm;
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  166  	vm = i915_vm_get(vm);
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  167  	rcu_read_unlock();
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  168  
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  169  	return vm;
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  170  }
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  171  
> 
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org


> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts
@ 2021-05-04 21:00       ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 21:00 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 7457 bytes --]

On Tue, May 04, 2021 at 02:52:03AM +0800, kernel test robot wrote:
> Hi Jason,
> 
> Thank you for the patch! Perhaps something to improve:
> 
> [auto build test WARNING on drm-intel/for-linux-next]
> [also build test WARNING on drm-tip/drm-tip drm-exynos/exynos-drm-next next-20210503]
> [cannot apply to tegra-drm/drm/tegra/for-next drm/drm-next v5.12]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch]
> 
> url:    https://github.com/0day-ci/linux/commits/Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
> base:   git://anongit.freedesktop.org/drm-intel for-linux-next
> config: i386-randconfig-s002-20210503 (attached as .config)
> compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
> reproduce:
>         # apt-get install sparse
>         # sparse version: v0.6.3-341-g8af24329-dirty
>         # https://github.com/0day-ci/linux/commit/6af12f5ca765ecd59075344f3be4c4c0b68ef95e
>         git remote add linux-review https://github.com/0day-ci/linux
>         git fetch --no-tags linux-review Jason-Ekstrand/drm-i915-gem-ioctl-clean-ups-v5/20210504-000132
>         git checkout 6af12f5ca765ecd59075344f3be4c4c0b68ef95e
>         # save the attached .config to linux build tree
>         make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' W=1 ARCH=i386 
> 
> If you fix the issue, kindly add following tag as appropriate
> Reported-by: kernel test robot <lkp@intel.com>

Just from staring at this I have no idea, so I guess you have to
reproduce. What sparse does is primarily check these special bit and
pointer values the kernel has, like __rcu and __user, where you need
special functions to access them. But since the code is using
rcu_dereference I have no idea what the complaint is about.
-Daniel

> 
> 
> sparse warnings: (new ones prefixed by >>)
>    drivers/gpu/drm/i915/gt/intel_reset.c:1329:5: sparse: sparse: context imbalance in 'intel_gt_reset_trylock' - different lock contexts for basic block
>    drivers/gpu/drm/i915/gt/intel_reset.c: note: in included file:
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/gt/intel_execlists_submission.c: note: in included file (through drivers/gpu/drm/i915/selftests/igt_spinner.h, drivers/gpu/drm/i915/gt/selftest_execlists.c):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/gem/i915_gem_object.c: note: in included file:
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
>    drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse: sparse: incompatible types in comparison expression (different address spaces):
>    drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space [noderef] __rcu *
>    drivers/gpu/drm/i915/gem/i915_gem_context.h:154:16: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/i915_gem_gtt.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_gem_gtt.c):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> --
>    drivers/gpu/drm/i915/i915_vma.c: note: in included file:
> >> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/selftests/i915_vma.c:42:24: sparse:    struct i915_address_space *
>    drivers/gpu/drm/i915/i915_vma.c: note: in included file (through drivers/gpu/drm/i915/selftests/i915_vma.c):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space [noderef] __rcu *
> >> drivers/gpu/drm/i915/gem/i915_gem_context.h:163:14: sparse:    struct i915_address_space *
> 
> vim +163 drivers/gpu/drm/i915/gem/i915_gem_context.h
> 
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  156  
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  157  static inline struct i915_address_space *
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  158  i915_gem_context_get_vm_rcu(struct i915_gem_context *ctx)
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  159  {
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  160  	struct i915_address_space *vm;
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  161  
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  162  	rcu_read_lock();
> a4e7ccdac38ec8 Chris Wilson 2019-10-04 @163  	vm = rcu_dereference(ctx->vm);
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  164  	if (!vm)
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  165  		vm = &ctx->i915->ggtt.vm;
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  166  	vm = i915_vm_get(vm);
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  167  	rcu_read_unlock();
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  168  
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  169  	return vm;
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  170  }
> a4e7ccdac38ec8 Chris Wilson 2019-10-04  171  
> 
> ---
> 0-DAY CI Kernel Test Service, Intel Corporation
> https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org


> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx(a)lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx


-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-04 21:17     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 21:17 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:44AM -0500, Jason Ekstrand wrote:
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

First, a bit of commit message please here.

Second I accidentally went down the rabbit hole and ended up at
try_qad_pin().

Your patch looks good, unfortunately my brain is complete mushroom soup
now.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 267 ------------------
>  .../gpu/drm/i915/gem/i915_gem_context_types.h |   2 +-
>  .../drm/i915/gem/selftests/i915_gem_context.c | 119 --------
>  .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
>  4 files changed, 1 insertion(+), 388 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index f0e7ce6b979b4..ad6e98d8a4fbd 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1637,121 +1637,6 @@ int i915_gem_vm_destroy_ioctl(struct drm_device *dev, void *data,
>  	return 0;
>  }
>  
> -struct context_barrier_task {
> -	struct i915_active base;
> -	void (*task)(void *data);
> -	void *data;
> -};
> -
> -__i915_active_call
> -static void cb_retire(struct i915_active *base)
> -{
> -	struct context_barrier_task *cb = container_of(base, typeof(*cb), base);
> -
> -	if (cb->task)
> -		cb->task(cb->data);
> -
> -	i915_active_fini(&cb->base);
> -	kfree(cb);
> -}
> -
> -I915_SELFTEST_DECLARE(static intel_engine_mask_t context_barrier_inject_fault);
> -static int context_barrier_task(struct i915_gem_context *ctx,
> -				intel_engine_mask_t engines,
> -				bool (*skip)(struct intel_context *ce, void *data),
> -				int (*pin)(struct intel_context *ce, struct i915_gem_ww_ctx *ww, void *data),
> -				int (*emit)(struct i915_request *rq, void *data),
> -				void (*task)(void *data),
> -				void *data)
> -{
> -	struct context_barrier_task *cb;
> -	struct i915_gem_engines_iter it;
> -	struct i915_gem_engines *e;
> -	struct i915_gem_ww_ctx ww;
> -	struct intel_context *ce;
> -	int err = 0;
> -
> -	GEM_BUG_ON(!task);
> -
> -	cb = kmalloc(sizeof(*cb), GFP_KERNEL);
> -	if (!cb)
> -		return -ENOMEM;
> -
> -	i915_active_init(&cb->base, NULL, cb_retire);
> -	err = i915_active_acquire(&cb->base);
> -	if (err) {
> -		kfree(cb);
> -		return err;
> -	}
> -
> -	e = __context_engines_await(ctx, NULL);
> -	if (!e) {
> -		i915_active_release(&cb->base);
> -		return -ENOENT;
> -	}
> -
> -	for_each_gem_engine(ce, e, it) {
> -		struct i915_request *rq;
> -
> -		if (I915_SELFTEST_ONLY(context_barrier_inject_fault &
> -				       ce->engine->mask)) {
> -			err = -ENXIO;
> -			break;
> -		}
> -
> -		if (!(ce->engine->mask & engines))
> -			continue;
> -
> -		if (skip && skip(ce, data))
> -			continue;
> -
> -		i915_gem_ww_ctx_init(&ww, true);
> -retry:
> -		err = intel_context_pin_ww(ce, &ww);
> -		if (err)
> -			goto err;
> -
> -		if (pin)
> -			err = pin(ce, &ww, data);
> -		if (err)
> -			goto err_unpin;
> -
> -		rq = i915_request_create(ce);
> -		if (IS_ERR(rq)) {
> -			err = PTR_ERR(rq);
> -			goto err_unpin;
> -		}
> -
> -		err = 0;
> -		if (emit)
> -			err = emit(rq, data);
> -		if (err == 0)
> -			err = i915_active_add_request(&cb->base, rq);
> -
> -		i915_request_add(rq);
> -err_unpin:
> -		intel_context_unpin(ce);
> -err:
> -		if (err == -EDEADLK) {
> -			err = i915_gem_ww_ctx_backoff(&ww);
> -			if (!err)
> -				goto retry;
> -		}
> -		i915_gem_ww_ctx_fini(&ww);
> -
> -		if (err)
> -			break;
> -	}
> -	i915_sw_fence_complete(&e->fence);
> -
> -	cb->task = err ? NULL : task; /* caller needs to unwind instead */
> -	cb->data = data;
> -
> -	i915_active_release(&cb->base);
> -
> -	return err;
> -}
> -
>  static int get_ppgtt(struct drm_i915_file_private *file_priv,
>  		     struct i915_gem_context *ctx,
>  		     struct drm_i915_gem_context_param *args)
> @@ -1784,154 +1669,6 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
>  	return err;
>  }
>  
> -static void set_ppgtt_barrier(void *data)
> -{
> -	struct i915_address_space *old = data;
> -
> -	if (INTEL_GEN(old->i915) < 8)
> -		gen6_ppgtt_unpin_all(i915_vm_to_ppgtt(old));
> -
> -	i915_vm_close(old);
> -}
> -
> -static int pin_ppgtt_update(struct intel_context *ce, struct i915_gem_ww_ctx *ww, void *data)
> -{
> -	struct i915_address_space *vm = ce->vm;
> -
> -	if (!HAS_LOGICAL_RING_CONTEXTS(vm->i915))
> -		/* ppGTT is not part of the legacy context image */
> -		return gen6_ppgtt_pin(i915_vm_to_ppgtt(vm), ww);
> -
> -	return 0;
> -}
> -
> -static int emit_ppgtt_update(struct i915_request *rq, void *data)
> -{
> -	struct i915_address_space *vm = rq->context->vm;
> -	struct intel_engine_cs *engine = rq->engine;
> -	u32 base = engine->mmio_base;
> -	u32 *cs;
> -	int i;
> -
> -	if (i915_vm_is_4lvl(vm)) {
> -		struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
> -		const dma_addr_t pd_daddr = px_dma(ppgtt->pd);
> -
> -		cs = intel_ring_begin(rq, 6);
> -		if (IS_ERR(cs))
> -			return PTR_ERR(cs);
> -
> -		*cs++ = MI_LOAD_REGISTER_IMM(2);
> -
> -		*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(base, 0));
> -		*cs++ = upper_32_bits(pd_daddr);
> -		*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(base, 0));
> -		*cs++ = lower_32_bits(pd_daddr);
> -
> -		*cs++ = MI_NOOP;
> -		intel_ring_advance(rq, cs);
> -	} else if (HAS_LOGICAL_RING_CONTEXTS(engine->i915)) {
> -		struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
> -		int err;
> -
> -		/* Magic required to prevent forcewake errors! */
> -		err = engine->emit_flush(rq, EMIT_INVALIDATE);
> -		if (err)
> -			return err;
> -
> -		cs = intel_ring_begin(rq, 4 * GEN8_3LVL_PDPES + 2);
> -		if (IS_ERR(cs))
> -			return PTR_ERR(cs);
> -
> -		*cs++ = MI_LOAD_REGISTER_IMM(2 * GEN8_3LVL_PDPES) | MI_LRI_FORCE_POSTED;
> -		for (i = GEN8_3LVL_PDPES; i--; ) {
> -			const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i);
> -
> -			*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(base, i));
> -			*cs++ = upper_32_bits(pd_daddr);
> -			*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(base, i));
> -			*cs++ = lower_32_bits(pd_daddr);
> -		}
> -		*cs++ = MI_NOOP;
> -		intel_ring_advance(rq, cs);
> -	}
> -
> -	return 0;
> -}
> -
> -static bool skip_ppgtt_update(struct intel_context *ce, void *data)
> -{
> -	if (HAS_LOGICAL_RING_CONTEXTS(ce->engine->i915))
> -		return !ce->state;
> -	else
> -		return !atomic_read(&ce->pin_count);
> -}
> -
> -static int set_ppgtt(struct drm_i915_file_private *file_priv,
> -		     struct i915_gem_context *ctx,
> -		     struct drm_i915_gem_context_param *args)
> -{
> -	struct i915_address_space *vm, *old;
> -	int err;
> -
> -	if (args->size)
> -		return -EINVAL;
> -
> -	if (!rcu_access_pointer(ctx->vm))
> -		return -ENODEV;
> -
> -	if (upper_32_bits(args->value))
> -		return -ENOENT;
> -
> -	rcu_read_lock();
> -	vm = xa_load(&file_priv->vm_xa, args->value);
> -	if (vm && !kref_get_unless_zero(&vm->ref))
> -		vm = NULL;
> -	rcu_read_unlock();
> -	if (!vm)
> -		return -ENOENT;
> -
> -	err = mutex_lock_interruptible(&ctx->mutex);
> -	if (err)
> -		goto out;
> -
> -	if (i915_gem_context_is_closed(ctx)) {
> -		err = -ENOENT;
> -		goto unlock;
> -	}
> -
> -	if (vm == rcu_access_pointer(ctx->vm))
> -		goto unlock;
> -
> -	old = __set_ppgtt(ctx, vm);
> -
> -	/* Teardown the existing obj:vma cache, it will have to be rebuilt. */
> -	lut_close(ctx);
> -
> -	/*
> -	 * We need to flush any requests using the current ppgtt before
> -	 * we release it as the requests do not hold a reference themselves,
> -	 * only indirectly through the context.
> -	 */
> -	err = context_barrier_task(ctx, ALL_ENGINES,
> -				   skip_ppgtt_update,
> -				   pin_ppgtt_update,
> -				   emit_ppgtt_update,
> -				   set_ppgtt_barrier,
> -				   old);
> -	if (err) {
> -		i915_vm_close(__set_ppgtt(ctx, old));
> -		i915_vm_close(old);
> -		lut_close(ctx); /* force a rebuild of the old obj:vma cache */
> -	}
> -
> -unlock:
> -	mutex_unlock(&ctx->mutex);
> -out:
> -	i915_vm_put(vm);
> -	return err;
> -}
> -
>  int
>  i915_gem_user_to_context_sseu(struct intel_gt *gt,
>  			      const struct drm_i915_gem_context_param_sseu *user,
> @@ -2468,10 +2205,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>  		ret = set_sseu(ctx, args);
>  		break;
>  
> -	case I915_CONTEXT_PARAM_VM:
> -		ret = set_ppgtt(fpriv, ctx, args);
> -		break;
> -
>  	case I915_CONTEXT_PARAM_ENGINES:
>  		ret = set_engines(ctx, args);
>  		break;
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index b673061f4f5ba..84c821cca1739 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -262,7 +262,7 @@ struct i915_gem_context {
>  	 * In other modes, this is a NULL pointer with the expectation that
>  	 * the caller uses the shared global GTT.
>  	 */
> -	struct i915_address_space __rcu *vm;
> +	struct i915_address_space *vm;
>  
>  	/**
>  	 * @pid: process id of creator
> diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> index 5fef592390cb5..16ff64ab34a1b 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> @@ -1882,125 +1882,6 @@ static int igt_vm_isolation(void *arg)
>  	return err;
>  }
>  
> -static bool skip_unused_engines(struct intel_context *ce, void *data)
> -{
> -	return !ce->state;
> -}
> -
> -static void mock_barrier_task(void *data)
> -{
> -	unsigned int *counter = data;
> -
> -	++*counter;
> -}
> -
> -static int mock_context_barrier(void *arg)
> -{
> -#undef pr_fmt
> -#define pr_fmt(x) "context_barrier_task():" # x
> -	struct drm_i915_private *i915 = arg;
> -	struct i915_gem_context *ctx;
> -	struct i915_request *rq;
> -	unsigned int counter;
> -	int err;
> -
> -	/*
> -	 * The context barrier provides us with a callback after it emits
> -	 * a request; useful for retiring old state after loading new.
> -	 */
> -
> -	ctx = mock_context(i915, "mock");
> -	if (!ctx)
> -		return -ENOMEM;
> -
> -	counter = 0;
> -	err = context_barrier_task(ctx, 0, NULL, NULL, NULL,
> -				   mock_barrier_task, &counter);
> -	if (err) {
> -		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
> -		goto out;
> -	}
> -	if (counter == 0) {
> -		pr_err("Did not retire immediately with 0 engines\n");
> -		err = -EINVAL;
> -		goto out;
> -	}
> -
> -	counter = 0;
> -	err = context_barrier_task(ctx, ALL_ENGINES, skip_unused_engines,
> -				   NULL, NULL, mock_barrier_task, &counter);
> -	if (err) {
> -		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
> -		goto out;
> -	}
> -	if (counter == 0) {
> -		pr_err("Did not retire immediately for all unused engines\n");
> -		err = -EINVAL;
> -		goto out;
> -	}
> -
> -	rq = igt_request_alloc(ctx, i915->gt.engine[RCS0]);
> -	if (IS_ERR(rq)) {
> -		pr_err("Request allocation failed!\n");
> -		goto out;
> -	}
> -	i915_request_add(rq);
> -
> -	counter = 0;
> -	context_barrier_inject_fault = BIT(RCS0);
> -	err = context_barrier_task(ctx, ALL_ENGINES, NULL, NULL, NULL,
> -				   mock_barrier_task, &counter);
> -	context_barrier_inject_fault = 0;
> -	if (err == -ENXIO)
> -		err = 0;
> -	else
> -		pr_err("Did not hit fault injection!\n");
> -	if (counter != 0) {
> -		pr_err("Invoked callback on error!\n");
> -		err = -EIO;
> -	}
> -	if (err)
> -		goto out;
> -
> -	counter = 0;
> -	err = context_barrier_task(ctx, ALL_ENGINES, skip_unused_engines,
> -				   NULL, NULL, mock_barrier_task, &counter);
> -	if (err) {
> -		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
> -		goto out;
> -	}
> -	mock_device_flush(i915);
> -	if (counter == 0) {
> -		pr_err("Did not retire on each active engines\n");
> -		err = -EINVAL;
> -		goto out;
> -	}
> -
> -out:
> -	mock_context_close(ctx);
> -	return err;
> -#undef pr_fmt
> -#define pr_fmt(x) x
> -}
> -
> -int i915_gem_context_mock_selftests(void)
> -{
> -	static const struct i915_subtest tests[] = {
> -		SUBTEST(mock_context_barrier),
> -	};
> -	struct drm_i915_private *i915;
> -	int err;
> -
> -	i915 = mock_gem_device();
> -	if (!i915)
> -		return -ENOMEM;
> -
> -	err = i915_subtests(tests, i915);
> -
> -	mock_destroy_device(i915);
> -	return err;
> -}
> -
>  int i915_gem_context_live_selftests(struct drm_i915_private *i915)
>  {
>  	static const struct i915_subtest tests[] = {
> diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> index 3db34d3eea58a..52aa91716dc1f 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> +++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> @@ -32,6 +32,5 @@ selftest(vma, i915_vma_mock_selftests)
>  selftest(evict, i915_gem_evict_mock_selftests)
>  selftest(gtt, i915_gem_gtt_mock_selftests)
>  selftest(hugepages, i915_gem_huge_page_mock_selftests)
> -selftest(contexts, i915_gem_context_mock_selftests)
>  selftest(buddy, i915_buddy_mock_selftests)
>  selftest(memory_region, intel_memory_region_mock_selftests)
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts
@ 2021-05-04 21:17     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-04 21:17 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:44AM -0500, Jason Ekstrand wrote:
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

First, a bit of commit message please here.

Second I accidentally went down the rabbit hole and ended up at
try_qad_pin().

Your patch looks good, unfortunately my brain is complete mushroom soup
now.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 267 ------------------
>  .../gpu/drm/i915/gem/i915_gem_context_types.h |   2 +-
>  .../drm/i915/gem/selftests/i915_gem_context.c | 119 --------
>  .../drm/i915/selftests/i915_mock_selftests.h  |   1 -
>  4 files changed, 1 insertion(+), 388 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index f0e7ce6b979b4..ad6e98d8a4fbd 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1637,121 +1637,6 @@ int i915_gem_vm_destroy_ioctl(struct drm_device *dev, void *data,
>  	return 0;
>  }
>  
> -struct context_barrier_task {
> -	struct i915_active base;
> -	void (*task)(void *data);
> -	void *data;
> -};
> -
> -__i915_active_call
> -static void cb_retire(struct i915_active *base)
> -{
> -	struct context_barrier_task *cb = container_of(base, typeof(*cb), base);
> -
> -	if (cb->task)
> -		cb->task(cb->data);
> -
> -	i915_active_fini(&cb->base);
> -	kfree(cb);
> -}
> -
> -I915_SELFTEST_DECLARE(static intel_engine_mask_t context_barrier_inject_fault);
> -static int context_barrier_task(struct i915_gem_context *ctx,
> -				intel_engine_mask_t engines,
> -				bool (*skip)(struct intel_context *ce, void *data),
> -				int (*pin)(struct intel_context *ce, struct i915_gem_ww_ctx *ww, void *data),
> -				int (*emit)(struct i915_request *rq, void *data),
> -				void (*task)(void *data),
> -				void *data)
> -{
> -	struct context_barrier_task *cb;
> -	struct i915_gem_engines_iter it;
> -	struct i915_gem_engines *e;
> -	struct i915_gem_ww_ctx ww;
> -	struct intel_context *ce;
> -	int err = 0;
> -
> -	GEM_BUG_ON(!task);
> -
> -	cb = kmalloc(sizeof(*cb), GFP_KERNEL);
> -	if (!cb)
> -		return -ENOMEM;
> -
> -	i915_active_init(&cb->base, NULL, cb_retire);
> -	err = i915_active_acquire(&cb->base);
> -	if (err) {
> -		kfree(cb);
> -		return err;
> -	}
> -
> -	e = __context_engines_await(ctx, NULL);
> -	if (!e) {
> -		i915_active_release(&cb->base);
> -		return -ENOENT;
> -	}
> -
> -	for_each_gem_engine(ce, e, it) {
> -		struct i915_request *rq;
> -
> -		if (I915_SELFTEST_ONLY(context_barrier_inject_fault &
> -				       ce->engine->mask)) {
> -			err = -ENXIO;
> -			break;
> -		}
> -
> -		if (!(ce->engine->mask & engines))
> -			continue;
> -
> -		if (skip && skip(ce, data))
> -			continue;
> -
> -		i915_gem_ww_ctx_init(&ww, true);
> -retry:
> -		err = intel_context_pin_ww(ce, &ww);
> -		if (err)
> -			goto err;
> -
> -		if (pin)
> -			err = pin(ce, &ww, data);
> -		if (err)
> -			goto err_unpin;
> -
> -		rq = i915_request_create(ce);
> -		if (IS_ERR(rq)) {
> -			err = PTR_ERR(rq);
> -			goto err_unpin;
> -		}
> -
> -		err = 0;
> -		if (emit)
> -			err = emit(rq, data);
> -		if (err == 0)
> -			err = i915_active_add_request(&cb->base, rq);
> -
> -		i915_request_add(rq);
> -err_unpin:
> -		intel_context_unpin(ce);
> -err:
> -		if (err == -EDEADLK) {
> -			err = i915_gem_ww_ctx_backoff(&ww);
> -			if (!err)
> -				goto retry;
> -		}
> -		i915_gem_ww_ctx_fini(&ww);
> -
> -		if (err)
> -			break;
> -	}
> -	i915_sw_fence_complete(&e->fence);
> -
> -	cb->task = err ? NULL : task; /* caller needs to unwind instead */
> -	cb->data = data;
> -
> -	i915_active_release(&cb->base);
> -
> -	return err;
> -}
> -
>  static int get_ppgtt(struct drm_i915_file_private *file_priv,
>  		     struct i915_gem_context *ctx,
>  		     struct drm_i915_gem_context_param *args)
> @@ -1784,154 +1669,6 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
>  	return err;
>  }
>  
> -static void set_ppgtt_barrier(void *data)
> -{
> -	struct i915_address_space *old = data;
> -
> -	if (INTEL_GEN(old->i915) < 8)
> -		gen6_ppgtt_unpin_all(i915_vm_to_ppgtt(old));
> -
> -	i915_vm_close(old);
> -}
> -
> -static int pin_ppgtt_update(struct intel_context *ce, struct i915_gem_ww_ctx *ww, void *data)
> -{
> -	struct i915_address_space *vm = ce->vm;
> -
> -	if (!HAS_LOGICAL_RING_CONTEXTS(vm->i915))
> -		/* ppGTT is not part of the legacy context image */
> -		return gen6_ppgtt_pin(i915_vm_to_ppgtt(vm), ww);
> -
> -	return 0;
> -}
> -
> -static int emit_ppgtt_update(struct i915_request *rq, void *data)
> -{
> -	struct i915_address_space *vm = rq->context->vm;
> -	struct intel_engine_cs *engine = rq->engine;
> -	u32 base = engine->mmio_base;
> -	u32 *cs;
> -	int i;
> -
> -	if (i915_vm_is_4lvl(vm)) {
> -		struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
> -		const dma_addr_t pd_daddr = px_dma(ppgtt->pd);
> -
> -		cs = intel_ring_begin(rq, 6);
> -		if (IS_ERR(cs))
> -			return PTR_ERR(cs);
> -
> -		*cs++ = MI_LOAD_REGISTER_IMM(2);
> -
> -		*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(base, 0));
> -		*cs++ = upper_32_bits(pd_daddr);
> -		*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(base, 0));
> -		*cs++ = lower_32_bits(pd_daddr);
> -
> -		*cs++ = MI_NOOP;
> -		intel_ring_advance(rq, cs);
> -	} else if (HAS_LOGICAL_RING_CONTEXTS(engine->i915)) {
> -		struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm);
> -		int err;
> -
> -		/* Magic required to prevent forcewake errors! */
> -		err = engine->emit_flush(rq, EMIT_INVALIDATE);
> -		if (err)
> -			return err;
> -
> -		cs = intel_ring_begin(rq, 4 * GEN8_3LVL_PDPES + 2);
> -		if (IS_ERR(cs))
> -			return PTR_ERR(cs);
> -
> -		*cs++ = MI_LOAD_REGISTER_IMM(2 * GEN8_3LVL_PDPES) | MI_LRI_FORCE_POSTED;
> -		for (i = GEN8_3LVL_PDPES; i--; ) {
> -			const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i);
> -
> -			*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_UDW(base, i));
> -			*cs++ = upper_32_bits(pd_daddr);
> -			*cs++ = i915_mmio_reg_offset(GEN8_RING_PDP_LDW(base, i));
> -			*cs++ = lower_32_bits(pd_daddr);
> -		}
> -		*cs++ = MI_NOOP;
> -		intel_ring_advance(rq, cs);
> -	}
> -
> -	return 0;
> -}
> -
> -static bool skip_ppgtt_update(struct intel_context *ce, void *data)
> -{
> -	if (HAS_LOGICAL_RING_CONTEXTS(ce->engine->i915))
> -		return !ce->state;
> -	else
> -		return !atomic_read(&ce->pin_count);
> -}
> -
> -static int set_ppgtt(struct drm_i915_file_private *file_priv,
> -		     struct i915_gem_context *ctx,
> -		     struct drm_i915_gem_context_param *args)
> -{
> -	struct i915_address_space *vm, *old;
> -	int err;
> -
> -	if (args->size)
> -		return -EINVAL;
> -
> -	if (!rcu_access_pointer(ctx->vm))
> -		return -ENODEV;
> -
> -	if (upper_32_bits(args->value))
> -		return -ENOENT;
> -
> -	rcu_read_lock();
> -	vm = xa_load(&file_priv->vm_xa, args->value);
> -	if (vm && !kref_get_unless_zero(&vm->ref))
> -		vm = NULL;
> -	rcu_read_unlock();
> -	if (!vm)
> -		return -ENOENT;
> -
> -	err = mutex_lock_interruptible(&ctx->mutex);
> -	if (err)
> -		goto out;
> -
> -	if (i915_gem_context_is_closed(ctx)) {
> -		err = -ENOENT;
> -		goto unlock;
> -	}
> -
> -	if (vm == rcu_access_pointer(ctx->vm))
> -		goto unlock;
> -
> -	old = __set_ppgtt(ctx, vm);
> -
> -	/* Teardown the existing obj:vma cache, it will have to be rebuilt. */
> -	lut_close(ctx);
> -
> -	/*
> -	 * We need to flush any requests using the current ppgtt before
> -	 * we release it as the requests do not hold a reference themselves,
> -	 * only indirectly through the context.
> -	 */
> -	err = context_barrier_task(ctx, ALL_ENGINES,
> -				   skip_ppgtt_update,
> -				   pin_ppgtt_update,
> -				   emit_ppgtt_update,
> -				   set_ppgtt_barrier,
> -				   old);
> -	if (err) {
> -		i915_vm_close(__set_ppgtt(ctx, old));
> -		i915_vm_close(old);
> -		lut_close(ctx); /* force a rebuild of the old obj:vma cache */
> -	}
> -
> -unlock:
> -	mutex_unlock(&ctx->mutex);
> -out:
> -	i915_vm_put(vm);
> -	return err;
> -}
> -
>  int
>  i915_gem_user_to_context_sseu(struct intel_gt *gt,
>  			      const struct drm_i915_gem_context_param_sseu *user,
> @@ -2468,10 +2205,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>  		ret = set_sseu(ctx, args);
>  		break;
>  
> -	case I915_CONTEXT_PARAM_VM:
> -		ret = set_ppgtt(fpriv, ctx, args);
> -		break;
> -
>  	case I915_CONTEXT_PARAM_ENGINES:
>  		ret = set_engines(ctx, args);
>  		break;
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index b673061f4f5ba..84c821cca1739 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -262,7 +262,7 @@ struct i915_gem_context {
>  	 * In other modes, this is a NULL pointer with the expectation that
>  	 * the caller uses the shared global GTT.
>  	 */
> -	struct i915_address_space __rcu *vm;
> +	struct i915_address_space *vm;
>  
>  	/**
>  	 * @pid: process id of creator
> diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> index 5fef592390cb5..16ff64ab34a1b 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> @@ -1882,125 +1882,6 @@ static int igt_vm_isolation(void *arg)
>  	return err;
>  }
>  
> -static bool skip_unused_engines(struct intel_context *ce, void *data)
> -{
> -	return !ce->state;
> -}
> -
> -static void mock_barrier_task(void *data)
> -{
> -	unsigned int *counter = data;
> -
> -	++*counter;
> -}
> -
> -static int mock_context_barrier(void *arg)
> -{
> -#undef pr_fmt
> -#define pr_fmt(x) "context_barrier_task():" # x
> -	struct drm_i915_private *i915 = arg;
> -	struct i915_gem_context *ctx;
> -	struct i915_request *rq;
> -	unsigned int counter;
> -	int err;
> -
> -	/*
> -	 * The context barrier provides us with a callback after it emits
> -	 * a request; useful for retiring old state after loading new.
> -	 */
> -
> -	ctx = mock_context(i915, "mock");
> -	if (!ctx)
> -		return -ENOMEM;
> -
> -	counter = 0;
> -	err = context_barrier_task(ctx, 0, NULL, NULL, NULL,
> -				   mock_barrier_task, &counter);
> -	if (err) {
> -		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
> -		goto out;
> -	}
> -	if (counter == 0) {
> -		pr_err("Did not retire immediately with 0 engines\n");
> -		err = -EINVAL;
> -		goto out;
> -	}
> -
> -	counter = 0;
> -	err = context_barrier_task(ctx, ALL_ENGINES, skip_unused_engines,
> -				   NULL, NULL, mock_barrier_task, &counter);
> -	if (err) {
> -		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
> -		goto out;
> -	}
> -	if (counter == 0) {
> -		pr_err("Did not retire immediately for all unused engines\n");
> -		err = -EINVAL;
> -		goto out;
> -	}
> -
> -	rq = igt_request_alloc(ctx, i915->gt.engine[RCS0]);
> -	if (IS_ERR(rq)) {
> -		pr_err("Request allocation failed!\n");
> -		goto out;
> -	}
> -	i915_request_add(rq);
> -
> -	counter = 0;
> -	context_barrier_inject_fault = BIT(RCS0);
> -	err = context_barrier_task(ctx, ALL_ENGINES, NULL, NULL, NULL,
> -				   mock_barrier_task, &counter);
> -	context_barrier_inject_fault = 0;
> -	if (err == -ENXIO)
> -		err = 0;
> -	else
> -		pr_err("Did not hit fault injection!\n");
> -	if (counter != 0) {
> -		pr_err("Invoked callback on error!\n");
> -		err = -EIO;
> -	}
> -	if (err)
> -		goto out;
> -
> -	counter = 0;
> -	err = context_barrier_task(ctx, ALL_ENGINES, skip_unused_engines,
> -				   NULL, NULL, mock_barrier_task, &counter);
> -	if (err) {
> -		pr_err("Failed at line %d, err=%d\n", __LINE__, err);
> -		goto out;
> -	}
> -	mock_device_flush(i915);
> -	if (counter == 0) {
> -		pr_err("Did not retire on each active engines\n");
> -		err = -EINVAL;
> -		goto out;
> -	}
> -
> -out:
> -	mock_context_close(ctx);
> -	return err;
> -#undef pr_fmt
> -#define pr_fmt(x) x
> -}
> -
> -int i915_gem_context_mock_selftests(void)
> -{
> -	static const struct i915_subtest tests[] = {
> -		SUBTEST(mock_context_barrier),
> -	};
> -	struct drm_i915_private *i915;
> -	int err;
> -
> -	i915 = mock_gem_device();
> -	if (!i915)
> -		return -ENOMEM;
> -
> -	err = i915_subtests(tests, i915);
> -
> -	mock_destroy_device(i915);
> -	return err;
> -}
> -
>  int i915_gem_context_live_selftests(struct drm_i915_private *i915)
>  {
>  	static const struct i915_subtest tests[] = {
> diff --git a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> index 3db34d3eea58a..52aa91716dc1f 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> +++ b/drivers/gpu/drm/i915/selftests/i915_mock_selftests.h
> @@ -32,6 +32,5 @@ selftest(vma, i915_vma_mock_selftests)
>  selftest(evict, i915_gem_evict_mock_selftests)
>  selftest(gtt, i915_gem_gtt_mock_selftests)
>  selftest(hugepages, i915_gem_huge_page_mock_selftests)
> -selftest(contexts, i915_gem_context_mock_selftests)
>  selftest(buddy, i915_buddy_mock_selftests)
>  selftest(memory_region, intel_memory_region_mock_selftests)
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem
  2021-05-04 19:00     ` Daniel Vetter
@ 2021-05-05  9:28       ` Tvrtko Ursulin
  -1 siblings, 0 replies; 135+ messages in thread
From: Tvrtko Ursulin @ 2021-05-05  9:28 UTC (permalink / raw)
  To: Daniel Vetter, Jason Ekstrand; +Cc: intel-gfx, dri-devel


On 04/05/2021 20:00, Daniel Vetter wrote:
> On Mon, May 03, 2021 at 10:57:39AM -0500, Jason Ekstrand wrote:
>> For now this is a no-op because everyone passes in a null SSEU but it
>> lets us get some of the error handling and selftest refactoring plumbed
>> through.
>>
>> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> 
> it is a bit icky that intel_context_set_gem also sets the sseu, feels a
> bit like a layering violation, but welp I couldn't come up with a better
> idea either.
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

It is actually quite horrible. As you say it breaks separation of duties 
and open codes stuff all over the place without transferring over the 
commentary about why.

Regards,

Tvrtko

>> ---
>>   drivers/gpu/drm/i915/gem/i915_gem_context.c   | 41 +++++++++++++++----
>>   .../gpu/drm/i915/gem/selftests/mock_context.c |  6 ++-
>>   2 files changed, 36 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>> index ce729e640bbf7..6dd50d669c5b9 100644
>> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>> @@ -320,9 +320,12 @@ context_get_vm_rcu(struct i915_gem_context *ctx)
>>   	} while (1);
>>   }
>>   
>> -static void intel_context_set_gem(struct intel_context *ce,
>> -				  struct i915_gem_context *ctx)
>> +static int intel_context_set_gem(struct intel_context *ce,
>> +				 struct i915_gem_context *ctx,
>> +				 struct intel_sseu sseu)
>>   {
>> +	int ret = 0;
>> +
>>   	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
>>   	RCU_INIT_POINTER(ce->gem_context, ctx);
>>   
>> @@ -349,6 +352,12 @@ static void intel_context_set_gem(struct intel_context *ce,
>>   
>>   		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
>>   	}
>> +
>> +	/* A valid SSEU has no zero fields */
>> +	if (sseu.slice_mask && !WARN_ON(ce->engine->class != RENDER_CLASS))
>> +		ret = intel_context_reconfigure_sseu(ce, sseu);
>> +
>> +	return ret;
>>   }
>>   
>>   static void __free_engines(struct i915_gem_engines *e, unsigned int count)
>> @@ -416,7 +425,8 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
>>   	return e;
>>   }
>>   
>> -static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>> +static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
>> +						struct intel_sseu rcs_sseu)
>>   {
>>   	const struct intel_gt *gt = &ctx->i915->gt;
>>   	struct intel_engine_cs *engine;
>> @@ -429,6 +439,8 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>>   
>>   	for_each_engine(engine, gt, id) {
>>   		struct intel_context *ce;
>> +		struct intel_sseu sseu = {};
>> +		int ret;
>>   
>>   		if (engine->legacy_idx == INVALID_ENGINE)
>>   			continue;
>> @@ -442,10 +454,18 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>>   			goto free_engines;
>>   		}
>>   
>> -		intel_context_set_gem(ce, ctx);
>> -
>>   		e->engines[engine->legacy_idx] = ce;
>>   		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
>> +
>> +		if (engine->class == RENDER_CLASS)
>> +			sseu = rcs_sseu;
>> +
>> +		ret = intel_context_set_gem(ce, ctx, sseu);
>> +		if (ret) {
>> +			err = ERR_PTR(ret);
>> +			goto free_engines;
>> +		}
>> +
>>   	}
>>   
>>   	return e;
>> @@ -759,6 +779,7 @@ __create_context(struct drm_i915_private *i915,
>>   {
>>   	struct i915_gem_context *ctx;
>>   	struct i915_gem_engines *e;
>> +	struct intel_sseu null_sseu = {};
>>   	int err;
>>   	int i;
>>   
>> @@ -776,7 +797,7 @@ __create_context(struct drm_i915_private *i915,
>>   	INIT_LIST_HEAD(&ctx->stale.engines);
>>   
>>   	mutex_init(&ctx->engines_mutex);
>> -	e = default_engines(ctx);
>> +	e = default_engines(ctx, null_sseu);
>>   	if (IS_ERR(e)) {
>>   		err = PTR_ERR(e);
>>   		goto err_free;
>> @@ -1544,6 +1565,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>>   	struct intel_engine_cs *stack[16];
>>   	struct intel_engine_cs **siblings;
>>   	struct intel_context *ce;
>> +	struct intel_sseu null_sseu = {};
>>   	u16 num_siblings, idx;
>>   	unsigned int n;
>>   	int err;
>> @@ -1616,7 +1638,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>>   		goto out_siblings;
>>   	}
>>   
>> -	intel_context_set_gem(ce, set->ctx);
>> +	intel_context_set_gem(ce, set->ctx, null_sseu);
>>   
>>   	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
>>   		intel_context_put(ce);
>> @@ -1724,6 +1746,7 @@ set_engines(struct i915_gem_context *ctx,
>>   	struct drm_i915_private *i915 = ctx->i915;
>>   	struct i915_context_param_engines __user *user =
>>   		u64_to_user_ptr(args->value);
>> +	struct intel_sseu null_sseu = {};
>>   	struct set_engines set = { .ctx = ctx };
>>   	unsigned int num_engines, n;
>>   	u64 extensions;
>> @@ -1733,7 +1756,7 @@ set_engines(struct i915_gem_context *ctx,
>>   		if (!i915_gem_context_user_engines(ctx))
>>   			return 0;
>>   
>> -		set.engines = default_engines(ctx);
>> +		set.engines = default_engines(ctx, null_sseu);
>>   		if (IS_ERR(set.engines))
>>   			return PTR_ERR(set.engines);
>>   
>> @@ -1790,7 +1813,7 @@ set_engines(struct i915_gem_context *ctx,
>>   			return PTR_ERR(ce);
>>   		}
>>   
>> -		intel_context_set_gem(ce, ctx);
>> +		intel_context_set_gem(ce, ctx, null_sseu);
>>   
>>   		set.engines->engines[n] = ce;
>>   	}
>> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>> index e0f512ef7f3c6..cbeefd060e97b 100644
>> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>> @@ -14,6 +14,7 @@ mock_context(struct drm_i915_private *i915,
>>   {
>>   	struct i915_gem_context *ctx;
>>   	struct i915_gem_engines *e;
>> +	struct intel_sseu null_sseu = {};
>>   
>>   	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>>   	if (!ctx)
>> @@ -31,7 +32,7 @@ mock_context(struct drm_i915_private *i915,
>>   	i915_gem_context_set_persistence(ctx);
>>   
>>   	mutex_init(&ctx->engines_mutex);
>> -	e = default_engines(ctx);
>> +	e = default_engines(ctx, null_sseu);
>>   	if (IS_ERR(e))
>>   		goto err_free;
>>   	RCU_INIT_POINTER(ctx->engines, e);
>> @@ -112,6 +113,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>>   {
>>   	struct i915_gem_engines *engines;
>>   	struct i915_gem_context *ctx;
>> +	struct intel_sseu null_sseu = {};
>>   	struct intel_context *ce;
>>   
>>   	engines = alloc_engines(1);
>> @@ -130,7 +132,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>>   		return ERR_CAST(ce);
>>   	}
>>   
>> -	intel_context_set_gem(ce, ctx);
>> +	intel_context_set_gem(ce, ctx, null_sseu);
>>   	engines->engines[0] = ce;
>>   	engines->num_engines = 1;
>>   
>> -- 
>> 2.31.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem
@ 2021-05-05  9:28       ` Tvrtko Ursulin
  0 siblings, 0 replies; 135+ messages in thread
From: Tvrtko Ursulin @ 2021-05-05  9:28 UTC (permalink / raw)
  To: Daniel Vetter, Jason Ekstrand; +Cc: intel-gfx, dri-devel


On 04/05/2021 20:00, Daniel Vetter wrote:
> On Mon, May 03, 2021 at 10:57:39AM -0500, Jason Ekstrand wrote:
>> For now this is a no-op because everyone passes in a null SSEU but it
>> lets us get some of the error handling and selftest refactoring plumbed
>> through.
>>
>> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> 
> it is a bit icky that intel_context_set_gem also sets the sseu, feels a
> bit like a layering violation, but welp I couldn't come up with a better
> idea either.
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

It is actually quite horrible. As you say it breaks separation of duties 
and open codes stuff all over the place without transferring over the 
commentary about why.

Regards,

Tvrtko

>> ---
>>   drivers/gpu/drm/i915/gem/i915_gem_context.c   | 41 +++++++++++++++----
>>   .../gpu/drm/i915/gem/selftests/mock_context.c |  6 ++-
>>   2 files changed, 36 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>> index ce729e640bbf7..6dd50d669c5b9 100644
>> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>> @@ -320,9 +320,12 @@ context_get_vm_rcu(struct i915_gem_context *ctx)
>>   	} while (1);
>>   }
>>   
>> -static void intel_context_set_gem(struct intel_context *ce,
>> -				  struct i915_gem_context *ctx)
>> +static int intel_context_set_gem(struct intel_context *ce,
>> +				 struct i915_gem_context *ctx,
>> +				 struct intel_sseu sseu)
>>   {
>> +	int ret = 0;
>> +
>>   	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
>>   	RCU_INIT_POINTER(ce->gem_context, ctx);
>>   
>> @@ -349,6 +352,12 @@ static void intel_context_set_gem(struct intel_context *ce,
>>   
>>   		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
>>   	}
>> +
>> +	/* A valid SSEU has no zero fields */
>> +	if (sseu.slice_mask && !WARN_ON(ce->engine->class != RENDER_CLASS))
>> +		ret = intel_context_reconfigure_sseu(ce, sseu);
>> +
>> +	return ret;
>>   }
>>   
>>   static void __free_engines(struct i915_gem_engines *e, unsigned int count)
>> @@ -416,7 +425,8 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
>>   	return e;
>>   }
>>   
>> -static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>> +static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
>> +						struct intel_sseu rcs_sseu)
>>   {
>>   	const struct intel_gt *gt = &ctx->i915->gt;
>>   	struct intel_engine_cs *engine;
>> @@ -429,6 +439,8 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>>   
>>   	for_each_engine(engine, gt, id) {
>>   		struct intel_context *ce;
>> +		struct intel_sseu sseu = {};
>> +		int ret;
>>   
>>   		if (engine->legacy_idx == INVALID_ENGINE)
>>   			continue;
>> @@ -442,10 +454,18 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>>   			goto free_engines;
>>   		}
>>   
>> -		intel_context_set_gem(ce, ctx);
>> -
>>   		e->engines[engine->legacy_idx] = ce;
>>   		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
>> +
>> +		if (engine->class == RENDER_CLASS)
>> +			sseu = rcs_sseu;
>> +
>> +		ret = intel_context_set_gem(ce, ctx, sseu);
>> +		if (ret) {
>> +			err = ERR_PTR(ret);
>> +			goto free_engines;
>> +		}
>> +
>>   	}
>>   
>>   	return e;
>> @@ -759,6 +779,7 @@ __create_context(struct drm_i915_private *i915,
>>   {
>>   	struct i915_gem_context *ctx;
>>   	struct i915_gem_engines *e;
>> +	struct intel_sseu null_sseu = {};
>>   	int err;
>>   	int i;
>>   
>> @@ -776,7 +797,7 @@ __create_context(struct drm_i915_private *i915,
>>   	INIT_LIST_HEAD(&ctx->stale.engines);
>>   
>>   	mutex_init(&ctx->engines_mutex);
>> -	e = default_engines(ctx);
>> +	e = default_engines(ctx, null_sseu);
>>   	if (IS_ERR(e)) {
>>   		err = PTR_ERR(e);
>>   		goto err_free;
>> @@ -1544,6 +1565,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>>   	struct intel_engine_cs *stack[16];
>>   	struct intel_engine_cs **siblings;
>>   	struct intel_context *ce;
>> +	struct intel_sseu null_sseu = {};
>>   	u16 num_siblings, idx;
>>   	unsigned int n;
>>   	int err;
>> @@ -1616,7 +1638,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>>   		goto out_siblings;
>>   	}
>>   
>> -	intel_context_set_gem(ce, set->ctx);
>> +	intel_context_set_gem(ce, set->ctx, null_sseu);
>>   
>>   	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
>>   		intel_context_put(ce);
>> @@ -1724,6 +1746,7 @@ set_engines(struct i915_gem_context *ctx,
>>   	struct drm_i915_private *i915 = ctx->i915;
>>   	struct i915_context_param_engines __user *user =
>>   		u64_to_user_ptr(args->value);
>> +	struct intel_sseu null_sseu = {};
>>   	struct set_engines set = { .ctx = ctx };
>>   	unsigned int num_engines, n;
>>   	u64 extensions;
>> @@ -1733,7 +1756,7 @@ set_engines(struct i915_gem_context *ctx,
>>   		if (!i915_gem_context_user_engines(ctx))
>>   			return 0;
>>   
>> -		set.engines = default_engines(ctx);
>> +		set.engines = default_engines(ctx, null_sseu);
>>   		if (IS_ERR(set.engines))
>>   			return PTR_ERR(set.engines);
>>   
>> @@ -1790,7 +1813,7 @@ set_engines(struct i915_gem_context *ctx,
>>   			return PTR_ERR(ce);
>>   		}
>>   
>> -		intel_context_set_gem(ce, ctx);
>> +		intel_context_set_gem(ce, ctx, null_sseu);
>>   
>>   		set.engines->engines[n] = ce;
>>   	}
>> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>> index e0f512ef7f3c6..cbeefd060e97b 100644
>> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>> @@ -14,6 +14,7 @@ mock_context(struct drm_i915_private *i915,
>>   {
>>   	struct i915_gem_context *ctx;
>>   	struct i915_gem_engines *e;
>> +	struct intel_sseu null_sseu = {};
>>   
>>   	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>>   	if (!ctx)
>> @@ -31,7 +32,7 @@ mock_context(struct drm_i915_private *i915,
>>   	i915_gem_context_set_persistence(ctx);
>>   
>>   	mutex_init(&ctx->engines_mutex);
>> -	e = default_engines(ctx);
>> +	e = default_engines(ctx, null_sseu);
>>   	if (IS_ERR(e))
>>   		goto err_free;
>>   	RCU_INIT_POINTER(ctx->engines, e);
>> @@ -112,6 +113,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>>   {
>>   	struct i915_gem_engines *engines;
>>   	struct i915_gem_context *ctx;
>> +	struct intel_sseu null_sseu = {};
>>   	struct intel_context *ce;
>>   
>>   	engines = alloc_engines(1);
>> @@ -130,7 +132,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>>   		return ERR_CAST(ce);
>>   	}
>>   
>> -	intel_context_set_gem(ce, ctx);
>> +	intel_context_set_gem(ce, ctx, null_sseu);
>>   	engines->engines[0] = ce;
>>   	engines->num_engines = 1;
>>   
>> -- 
>> 2.31.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem
  2021-05-05  9:28       ` Tvrtko Ursulin
@ 2021-05-05  9:47         ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-05  9:47 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: dri-devel, intel-gfx, Jason Ekstrand

On Wed, May 05, 2021 at 10:28:59AM +0100, Tvrtko Ursulin wrote:
> 
> On 04/05/2021 20:00, Daniel Vetter wrote:
> > On Mon, May 03, 2021 at 10:57:39AM -0500, Jason Ekstrand wrote:
> > > For now this is a no-op because everyone passes in a null SSEU but it
> > > lets us get some of the error handling and selftest refactoring plumbed
> > > through.
> > > 
> > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > 
> > it is a bit icky that intel_context_set_gem also sets the sseu, feels a
> > bit like a layering violation, but welp I couldn't come up with a better
> > idea either.
> > 
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> It is actually quite horrible. As you say it breaks separation of duties and
> open codes stuff all over the place without transferring over the commentary
> about why.

I didn't really see lost commentary anywhere? Can you pls point out what
got lost?
-Daniel

> 
> Regards,
> 
> Tvrtko
> 
> > > ---
> > >   drivers/gpu/drm/i915/gem/i915_gem_context.c   | 41 +++++++++++++++----
> > >   .../gpu/drm/i915/gem/selftests/mock_context.c |  6 ++-
> > >   2 files changed, 36 insertions(+), 11 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > index ce729e640bbf7..6dd50d669c5b9 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > @@ -320,9 +320,12 @@ context_get_vm_rcu(struct i915_gem_context *ctx)
> > >   	} while (1);
> > >   }
> > > -static void intel_context_set_gem(struct intel_context *ce,
> > > -				  struct i915_gem_context *ctx)
> > > +static int intel_context_set_gem(struct intel_context *ce,
> > > +				 struct i915_gem_context *ctx,
> > > +				 struct intel_sseu sseu)
> > >   {
> > > +	int ret = 0;
> > > +
> > >   	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
> > >   	RCU_INIT_POINTER(ce->gem_context, ctx);
> > > @@ -349,6 +352,12 @@ static void intel_context_set_gem(struct intel_context *ce,
> > >   		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
> > >   	}
> > > +
> > > +	/* A valid SSEU has no zero fields */
> > > +	if (sseu.slice_mask && !WARN_ON(ce->engine->class != RENDER_CLASS))
> > > +		ret = intel_context_reconfigure_sseu(ce, sseu);
> > > +
> > > +	return ret;
> > >   }
> > >   static void __free_engines(struct i915_gem_engines *e, unsigned int count)
> > > @@ -416,7 +425,8 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
> > >   	return e;
> > >   }
> > > -static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> > > +static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> > > +						struct intel_sseu rcs_sseu)
> > >   {
> > >   	const struct intel_gt *gt = &ctx->i915->gt;
> > >   	struct intel_engine_cs *engine;
> > > @@ -429,6 +439,8 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> > >   	for_each_engine(engine, gt, id) {
> > >   		struct intel_context *ce;
> > > +		struct intel_sseu sseu = {};
> > > +		int ret;
> > >   		if (engine->legacy_idx == INVALID_ENGINE)
> > >   			continue;
> > > @@ -442,10 +454,18 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> > >   			goto free_engines;
> > >   		}
> > > -		intel_context_set_gem(ce, ctx);
> > > -
> > >   		e->engines[engine->legacy_idx] = ce;
> > >   		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
> > > +
> > > +		if (engine->class == RENDER_CLASS)
> > > +			sseu = rcs_sseu;
> > > +
> > > +		ret = intel_context_set_gem(ce, ctx, sseu);
> > > +		if (ret) {
> > > +			err = ERR_PTR(ret);
> > > +			goto free_engines;
> > > +		}
> > > +
> > >   	}
> > >   	return e;
> > > @@ -759,6 +779,7 @@ __create_context(struct drm_i915_private *i915,
> > >   {
> > >   	struct i915_gem_context *ctx;
> > >   	struct i915_gem_engines *e;
> > > +	struct intel_sseu null_sseu = {};
> > >   	int err;
> > >   	int i;
> > > @@ -776,7 +797,7 @@ __create_context(struct drm_i915_private *i915,
> > >   	INIT_LIST_HEAD(&ctx->stale.engines);
> > >   	mutex_init(&ctx->engines_mutex);
> > > -	e = default_engines(ctx);
> > > +	e = default_engines(ctx, null_sseu);
> > >   	if (IS_ERR(e)) {
> > >   		err = PTR_ERR(e);
> > >   		goto err_free;
> > > @@ -1544,6 +1565,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
> > >   	struct intel_engine_cs *stack[16];
> > >   	struct intel_engine_cs **siblings;
> > >   	struct intel_context *ce;
> > > +	struct intel_sseu null_sseu = {};
> > >   	u16 num_siblings, idx;
> > >   	unsigned int n;
> > >   	int err;
> > > @@ -1616,7 +1638,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
> > >   		goto out_siblings;
> > >   	}
> > > -	intel_context_set_gem(ce, set->ctx);
> > > +	intel_context_set_gem(ce, set->ctx, null_sseu);
> > >   	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
> > >   		intel_context_put(ce);
> > > @@ -1724,6 +1746,7 @@ set_engines(struct i915_gem_context *ctx,
> > >   	struct drm_i915_private *i915 = ctx->i915;
> > >   	struct i915_context_param_engines __user *user =
> > >   		u64_to_user_ptr(args->value);
> > > +	struct intel_sseu null_sseu = {};
> > >   	struct set_engines set = { .ctx = ctx };
> > >   	unsigned int num_engines, n;
> > >   	u64 extensions;
> > > @@ -1733,7 +1756,7 @@ set_engines(struct i915_gem_context *ctx,
> > >   		if (!i915_gem_context_user_engines(ctx))
> > >   			return 0;
> > > -		set.engines = default_engines(ctx);
> > > +		set.engines = default_engines(ctx, null_sseu);
> > >   		if (IS_ERR(set.engines))
> > >   			return PTR_ERR(set.engines);
> > > @@ -1790,7 +1813,7 @@ set_engines(struct i915_gem_context *ctx,
> > >   			return PTR_ERR(ce);
> > >   		}
> > > -		intel_context_set_gem(ce, ctx);
> > > +		intel_context_set_gem(ce, ctx, null_sseu);
> > >   		set.engines->engines[n] = ce;
> > >   	}
> > > diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > index e0f512ef7f3c6..cbeefd060e97b 100644
> > > --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > @@ -14,6 +14,7 @@ mock_context(struct drm_i915_private *i915,
> > >   {
> > >   	struct i915_gem_context *ctx;
> > >   	struct i915_gem_engines *e;
> > > +	struct intel_sseu null_sseu = {};
> > >   	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> > >   	if (!ctx)
> > > @@ -31,7 +32,7 @@ mock_context(struct drm_i915_private *i915,
> > >   	i915_gem_context_set_persistence(ctx);
> > >   	mutex_init(&ctx->engines_mutex);
> > > -	e = default_engines(ctx);
> > > +	e = default_engines(ctx, null_sseu);
> > >   	if (IS_ERR(e))
> > >   		goto err_free;
> > >   	RCU_INIT_POINTER(ctx->engines, e);
> > > @@ -112,6 +113,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
> > >   {
> > >   	struct i915_gem_engines *engines;
> > >   	struct i915_gem_context *ctx;
> > > +	struct intel_sseu null_sseu = {};
> > >   	struct intel_context *ce;
> > >   	engines = alloc_engines(1);
> > > @@ -130,7 +132,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
> > >   		return ERR_CAST(ce);
> > >   	}
> > > -	intel_context_set_gem(ce, ctx);
> > > +	intel_context_set_gem(ce, ctx, null_sseu);
> > >   	engines->engines[0] = ce;
> > >   	engines->num_engines = 1;
> > > -- 
> > > 2.31.1
> > > 
> > > _______________________________________________
> > > Intel-gfx mailing list
> > > Intel-gfx@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem
@ 2021-05-05  9:47         ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-05  9:47 UTC (permalink / raw)
  To: Tvrtko Ursulin; +Cc: dri-devel, intel-gfx

On Wed, May 05, 2021 at 10:28:59AM +0100, Tvrtko Ursulin wrote:
> 
> On 04/05/2021 20:00, Daniel Vetter wrote:
> > On Mon, May 03, 2021 at 10:57:39AM -0500, Jason Ekstrand wrote:
> > > For now this is a no-op because everyone passes in a null SSEU but it
> > > lets us get some of the error handling and selftest refactoring plumbed
> > > through.
> > > 
> > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > 
> > it is a bit icky that intel_context_set_gem also sets the sseu, feels a
> > bit like a layering violation, but welp I couldn't come up with a better
> > idea either.
> > 
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> It is actually quite horrible. As you say it breaks separation of duties and
> open codes stuff all over the place without transferring over the commentary
> about why.

I didn't really see lost commentary anywhere? Can you pls point out what
got lost?
-Daniel

> 
> Regards,
> 
> Tvrtko
> 
> > > ---
> > >   drivers/gpu/drm/i915/gem/i915_gem_context.c   | 41 +++++++++++++++----
> > >   .../gpu/drm/i915/gem/selftests/mock_context.c |  6 ++-
> > >   2 files changed, 36 insertions(+), 11 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > index ce729e640bbf7..6dd50d669c5b9 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > @@ -320,9 +320,12 @@ context_get_vm_rcu(struct i915_gem_context *ctx)
> > >   	} while (1);
> > >   }
> > > -static void intel_context_set_gem(struct intel_context *ce,
> > > -				  struct i915_gem_context *ctx)
> > > +static int intel_context_set_gem(struct intel_context *ce,
> > > +				 struct i915_gem_context *ctx,
> > > +				 struct intel_sseu sseu)
> > >   {
> > > +	int ret = 0;
> > > +
> > >   	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
> > >   	RCU_INIT_POINTER(ce->gem_context, ctx);
> > > @@ -349,6 +352,12 @@ static void intel_context_set_gem(struct intel_context *ce,
> > >   		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
> > >   	}
> > > +
> > > +	/* A valid SSEU has no zero fields */
> > > +	if (sseu.slice_mask && !WARN_ON(ce->engine->class != RENDER_CLASS))
> > > +		ret = intel_context_reconfigure_sseu(ce, sseu);
> > > +
> > > +	return ret;
> > >   }
> > >   static void __free_engines(struct i915_gem_engines *e, unsigned int count)
> > > @@ -416,7 +425,8 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
> > >   	return e;
> > >   }
> > > -static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> > > +static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> > > +						struct intel_sseu rcs_sseu)
> > >   {
> > >   	const struct intel_gt *gt = &ctx->i915->gt;
> > >   	struct intel_engine_cs *engine;
> > > @@ -429,6 +439,8 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> > >   	for_each_engine(engine, gt, id) {
> > >   		struct intel_context *ce;
> > > +		struct intel_sseu sseu = {};
> > > +		int ret;
> > >   		if (engine->legacy_idx == INVALID_ENGINE)
> > >   			continue;
> > > @@ -442,10 +454,18 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> > >   			goto free_engines;
> > >   		}
> > > -		intel_context_set_gem(ce, ctx);
> > > -
> > >   		e->engines[engine->legacy_idx] = ce;
> > >   		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
> > > +
> > > +		if (engine->class == RENDER_CLASS)
> > > +			sseu = rcs_sseu;
> > > +
> > > +		ret = intel_context_set_gem(ce, ctx, sseu);
> > > +		if (ret) {
> > > +			err = ERR_PTR(ret);
> > > +			goto free_engines;
> > > +		}
> > > +
> > >   	}
> > >   	return e;
> > > @@ -759,6 +779,7 @@ __create_context(struct drm_i915_private *i915,
> > >   {
> > >   	struct i915_gem_context *ctx;
> > >   	struct i915_gem_engines *e;
> > > +	struct intel_sseu null_sseu = {};
> > >   	int err;
> > >   	int i;
> > > @@ -776,7 +797,7 @@ __create_context(struct drm_i915_private *i915,
> > >   	INIT_LIST_HEAD(&ctx->stale.engines);
> > >   	mutex_init(&ctx->engines_mutex);
> > > -	e = default_engines(ctx);
> > > +	e = default_engines(ctx, null_sseu);
> > >   	if (IS_ERR(e)) {
> > >   		err = PTR_ERR(e);
> > >   		goto err_free;
> > > @@ -1544,6 +1565,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
> > >   	struct intel_engine_cs *stack[16];
> > >   	struct intel_engine_cs **siblings;
> > >   	struct intel_context *ce;
> > > +	struct intel_sseu null_sseu = {};
> > >   	u16 num_siblings, idx;
> > >   	unsigned int n;
> > >   	int err;
> > > @@ -1616,7 +1638,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
> > >   		goto out_siblings;
> > >   	}
> > > -	intel_context_set_gem(ce, set->ctx);
> > > +	intel_context_set_gem(ce, set->ctx, null_sseu);
> > >   	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
> > >   		intel_context_put(ce);
> > > @@ -1724,6 +1746,7 @@ set_engines(struct i915_gem_context *ctx,
> > >   	struct drm_i915_private *i915 = ctx->i915;
> > >   	struct i915_context_param_engines __user *user =
> > >   		u64_to_user_ptr(args->value);
> > > +	struct intel_sseu null_sseu = {};
> > >   	struct set_engines set = { .ctx = ctx };
> > >   	unsigned int num_engines, n;
> > >   	u64 extensions;
> > > @@ -1733,7 +1756,7 @@ set_engines(struct i915_gem_context *ctx,
> > >   		if (!i915_gem_context_user_engines(ctx))
> > >   			return 0;
> > > -		set.engines = default_engines(ctx);
> > > +		set.engines = default_engines(ctx, null_sseu);
> > >   		if (IS_ERR(set.engines))
> > >   			return PTR_ERR(set.engines);
> > > @@ -1790,7 +1813,7 @@ set_engines(struct i915_gem_context *ctx,
> > >   			return PTR_ERR(ce);
> > >   		}
> > > -		intel_context_set_gem(ce, ctx);
> > > +		intel_context_set_gem(ce, ctx, null_sseu);
> > >   		set.engines->engines[n] = ce;
> > >   	}
> > > diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > index e0f512ef7f3c6..cbeefd060e97b 100644
> > > --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > @@ -14,6 +14,7 @@ mock_context(struct drm_i915_private *i915,
> > >   {
> > >   	struct i915_gem_context *ctx;
> > >   	struct i915_gem_engines *e;
> > > +	struct intel_sseu null_sseu = {};
> > >   	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> > >   	if (!ctx)
> > > @@ -31,7 +32,7 @@ mock_context(struct drm_i915_private *i915,
> > >   	i915_gem_context_set_persistence(ctx);
> > >   	mutex_init(&ctx->engines_mutex);
> > > -	e = default_engines(ctx);
> > > +	e = default_engines(ctx, null_sseu);
> > >   	if (IS_ERR(e))
> > >   		goto err_free;
> > >   	RCU_INIT_POINTER(ctx->engines, e);
> > > @@ -112,6 +113,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
> > >   {
> > >   	struct i915_gem_engines *engines;
> > >   	struct i915_gem_context *ctx;
> > > +	struct intel_sseu null_sseu = {};
> > >   	struct intel_context *ce;
> > >   	engines = alloc_engines(1);
> > > @@ -130,7 +132,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
> > >   		return ERR_CAST(ce);
> > >   	}
> > > -	intel_context_set_gem(ce, ctx);
> > > +	intel_context_set_gem(ce, ctx, null_sseu);
> > >   	engines->engines[0] = ce;
> > >   	engines->num_engines = 1;
> > > -- 
> > > 2.31.1
> > > 
> > > _______________________________________________
> > > Intel-gfx mailing list
> > > Intel-gfx@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 24/27] drm/i915/gem: Don't allow changing the engine set on running contexts
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-05  9:49     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-05  9:49 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:45AM -0500, Jason Ekstrand wrote:
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Again needs some commit message, with that:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c | 304 --------------------
>  1 file changed, 304 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index ad6e98d8a4fbd..6e5828fe1a792 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1823,306 +1823,6 @@ static int set_sseu(struct i915_gem_context *ctx,
>  	return ret;
>  }
>  
> -struct set_engines {
> -	struct i915_gem_context *ctx;
> -	struct i915_gem_engines *engines;
> -};
> -
> -static int
> -set_engines__load_balance(struct i915_user_extension __user *base, void *data)
> -{
> -	struct i915_context_engines_load_balance __user *ext =
> -		container_of_user(base, typeof(*ext), base);
> -	const struct set_engines *set = data;
> -	struct drm_i915_private *i915 = set->ctx->i915;
> -	struct intel_engine_cs *stack[16];
> -	struct intel_engine_cs **siblings;
> -	struct intel_context *ce;
> -	struct intel_sseu null_sseu = {};
> -	u16 num_siblings, idx;
> -	unsigned int n;
> -	int err;
> -
> -	if (!HAS_EXECLISTS(i915))
> -		return -ENODEV;
> -
> -	if (intel_uc_uses_guc_submission(&i915->gt.uc))
> -		return -ENODEV; /* not implement yet */
> -
> -	if (get_user(idx, &ext->engine_index))
> -		return -EFAULT;
> -
> -	if (idx >= set->engines->num_engines) {
> -		drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> -			idx, set->engines->num_engines);
> -		return -EINVAL;
> -	}
> -
> -	idx = array_index_nospec(idx, set->engines->num_engines);
> -	if (set->engines->engines[idx]) {
> -		drm_dbg(&i915->drm,
> -			"Invalid placement[%d], already occupied\n", idx);
> -		return -EEXIST;
> -	}
> -
> -	if (get_user(num_siblings, &ext->num_siblings))
> -		return -EFAULT;
> -
> -	err = check_user_mbz(&ext->flags);
> -	if (err)
> -		return err;
> -
> -	err = check_user_mbz(&ext->mbz64);
> -	if (err)
> -		return err;
> -
> -	siblings = stack;
> -	if (num_siblings > ARRAY_SIZE(stack)) {
> -		siblings = kmalloc_array(num_siblings,
> -					 sizeof(*siblings),
> -					 GFP_KERNEL);
> -		if (!siblings)
> -			return -ENOMEM;
> -	}
> -
> -	for (n = 0; n < num_siblings; n++) {
> -		struct i915_engine_class_instance ci;
> -
> -		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> -			err = -EFAULT;
> -			goto out_siblings;
> -		}
> -
> -		siblings[n] = intel_engine_lookup_user(i915,
> -						       ci.engine_class,
> -						       ci.engine_instance);
> -		if (!siblings[n]) {
> -			drm_dbg(&i915->drm,
> -				"Invalid sibling[%d]: { class:%d, inst:%d }\n",
> -				n, ci.engine_class, ci.engine_instance);
> -			err = -EINVAL;
> -			goto out_siblings;
> -		}
> -	}
> -
> -	ce = intel_execlists_create_virtual(siblings, n);
> -	if (IS_ERR(ce)) {
> -		err = PTR_ERR(ce);
> -		goto out_siblings;
> -	}
> -
> -	intel_context_set_gem(ce, set->ctx, null_sseu);
> -
> -	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
> -		intel_context_put(ce);
> -		err = -EEXIST;
> -		goto out_siblings;
> -	}
> -
> -out_siblings:
> -	if (siblings != stack)
> -		kfree(siblings);
> -
> -	return err;
> -}
> -
> -static int
> -set_engines__bond(struct i915_user_extension __user *base, void *data)
> -{
> -	struct i915_context_engines_bond __user *ext =
> -		container_of_user(base, typeof(*ext), base);
> -	const struct set_engines *set = data;
> -	struct drm_i915_private *i915 = set->ctx->i915;
> -	struct i915_engine_class_instance ci;
> -	struct intel_engine_cs *virtual;
> -	struct intel_engine_cs *master;
> -	u16 idx, num_bonds;
> -	int err, n;
> -
> -	if (get_user(idx, &ext->virtual_index))
> -		return -EFAULT;
> -
> -	if (idx >= set->engines->num_engines) {
> -		drm_dbg(&i915->drm,
> -			"Invalid index for virtual engine: %d >= %d\n",
> -			idx, set->engines->num_engines);
> -		return -EINVAL;
> -	}
> -
> -	idx = array_index_nospec(idx, set->engines->num_engines);
> -	if (!set->engines->engines[idx]) {
> -		drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> -		return -EINVAL;
> -	}
> -	virtual = set->engines->engines[idx]->engine;
> -
> -	if (intel_engine_is_virtual(virtual)) {
> -		drm_dbg(&i915->drm,
> -			"Bonding with virtual engines not allowed\n");
> -		return -EINVAL;
> -	}
> -
> -	err = check_user_mbz(&ext->flags);
> -	if (err)
> -		return err;
> -
> -	for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> -		err = check_user_mbz(&ext->mbz64[n]);
> -		if (err)
> -			return err;
> -	}
> -
> -	if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> -		return -EFAULT;
> -
> -	master = intel_engine_lookup_user(i915,
> -					  ci.engine_class, ci.engine_instance);
> -	if (!master) {
> -		drm_dbg(&i915->drm,
> -			"Unrecognised master engine: { class:%u, instance:%u }\n",
> -			ci.engine_class, ci.engine_instance);
> -		return -EINVAL;
> -	}
> -
> -	if (get_user(num_bonds, &ext->num_bonds))
> -		return -EFAULT;
> -
> -	for (n = 0; n < num_bonds; n++) {
> -		struct intel_engine_cs *bond;
> -
> -		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> -			return -EFAULT;
> -
> -		bond = intel_engine_lookup_user(i915,
> -						ci.engine_class,
> -						ci.engine_instance);
> -		if (!bond) {
> -			drm_dbg(&i915->drm,
> -				"Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> -				n, ci.engine_class, ci.engine_instance);
> -			return -EINVAL;
> -		}
> -	}
> -
> -	return 0;
> -}
> -
> -static const i915_user_extension_fn set_engines__extensions[] = {
> -	[I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_engines__load_balance,
> -	[I915_CONTEXT_ENGINES_EXT_BOND] = set_engines__bond,
> -};
> -
> -static int
> -set_engines(struct i915_gem_context *ctx,
> -	    const struct drm_i915_gem_context_param *args)
> -{
> -	struct drm_i915_private *i915 = ctx->i915;
> -	struct i915_context_param_engines __user *user =
> -		u64_to_user_ptr(args->value);
> -	struct intel_sseu null_sseu = {};
> -	struct set_engines set = { .ctx = ctx };
> -	unsigned int num_engines, n;
> -	u64 extensions;
> -	int err;
> -
> -	if (!args->size) { /* switch back to legacy user_ring_map */
> -		if (!i915_gem_context_user_engines(ctx))
> -			return 0;
> -
> -		set.engines = default_engines(ctx, null_sseu);
> -		if (IS_ERR(set.engines))
> -			return PTR_ERR(set.engines);
> -
> -		goto replace;
> -	}
> -
> -	BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
> -	if (args->size < sizeof(*user) ||
> -	    !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> -		drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> -			args->size);
> -		return -EINVAL;
> -	}
> -
> -	num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> -	/* RING_MASK has no shift so we can use it directly here */
> -	if (num_engines > I915_EXEC_RING_MASK + 1)
> -		return -EINVAL;
> -
> -	set.engines = alloc_engines(num_engines);
> -	if (!set.engines)
> -		return -ENOMEM;
> -
> -	for (n = 0; n < num_engines; n++) {
> -		struct i915_engine_class_instance ci;
> -		struct intel_engine_cs *engine;
> -		struct intel_context *ce;
> -
> -		if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> -			__free_engines(set.engines, n);
> -			return -EFAULT;
> -		}
> -
> -		if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> -		    ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE) {
> -			set.engines->engines[n] = NULL;
> -			continue;
> -		}
> -
> -		engine = intel_engine_lookup_user(ctx->i915,
> -						  ci.engine_class,
> -						  ci.engine_instance);
> -		if (!engine) {
> -			drm_dbg(&i915->drm,
> -				"Invalid engine[%d]: { class:%d, instance:%d }\n",
> -				n, ci.engine_class, ci.engine_instance);
> -			__free_engines(set.engines, n);
> -			return -ENOENT;
> -		}
> -
> -		ce = intel_context_create(engine);
> -		if (IS_ERR(ce)) {
> -			__free_engines(set.engines, n);
> -			return PTR_ERR(ce);
> -		}
> -
> -		intel_context_set_gem(ce, ctx, null_sseu);
> -
> -		set.engines->engines[n] = ce;
> -	}
> -	set.engines->num_engines = num_engines;
> -
> -	err = -EFAULT;
> -	if (!get_user(extensions, &user->extensions))
> -		err = i915_user_extensions(u64_to_user_ptr(extensions),
> -					   set_engines__extensions,
> -					   ARRAY_SIZE(set_engines__extensions),
> -					   &set);
> -	if (err) {
> -		free_engines(set.engines);
> -		return err;
> -	}
> -
> -replace:
> -	mutex_lock(&ctx->engines_mutex);
> -	if (i915_gem_context_is_closed(ctx)) {
> -		mutex_unlock(&ctx->engines_mutex);
> -		free_engines(set.engines);
> -		return -ENOENT;
> -	}
> -	if (args->size)
> -		i915_gem_context_set_user_engines(ctx);
> -	else
> -		i915_gem_context_clear_user_engines(ctx);
> -	set.engines = rcu_replace_pointer(ctx->engines, set.engines, 1);
> -	mutex_unlock(&ctx->engines_mutex);
> -
> -	/* Keep track of old engine sets for kill_context() */
> -	engines_idle_release(ctx, set.engines);
> -
> -	return 0;
> -}
> -
>  static int
>  set_persistence(struct i915_gem_context *ctx,
>  		const struct drm_i915_gem_context_param *args)
> @@ -2205,10 +1905,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>  		ret = set_sseu(ctx, args);
>  		break;
>  
> -	case I915_CONTEXT_PARAM_ENGINES:
> -		ret = set_engines(ctx, args);
> -		break;
> -
>  	case I915_CONTEXT_PARAM_PERSISTENCE:
>  		ret = set_persistence(ctx, args);
>  		break;
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 24/27] drm/i915/gem: Don't allow changing the engine set on running contexts
@ 2021-05-05  9:49     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-05  9:49 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:45AM -0500, Jason Ekstrand wrote:
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Again needs some commit message, with that:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c | 304 --------------------
>  1 file changed, 304 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index ad6e98d8a4fbd..6e5828fe1a792 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1823,306 +1823,6 @@ static int set_sseu(struct i915_gem_context *ctx,
>  	return ret;
>  }
>  
> -struct set_engines {
> -	struct i915_gem_context *ctx;
> -	struct i915_gem_engines *engines;
> -};
> -
> -static int
> -set_engines__load_balance(struct i915_user_extension __user *base, void *data)
> -{
> -	struct i915_context_engines_load_balance __user *ext =
> -		container_of_user(base, typeof(*ext), base);
> -	const struct set_engines *set = data;
> -	struct drm_i915_private *i915 = set->ctx->i915;
> -	struct intel_engine_cs *stack[16];
> -	struct intel_engine_cs **siblings;
> -	struct intel_context *ce;
> -	struct intel_sseu null_sseu = {};
> -	u16 num_siblings, idx;
> -	unsigned int n;
> -	int err;
> -
> -	if (!HAS_EXECLISTS(i915))
> -		return -ENODEV;
> -
> -	if (intel_uc_uses_guc_submission(&i915->gt.uc))
> -		return -ENODEV; /* not implement yet */
> -
> -	if (get_user(idx, &ext->engine_index))
> -		return -EFAULT;
> -
> -	if (idx >= set->engines->num_engines) {
> -		drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> -			idx, set->engines->num_engines);
> -		return -EINVAL;
> -	}
> -
> -	idx = array_index_nospec(idx, set->engines->num_engines);
> -	if (set->engines->engines[idx]) {
> -		drm_dbg(&i915->drm,
> -			"Invalid placement[%d], already occupied\n", idx);
> -		return -EEXIST;
> -	}
> -
> -	if (get_user(num_siblings, &ext->num_siblings))
> -		return -EFAULT;
> -
> -	err = check_user_mbz(&ext->flags);
> -	if (err)
> -		return err;
> -
> -	err = check_user_mbz(&ext->mbz64);
> -	if (err)
> -		return err;
> -
> -	siblings = stack;
> -	if (num_siblings > ARRAY_SIZE(stack)) {
> -		siblings = kmalloc_array(num_siblings,
> -					 sizeof(*siblings),
> -					 GFP_KERNEL);
> -		if (!siblings)
> -			return -ENOMEM;
> -	}
> -
> -	for (n = 0; n < num_siblings; n++) {
> -		struct i915_engine_class_instance ci;
> -
> -		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> -			err = -EFAULT;
> -			goto out_siblings;
> -		}
> -
> -		siblings[n] = intel_engine_lookup_user(i915,
> -						       ci.engine_class,
> -						       ci.engine_instance);
> -		if (!siblings[n]) {
> -			drm_dbg(&i915->drm,
> -				"Invalid sibling[%d]: { class:%d, inst:%d }\n",
> -				n, ci.engine_class, ci.engine_instance);
> -			err = -EINVAL;
> -			goto out_siblings;
> -		}
> -	}
> -
> -	ce = intel_execlists_create_virtual(siblings, n);
> -	if (IS_ERR(ce)) {
> -		err = PTR_ERR(ce);
> -		goto out_siblings;
> -	}
> -
> -	intel_context_set_gem(ce, set->ctx, null_sseu);
> -
> -	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
> -		intel_context_put(ce);
> -		err = -EEXIST;
> -		goto out_siblings;
> -	}
> -
> -out_siblings:
> -	if (siblings != stack)
> -		kfree(siblings);
> -
> -	return err;
> -}
> -
> -static int
> -set_engines__bond(struct i915_user_extension __user *base, void *data)
> -{
> -	struct i915_context_engines_bond __user *ext =
> -		container_of_user(base, typeof(*ext), base);
> -	const struct set_engines *set = data;
> -	struct drm_i915_private *i915 = set->ctx->i915;
> -	struct i915_engine_class_instance ci;
> -	struct intel_engine_cs *virtual;
> -	struct intel_engine_cs *master;
> -	u16 idx, num_bonds;
> -	int err, n;
> -
> -	if (get_user(idx, &ext->virtual_index))
> -		return -EFAULT;
> -
> -	if (idx >= set->engines->num_engines) {
> -		drm_dbg(&i915->drm,
> -			"Invalid index for virtual engine: %d >= %d\n",
> -			idx, set->engines->num_engines);
> -		return -EINVAL;
> -	}
> -
> -	idx = array_index_nospec(idx, set->engines->num_engines);
> -	if (!set->engines->engines[idx]) {
> -		drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> -		return -EINVAL;
> -	}
> -	virtual = set->engines->engines[idx]->engine;
> -
> -	if (intel_engine_is_virtual(virtual)) {
> -		drm_dbg(&i915->drm,
> -			"Bonding with virtual engines not allowed\n");
> -		return -EINVAL;
> -	}
> -
> -	err = check_user_mbz(&ext->flags);
> -	if (err)
> -		return err;
> -
> -	for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> -		err = check_user_mbz(&ext->mbz64[n]);
> -		if (err)
> -			return err;
> -	}
> -
> -	if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> -		return -EFAULT;
> -
> -	master = intel_engine_lookup_user(i915,
> -					  ci.engine_class, ci.engine_instance);
> -	if (!master) {
> -		drm_dbg(&i915->drm,
> -			"Unrecognised master engine: { class:%u, instance:%u }\n",
> -			ci.engine_class, ci.engine_instance);
> -		return -EINVAL;
> -	}
> -
> -	if (get_user(num_bonds, &ext->num_bonds))
> -		return -EFAULT;
> -
> -	for (n = 0; n < num_bonds; n++) {
> -		struct intel_engine_cs *bond;
> -
> -		if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> -			return -EFAULT;
> -
> -		bond = intel_engine_lookup_user(i915,
> -						ci.engine_class,
> -						ci.engine_instance);
> -		if (!bond) {
> -			drm_dbg(&i915->drm,
> -				"Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> -				n, ci.engine_class, ci.engine_instance);
> -			return -EINVAL;
> -		}
> -	}
> -
> -	return 0;
> -}
> -
> -static const i915_user_extension_fn set_engines__extensions[] = {
> -	[I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_engines__load_balance,
> -	[I915_CONTEXT_ENGINES_EXT_BOND] = set_engines__bond,
> -};
> -
> -static int
> -set_engines(struct i915_gem_context *ctx,
> -	    const struct drm_i915_gem_context_param *args)
> -{
> -	struct drm_i915_private *i915 = ctx->i915;
> -	struct i915_context_param_engines __user *user =
> -		u64_to_user_ptr(args->value);
> -	struct intel_sseu null_sseu = {};
> -	struct set_engines set = { .ctx = ctx };
> -	unsigned int num_engines, n;
> -	u64 extensions;
> -	int err;
> -
> -	if (!args->size) { /* switch back to legacy user_ring_map */
> -		if (!i915_gem_context_user_engines(ctx))
> -			return 0;
> -
> -		set.engines = default_engines(ctx, null_sseu);
> -		if (IS_ERR(set.engines))
> -			return PTR_ERR(set.engines);
> -
> -		goto replace;
> -	}
> -
> -	BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
> -	if (args->size < sizeof(*user) ||
> -	    !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> -		drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> -			args->size);
> -		return -EINVAL;
> -	}
> -
> -	num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> -	/* RING_MASK has no shift so we can use it directly here */
> -	if (num_engines > I915_EXEC_RING_MASK + 1)
> -		return -EINVAL;
> -
> -	set.engines = alloc_engines(num_engines);
> -	if (!set.engines)
> -		return -ENOMEM;
> -
> -	for (n = 0; n < num_engines; n++) {
> -		struct i915_engine_class_instance ci;
> -		struct intel_engine_cs *engine;
> -		struct intel_context *ce;
> -
> -		if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> -			__free_engines(set.engines, n);
> -			return -EFAULT;
> -		}
> -
> -		if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> -		    ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE) {
> -			set.engines->engines[n] = NULL;
> -			continue;
> -		}
> -
> -		engine = intel_engine_lookup_user(ctx->i915,
> -						  ci.engine_class,
> -						  ci.engine_instance);
> -		if (!engine) {
> -			drm_dbg(&i915->drm,
> -				"Invalid engine[%d]: { class:%d, instance:%d }\n",
> -				n, ci.engine_class, ci.engine_instance);
> -			__free_engines(set.engines, n);
> -			return -ENOENT;
> -		}
> -
> -		ce = intel_context_create(engine);
> -		if (IS_ERR(ce)) {
> -			__free_engines(set.engines, n);
> -			return PTR_ERR(ce);
> -		}
> -
> -		intel_context_set_gem(ce, ctx, null_sseu);
> -
> -		set.engines->engines[n] = ce;
> -	}
> -	set.engines->num_engines = num_engines;
> -
> -	err = -EFAULT;
> -	if (!get_user(extensions, &user->extensions))
> -		err = i915_user_extensions(u64_to_user_ptr(extensions),
> -					   set_engines__extensions,
> -					   ARRAY_SIZE(set_engines__extensions),
> -					   &set);
> -	if (err) {
> -		free_engines(set.engines);
> -		return err;
> -	}
> -
> -replace:
> -	mutex_lock(&ctx->engines_mutex);
> -	if (i915_gem_context_is_closed(ctx)) {
> -		mutex_unlock(&ctx->engines_mutex);
> -		free_engines(set.engines);
> -		return -ENOENT;
> -	}
> -	if (args->size)
> -		i915_gem_context_set_user_engines(ctx);
> -	else
> -		i915_gem_context_clear_user_engines(ctx);
> -	set.engines = rcu_replace_pointer(ctx->engines, set.engines, 1);
> -	mutex_unlock(&ctx->engines_mutex);
> -
> -	/* Keep track of old engine sets for kill_context() */
> -	engines_idle_release(ctx, set.engines);
> -
> -	return 0;
> -}
> -
>  static int
>  set_persistence(struct i915_gem_context *ctx,
>  		const struct drm_i915_gem_context_param *args)
> @@ -2205,10 +1905,6 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
>  		ret = set_sseu(ctx, args);
>  		break;
>  
> -	case I915_CONTEXT_PARAM_ENGINES:
> -		ret = set_engines(ctx, args);
> -		break;
> -
>  	case I915_CONTEXT_PARAM_PERSISTENCE:
>  		ret = set_persistence(ctx, args);
>  		break;
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 25/27] drm/i915/selftests: Take a VM in kernel_context()
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-05  9:50     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-05  9:50 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:46AM -0500, Jason Ekstrand wrote:
> This better models where we want to go with contexts in general where
> things like the VM and engine set are create parameters instead of being
> set after the fact.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Looks reasonable.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  .../drm/i915/gem/selftests/i915_gem_context.c |  4 ++--
>  .../gpu/drm/i915/gem/selftests/mock_context.c |  9 ++++++++-
>  .../gpu/drm/i915/gem/selftests/mock_context.h |  4 +++-
>  drivers/gpu/drm/i915/gt/selftest_execlists.c  | 20 +++++++++----------
>  drivers/gpu/drm/i915/gt/selftest_hangcheck.c  |  2 +-
>  5 files changed, 24 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> index 16ff64ab34a1b..76029d7143f6c 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> @@ -680,7 +680,7 @@ static int igt_ctx_exec(void *arg)
>  			struct i915_gem_context *ctx;
>  			struct intel_context *ce;
>  
> -			ctx = kernel_context(i915);
> +			ctx = kernel_context(i915, NULL);
>  			if (IS_ERR(ctx)) {
>  				err = PTR_ERR(ctx);
>  				goto out_file;
> @@ -813,7 +813,7 @@ static int igt_shared_ctx_exec(void *arg)
>  			struct i915_gem_context *ctx;
>  			struct intel_context *ce;
>  
> -			ctx = kernel_context(i915);
> +			ctx = kernel_context(i915, NULL);
>  			if (IS_ERR(ctx)) {
>  				err = PTR_ERR(ctx);
>  				goto out_test;
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index 61aaac4a334cf..500ef27ba4771 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -150,7 +150,8 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>  }
>  
>  struct i915_gem_context *
> -kernel_context(struct drm_i915_private *i915)
> +kernel_context(struct drm_i915_private *i915,
> +	       struct i915_address_space *vm)
>  {
>  	struct i915_gem_context *ctx;
>  	struct i915_gem_proto_context *pc;
> @@ -159,6 +160,12 @@ kernel_context(struct drm_i915_private *i915)
>  	if (IS_ERR(pc))
>  		return ERR_CAST(pc);
>  
> +	if (vm) {
> +		if (pc->vm)
> +			i915_vm_put(pc->vm);
> +		pc->vm = i915_vm_get(vm);
> +	}
> +
>  	ctx = i915_gem_create_context(i915, pc);
>  	proto_context_close(pc);
>  	if (IS_ERR(ctx))
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.h b/drivers/gpu/drm/i915/gem/selftests/mock_context.h
> index 2a6121d33352d..7a02fd9b5866a 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.h
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.h
> @@ -10,6 +10,7 @@
>  struct file;
>  struct drm_i915_private;
>  struct intel_engine_cs;
> +struct i915_address_space;
>  
>  void mock_init_contexts(struct drm_i915_private *i915);
>  
> @@ -25,7 +26,8 @@ live_context(struct drm_i915_private *i915, struct file *file);
>  struct i915_gem_context *
>  live_context_for_engine(struct intel_engine_cs *engine, struct file *file);
>  
> -struct i915_gem_context *kernel_context(struct drm_i915_private *i915);
> +struct i915_gem_context *kernel_context(struct drm_i915_private *i915,
> +					struct i915_address_space *vm);
>  void kernel_context_close(struct i915_gem_context *ctx);
>  
>  #endif /* !__MOCK_CONTEXT_H */
> diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> index a0e75b71a3374..0989e024f7a03 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> @@ -1522,12 +1522,12 @@ static int live_busywait_preempt(void *arg)
>  	 * preempt the busywaits used to synchronise between rings.
>  	 */
>  
> -	ctx_hi = kernel_context(gt->i915);
> +	ctx_hi = kernel_context(gt->i915, NULL);
>  	if (!ctx_hi)
>  		return -ENOMEM;
>  	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
>  
> -	ctx_lo = kernel_context(gt->i915);
> +	ctx_lo = kernel_context(gt->i915, NULL);
>  	if (!ctx_lo)
>  		goto err_ctx_hi;
>  	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
> @@ -1724,12 +1724,12 @@ static int live_preempt(void *arg)
>  	if (igt_spinner_init(&spin_lo, gt))
>  		goto err_spin_hi;
>  
> -	ctx_hi = kernel_context(gt->i915);
> +	ctx_hi = kernel_context(gt->i915, NULL);
>  	if (!ctx_hi)
>  		goto err_spin_lo;
>  	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
>  
> -	ctx_lo = kernel_context(gt->i915);
> +	ctx_lo = kernel_context(gt->i915, NULL);
>  	if (!ctx_lo)
>  		goto err_ctx_hi;
>  	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
> @@ -1816,11 +1816,11 @@ static int live_late_preempt(void *arg)
>  	if (igt_spinner_init(&spin_lo, gt))
>  		goto err_spin_hi;
>  
> -	ctx_hi = kernel_context(gt->i915);
> +	ctx_hi = kernel_context(gt->i915, NULL);
>  	if (!ctx_hi)
>  		goto err_spin_lo;
>  
> -	ctx_lo = kernel_context(gt->i915);
> +	ctx_lo = kernel_context(gt->i915, NULL);
>  	if (!ctx_lo)
>  		goto err_ctx_hi;
>  
> @@ -1910,7 +1910,7 @@ struct preempt_client {
>  
>  static int preempt_client_init(struct intel_gt *gt, struct preempt_client *c)
>  {
> -	c->ctx = kernel_context(gt->i915);
> +	c->ctx = kernel_context(gt->i915, NULL);
>  	if (!c->ctx)
>  		return -ENOMEM;
>  
> @@ -3367,12 +3367,12 @@ static int live_preempt_timeout(void *arg)
>  	if (igt_spinner_init(&spin_lo, gt))
>  		return -ENOMEM;
>  
> -	ctx_hi = kernel_context(gt->i915);
> +	ctx_hi = kernel_context(gt->i915, NULL);
>  	if (!ctx_hi)
>  		goto err_spin_lo;
>  	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
>  
> -	ctx_lo = kernel_context(gt->i915);
> +	ctx_lo = kernel_context(gt->i915, NULL);
>  	if (!ctx_lo)
>  		goto err_ctx_hi;
>  	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
> @@ -3659,7 +3659,7 @@ static int live_preempt_smoke(void *arg)
>  	}
>  
>  	for (n = 0; n < smoke.ncontext; n++) {
> -		smoke.contexts[n] = kernel_context(smoke.gt->i915);
> +		smoke.contexts[n] = kernel_context(smoke.gt->i915, NULL);
>  		if (!smoke.contexts[n])
>  			goto err_ctx;
>  	}
> diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
> index 746985971c3a6..3676eaf6b2aee 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
> @@ -42,7 +42,7 @@ static int hang_init(struct hang *h, struct intel_gt *gt)
>  	memset(h, 0, sizeof(*h));
>  	h->gt = gt;
>  
> -	h->ctx = kernel_context(gt->i915);
> +	h->ctx = kernel_context(gt->i915, NULL);
>  	if (IS_ERR(h->ctx))
>  		return PTR_ERR(h->ctx);
>  
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 25/27] drm/i915/selftests: Take a VM in kernel_context()
@ 2021-05-05  9:50     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-05  9:50 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:46AM -0500, Jason Ekstrand wrote:
> This better models where we want to go with contexts in general where
> things like the VM and engine set are create parameters instead of being
> set after the fact.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Looks reasonable.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  .../drm/i915/gem/selftests/i915_gem_context.c |  4 ++--
>  .../gpu/drm/i915/gem/selftests/mock_context.c |  9 ++++++++-
>  .../gpu/drm/i915/gem/selftests/mock_context.h |  4 +++-
>  drivers/gpu/drm/i915/gt/selftest_execlists.c  | 20 +++++++++----------
>  drivers/gpu/drm/i915/gt/selftest_hangcheck.c  |  2 +-
>  5 files changed, 24 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> index 16ff64ab34a1b..76029d7143f6c 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> @@ -680,7 +680,7 @@ static int igt_ctx_exec(void *arg)
>  			struct i915_gem_context *ctx;
>  			struct intel_context *ce;
>  
> -			ctx = kernel_context(i915);
> +			ctx = kernel_context(i915, NULL);
>  			if (IS_ERR(ctx)) {
>  				err = PTR_ERR(ctx);
>  				goto out_file;
> @@ -813,7 +813,7 @@ static int igt_shared_ctx_exec(void *arg)
>  			struct i915_gem_context *ctx;
>  			struct intel_context *ce;
>  
> -			ctx = kernel_context(i915);
> +			ctx = kernel_context(i915, NULL);
>  			if (IS_ERR(ctx)) {
>  				err = PTR_ERR(ctx);
>  				goto out_test;
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index 61aaac4a334cf..500ef27ba4771 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -150,7 +150,8 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>  }
>  
>  struct i915_gem_context *
> -kernel_context(struct drm_i915_private *i915)
> +kernel_context(struct drm_i915_private *i915,
> +	       struct i915_address_space *vm)
>  {
>  	struct i915_gem_context *ctx;
>  	struct i915_gem_proto_context *pc;
> @@ -159,6 +160,12 @@ kernel_context(struct drm_i915_private *i915)
>  	if (IS_ERR(pc))
>  		return ERR_CAST(pc);
>  
> +	if (vm) {
> +		if (pc->vm)
> +			i915_vm_put(pc->vm);
> +		pc->vm = i915_vm_get(vm);
> +	}
> +
>  	ctx = i915_gem_create_context(i915, pc);
>  	proto_context_close(pc);
>  	if (IS_ERR(ctx))
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.h b/drivers/gpu/drm/i915/gem/selftests/mock_context.h
> index 2a6121d33352d..7a02fd9b5866a 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.h
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.h
> @@ -10,6 +10,7 @@
>  struct file;
>  struct drm_i915_private;
>  struct intel_engine_cs;
> +struct i915_address_space;
>  
>  void mock_init_contexts(struct drm_i915_private *i915);
>  
> @@ -25,7 +26,8 @@ live_context(struct drm_i915_private *i915, struct file *file);
>  struct i915_gem_context *
>  live_context_for_engine(struct intel_engine_cs *engine, struct file *file);
>  
> -struct i915_gem_context *kernel_context(struct drm_i915_private *i915);
> +struct i915_gem_context *kernel_context(struct drm_i915_private *i915,
> +					struct i915_address_space *vm);
>  void kernel_context_close(struct i915_gem_context *ctx);
>  
>  #endif /* !__MOCK_CONTEXT_H */
> diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> index a0e75b71a3374..0989e024f7a03 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> @@ -1522,12 +1522,12 @@ static int live_busywait_preempt(void *arg)
>  	 * preempt the busywaits used to synchronise between rings.
>  	 */
>  
> -	ctx_hi = kernel_context(gt->i915);
> +	ctx_hi = kernel_context(gt->i915, NULL);
>  	if (!ctx_hi)
>  		return -ENOMEM;
>  	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
>  
> -	ctx_lo = kernel_context(gt->i915);
> +	ctx_lo = kernel_context(gt->i915, NULL);
>  	if (!ctx_lo)
>  		goto err_ctx_hi;
>  	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
> @@ -1724,12 +1724,12 @@ static int live_preempt(void *arg)
>  	if (igt_spinner_init(&spin_lo, gt))
>  		goto err_spin_hi;
>  
> -	ctx_hi = kernel_context(gt->i915);
> +	ctx_hi = kernel_context(gt->i915, NULL);
>  	if (!ctx_hi)
>  		goto err_spin_lo;
>  	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
>  
> -	ctx_lo = kernel_context(gt->i915);
> +	ctx_lo = kernel_context(gt->i915, NULL);
>  	if (!ctx_lo)
>  		goto err_ctx_hi;
>  	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
> @@ -1816,11 +1816,11 @@ static int live_late_preempt(void *arg)
>  	if (igt_spinner_init(&spin_lo, gt))
>  		goto err_spin_hi;
>  
> -	ctx_hi = kernel_context(gt->i915);
> +	ctx_hi = kernel_context(gt->i915, NULL);
>  	if (!ctx_hi)
>  		goto err_spin_lo;
>  
> -	ctx_lo = kernel_context(gt->i915);
> +	ctx_lo = kernel_context(gt->i915, NULL);
>  	if (!ctx_lo)
>  		goto err_ctx_hi;
>  
> @@ -1910,7 +1910,7 @@ struct preempt_client {
>  
>  static int preempt_client_init(struct intel_gt *gt, struct preempt_client *c)
>  {
> -	c->ctx = kernel_context(gt->i915);
> +	c->ctx = kernel_context(gt->i915, NULL);
>  	if (!c->ctx)
>  		return -ENOMEM;
>  
> @@ -3367,12 +3367,12 @@ static int live_preempt_timeout(void *arg)
>  	if (igt_spinner_init(&spin_lo, gt))
>  		return -ENOMEM;
>  
> -	ctx_hi = kernel_context(gt->i915);
> +	ctx_hi = kernel_context(gt->i915, NULL);
>  	if (!ctx_hi)
>  		goto err_spin_lo;
>  	ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
>  
> -	ctx_lo = kernel_context(gt->i915);
> +	ctx_lo = kernel_context(gt->i915, NULL);
>  	if (!ctx_lo)
>  		goto err_ctx_hi;
>  	ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
> @@ -3659,7 +3659,7 @@ static int live_preempt_smoke(void *arg)
>  	}
>  
>  	for (n = 0; n < smoke.ncontext; n++) {
> -		smoke.contexts[n] = kernel_context(smoke.gt->i915);
> +		smoke.contexts[n] = kernel_context(smoke.gt->i915, NULL);
>  		if (!smoke.contexts[n])
>  			goto err_ctx;
>  	}
> diff --git a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
> index 746985971c3a6..3676eaf6b2aee 100644
> --- a/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
> +++ b/drivers/gpu/drm/i915/gt/selftest_hangcheck.c
> @@ -42,7 +42,7 @@ static int hang_init(struct hang *h, struct intel_gt *gt)
>  	memset(h, 0, sizeof(*h));
>  	h->gt = gt;
>  
> -	h->ctx = kernel_context(gt->i915);
> +	h->ctx = kernel_context(gt->i915, NULL);
>  	if (IS_ERR(h->ctx))
>  		return PTR_ERR(h->ctx);
>  
> -- 
> 2.31.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem
  2021-05-05  9:47         ` Daniel Vetter
@ 2021-05-05  9:52           ` Tvrtko Ursulin
  -1 siblings, 0 replies; 135+ messages in thread
From: Tvrtko Ursulin @ 2021-05-05  9:52 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel, Jason Ekstrand


On 05/05/2021 10:47, Daniel Vetter wrote:
> On Wed, May 05, 2021 at 10:28:59AM +0100, Tvrtko Ursulin wrote:
>>
>> On 04/05/2021 20:00, Daniel Vetter wrote:
>>> On Mon, May 03, 2021 at 10:57:39AM -0500, Jason Ekstrand wrote:
>>>> For now this is a no-op because everyone passes in a null SSEU but it
>>>> lets us get some of the error handling and selftest refactoring plumbed
>>>> through.
>>>>
>>>> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
>>>
>>> it is a bit icky that intel_context_set_gem also sets the sseu, feels a
>>> bit like a layering violation, but welp I couldn't come up with a better
>>> idea either.
>>>
>>> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>
>> It is actually quite horrible. As you say it breaks separation of duties and
>> open codes stuff all over the place without transferring over the commentary
>> about why.
> 
> I didn't really see lost commentary anywhere? Can you pls point out what
> got lost?

I glanced over two new places which check for RENDER_CLASS without any 
commentary while the existing code helpfully says:

	/* Only render engine supports RPCS configuration. */
	if (ce->engine->class != RENDER_CLASS) {
		ret = -ENODEV;
		goto out_ce;
	}

But really that is really just a symptom how mixed up the flows end up 
with this patch. In other words I am not suggesting those two new sites 
should have the same comment, just highlighting that the design is not good.

Regards,

Tvrtko

  -Daniel
> 
>>
>> Regards,
>>
>> Tvrtko
>>
>>>> ---
>>>>    drivers/gpu/drm/i915/gem/i915_gem_context.c   | 41 +++++++++++++++----
>>>>    .../gpu/drm/i915/gem/selftests/mock_context.c |  6 ++-
>>>>    2 files changed, 36 insertions(+), 11 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>>>> index ce729e640bbf7..6dd50d669c5b9 100644
>>>> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
>>>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>>>> @@ -320,9 +320,12 @@ context_get_vm_rcu(struct i915_gem_context *ctx)
>>>>    	} while (1);
>>>>    }
>>>> -static void intel_context_set_gem(struct intel_context *ce,
>>>> -				  struct i915_gem_context *ctx)
>>>> +static int intel_context_set_gem(struct intel_context *ce,
>>>> +				 struct i915_gem_context *ctx,
>>>> +				 struct intel_sseu sseu)
>>>>    {
>>>> +	int ret = 0;
>>>> +
>>>>    	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
>>>>    	RCU_INIT_POINTER(ce->gem_context, ctx);
>>>> @@ -349,6 +352,12 @@ static void intel_context_set_gem(struct intel_context *ce,
>>>>    		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
>>>>    	}
>>>> +
>>>> +	/* A valid SSEU has no zero fields */
>>>> +	if (sseu.slice_mask && !WARN_ON(ce->engine->class != RENDER_CLASS))
>>>> +		ret = intel_context_reconfigure_sseu(ce, sseu);
>>>> +
>>>> +	return ret;
>>>>    }
>>>>    static void __free_engines(struct i915_gem_engines *e, unsigned int count)
>>>> @@ -416,7 +425,8 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
>>>>    	return e;
>>>>    }
>>>> -static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>>>> +static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
>>>> +						struct intel_sseu rcs_sseu)
>>>>    {
>>>>    	const struct intel_gt *gt = &ctx->i915->gt;
>>>>    	struct intel_engine_cs *engine;
>>>> @@ -429,6 +439,8 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>>>>    	for_each_engine(engine, gt, id) {
>>>>    		struct intel_context *ce;
>>>> +		struct intel_sseu sseu = {};
>>>> +		int ret;
>>>>    		if (engine->legacy_idx == INVALID_ENGINE)
>>>>    			continue;
>>>> @@ -442,10 +454,18 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>>>>    			goto free_engines;
>>>>    		}
>>>> -		intel_context_set_gem(ce, ctx);
>>>> -
>>>>    		e->engines[engine->legacy_idx] = ce;
>>>>    		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
>>>> +
>>>> +		if (engine->class == RENDER_CLASS)
>>>> +			sseu = rcs_sseu;
>>>> +
>>>> +		ret = intel_context_set_gem(ce, ctx, sseu);
>>>> +		if (ret) {
>>>> +			err = ERR_PTR(ret);
>>>> +			goto free_engines;
>>>> +		}
>>>> +
>>>>    	}
>>>>    	return e;
>>>> @@ -759,6 +779,7 @@ __create_context(struct drm_i915_private *i915,
>>>>    {
>>>>    	struct i915_gem_context *ctx;
>>>>    	struct i915_gem_engines *e;
>>>> +	struct intel_sseu null_sseu = {};
>>>>    	int err;
>>>>    	int i;
>>>> @@ -776,7 +797,7 @@ __create_context(struct drm_i915_private *i915,
>>>>    	INIT_LIST_HEAD(&ctx->stale.engines);
>>>>    	mutex_init(&ctx->engines_mutex);
>>>> -	e = default_engines(ctx);
>>>> +	e = default_engines(ctx, null_sseu);
>>>>    	if (IS_ERR(e)) {
>>>>    		err = PTR_ERR(e);
>>>>    		goto err_free;
>>>> @@ -1544,6 +1565,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>>>>    	struct intel_engine_cs *stack[16];
>>>>    	struct intel_engine_cs **siblings;
>>>>    	struct intel_context *ce;
>>>> +	struct intel_sseu null_sseu = {};
>>>>    	u16 num_siblings, idx;
>>>>    	unsigned int n;
>>>>    	int err;
>>>> @@ -1616,7 +1638,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>>>>    		goto out_siblings;
>>>>    	}
>>>> -	intel_context_set_gem(ce, set->ctx);
>>>> +	intel_context_set_gem(ce, set->ctx, null_sseu);
>>>>    	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
>>>>    		intel_context_put(ce);
>>>> @@ -1724,6 +1746,7 @@ set_engines(struct i915_gem_context *ctx,
>>>>    	struct drm_i915_private *i915 = ctx->i915;
>>>>    	struct i915_context_param_engines __user *user =
>>>>    		u64_to_user_ptr(args->value);
>>>> +	struct intel_sseu null_sseu = {};
>>>>    	struct set_engines set = { .ctx = ctx };
>>>>    	unsigned int num_engines, n;
>>>>    	u64 extensions;
>>>> @@ -1733,7 +1756,7 @@ set_engines(struct i915_gem_context *ctx,
>>>>    		if (!i915_gem_context_user_engines(ctx))
>>>>    			return 0;
>>>> -		set.engines = default_engines(ctx);
>>>> +		set.engines = default_engines(ctx, null_sseu);
>>>>    		if (IS_ERR(set.engines))
>>>>    			return PTR_ERR(set.engines);
>>>> @@ -1790,7 +1813,7 @@ set_engines(struct i915_gem_context *ctx,
>>>>    			return PTR_ERR(ce);
>>>>    		}
>>>> -		intel_context_set_gem(ce, ctx);
>>>> +		intel_context_set_gem(ce, ctx, null_sseu);
>>>>    		set.engines->engines[n] = ce;
>>>>    	}
>>>> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>>>> index e0f512ef7f3c6..cbeefd060e97b 100644
>>>> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>>>> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>>>> @@ -14,6 +14,7 @@ mock_context(struct drm_i915_private *i915,
>>>>    {
>>>>    	struct i915_gem_context *ctx;
>>>>    	struct i915_gem_engines *e;
>>>> +	struct intel_sseu null_sseu = {};
>>>>    	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>>>>    	if (!ctx)
>>>> @@ -31,7 +32,7 @@ mock_context(struct drm_i915_private *i915,
>>>>    	i915_gem_context_set_persistence(ctx);
>>>>    	mutex_init(&ctx->engines_mutex);
>>>> -	e = default_engines(ctx);
>>>> +	e = default_engines(ctx, null_sseu);
>>>>    	if (IS_ERR(e))
>>>>    		goto err_free;
>>>>    	RCU_INIT_POINTER(ctx->engines, e);
>>>> @@ -112,6 +113,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>>>>    {
>>>>    	struct i915_gem_engines *engines;
>>>>    	struct i915_gem_context *ctx;
>>>> +	struct intel_sseu null_sseu = {};
>>>>    	struct intel_context *ce;
>>>>    	engines = alloc_engines(1);
>>>> @@ -130,7 +132,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>>>>    		return ERR_CAST(ce);
>>>>    	}
>>>> -	intel_context_set_gem(ce, ctx);
>>>> +	intel_context_set_gem(ce, ctx, null_sseu);
>>>>    	engines->engines[0] = ce;
>>>>    	engines->num_engines = 1;
>>>> -- 
>>>> 2.31.1
>>>>
>>>> _______________________________________________
>>>> Intel-gfx mailing list
>>>> Intel-gfx@lists.freedesktop.org
>>>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem
@ 2021-05-05  9:52           ` Tvrtko Ursulin
  0 siblings, 0 replies; 135+ messages in thread
From: Tvrtko Ursulin @ 2021-05-05  9:52 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx, dri-devel


On 05/05/2021 10:47, Daniel Vetter wrote:
> On Wed, May 05, 2021 at 10:28:59AM +0100, Tvrtko Ursulin wrote:
>>
>> On 04/05/2021 20:00, Daniel Vetter wrote:
>>> On Mon, May 03, 2021 at 10:57:39AM -0500, Jason Ekstrand wrote:
>>>> For now this is a no-op because everyone passes in a null SSEU but it
>>>> lets us get some of the error handling and selftest refactoring plumbed
>>>> through.
>>>>
>>>> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
>>>
>>> it is a bit icky that intel_context_set_gem also sets the sseu, feels a
>>> bit like a layering violation, but welp I couldn't come up with a better
>>> idea either.
>>>
>>> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>
>> It is actually quite horrible. As you say it breaks separation of duties and
>> open codes stuff all over the place without transferring over the commentary
>> about why.
> 
> I didn't really see lost commentary anywhere? Can you pls point out what
> got lost?

I glanced over two new places which check for RENDER_CLASS without any 
commentary while the existing code helpfully says:

	/* Only render engine supports RPCS configuration. */
	if (ce->engine->class != RENDER_CLASS) {
		ret = -ENODEV;
		goto out_ce;
	}

But really that is really just a symptom how mixed up the flows end up 
with this patch. In other words I am not suggesting those two new sites 
should have the same comment, just highlighting that the design is not good.

Regards,

Tvrtko

  -Daniel
> 
>>
>> Regards,
>>
>> Tvrtko
>>
>>>> ---
>>>>    drivers/gpu/drm/i915/gem/i915_gem_context.c   | 41 +++++++++++++++----
>>>>    .../gpu/drm/i915/gem/selftests/mock_context.c |  6 ++-
>>>>    2 files changed, 36 insertions(+), 11 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>>>> index ce729e640bbf7..6dd50d669c5b9 100644
>>>> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
>>>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
>>>> @@ -320,9 +320,12 @@ context_get_vm_rcu(struct i915_gem_context *ctx)
>>>>    	} while (1);
>>>>    }
>>>> -static void intel_context_set_gem(struct intel_context *ce,
>>>> -				  struct i915_gem_context *ctx)
>>>> +static int intel_context_set_gem(struct intel_context *ce,
>>>> +				 struct i915_gem_context *ctx,
>>>> +				 struct intel_sseu sseu)
>>>>    {
>>>> +	int ret = 0;
>>>> +
>>>>    	GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
>>>>    	RCU_INIT_POINTER(ce->gem_context, ctx);
>>>> @@ -349,6 +352,12 @@ static void intel_context_set_gem(struct intel_context *ce,
>>>>    		intel_context_set_watchdog_us(ce, (u64)timeout_ms * 1000);
>>>>    	}
>>>> +
>>>> +	/* A valid SSEU has no zero fields */
>>>> +	if (sseu.slice_mask && !WARN_ON(ce->engine->class != RENDER_CLASS))
>>>> +		ret = intel_context_reconfigure_sseu(ce, sseu);
>>>> +
>>>> +	return ret;
>>>>    }
>>>>    static void __free_engines(struct i915_gem_engines *e, unsigned int count)
>>>> @@ -416,7 +425,8 @@ static struct i915_gem_engines *alloc_engines(unsigned int count)
>>>>    	return e;
>>>>    }
>>>> -static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>>>> +static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
>>>> +						struct intel_sseu rcs_sseu)
>>>>    {
>>>>    	const struct intel_gt *gt = &ctx->i915->gt;
>>>>    	struct intel_engine_cs *engine;
>>>> @@ -429,6 +439,8 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>>>>    	for_each_engine(engine, gt, id) {
>>>>    		struct intel_context *ce;
>>>> +		struct intel_sseu sseu = {};
>>>> +		int ret;
>>>>    		if (engine->legacy_idx == INVALID_ENGINE)
>>>>    			continue;
>>>> @@ -442,10 +454,18 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
>>>>    			goto free_engines;
>>>>    		}
>>>> -		intel_context_set_gem(ce, ctx);
>>>> -
>>>>    		e->engines[engine->legacy_idx] = ce;
>>>>    		e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
>>>> +
>>>> +		if (engine->class == RENDER_CLASS)
>>>> +			sseu = rcs_sseu;
>>>> +
>>>> +		ret = intel_context_set_gem(ce, ctx, sseu);
>>>> +		if (ret) {
>>>> +			err = ERR_PTR(ret);
>>>> +			goto free_engines;
>>>> +		}
>>>> +
>>>>    	}
>>>>    	return e;
>>>> @@ -759,6 +779,7 @@ __create_context(struct drm_i915_private *i915,
>>>>    {
>>>>    	struct i915_gem_context *ctx;
>>>>    	struct i915_gem_engines *e;
>>>> +	struct intel_sseu null_sseu = {};
>>>>    	int err;
>>>>    	int i;
>>>> @@ -776,7 +797,7 @@ __create_context(struct drm_i915_private *i915,
>>>>    	INIT_LIST_HEAD(&ctx->stale.engines);
>>>>    	mutex_init(&ctx->engines_mutex);
>>>> -	e = default_engines(ctx);
>>>> +	e = default_engines(ctx, null_sseu);
>>>>    	if (IS_ERR(e)) {
>>>>    		err = PTR_ERR(e);
>>>>    		goto err_free;
>>>> @@ -1544,6 +1565,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>>>>    	struct intel_engine_cs *stack[16];
>>>>    	struct intel_engine_cs **siblings;
>>>>    	struct intel_context *ce;
>>>> +	struct intel_sseu null_sseu = {};
>>>>    	u16 num_siblings, idx;
>>>>    	unsigned int n;
>>>>    	int err;
>>>> @@ -1616,7 +1638,7 @@ set_engines__load_balance(struct i915_user_extension __user *base, void *data)
>>>>    		goto out_siblings;
>>>>    	}
>>>> -	intel_context_set_gem(ce, set->ctx);
>>>> +	intel_context_set_gem(ce, set->ctx, null_sseu);
>>>>    	if (cmpxchg(&set->engines->engines[idx], NULL, ce)) {
>>>>    		intel_context_put(ce);
>>>> @@ -1724,6 +1746,7 @@ set_engines(struct i915_gem_context *ctx,
>>>>    	struct drm_i915_private *i915 = ctx->i915;
>>>>    	struct i915_context_param_engines __user *user =
>>>>    		u64_to_user_ptr(args->value);
>>>> +	struct intel_sseu null_sseu = {};
>>>>    	struct set_engines set = { .ctx = ctx };
>>>>    	unsigned int num_engines, n;
>>>>    	u64 extensions;
>>>> @@ -1733,7 +1756,7 @@ set_engines(struct i915_gem_context *ctx,
>>>>    		if (!i915_gem_context_user_engines(ctx))
>>>>    			return 0;
>>>> -		set.engines = default_engines(ctx);
>>>> +		set.engines = default_engines(ctx, null_sseu);
>>>>    		if (IS_ERR(set.engines))
>>>>    			return PTR_ERR(set.engines);
>>>> @@ -1790,7 +1813,7 @@ set_engines(struct i915_gem_context *ctx,
>>>>    			return PTR_ERR(ce);
>>>>    		}
>>>> -		intel_context_set_gem(ce, ctx);
>>>> +		intel_context_set_gem(ce, ctx, null_sseu);
>>>>    		set.engines->engines[n] = ce;
>>>>    	}
>>>> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>>>> index e0f512ef7f3c6..cbeefd060e97b 100644
>>>> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>>>> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
>>>> @@ -14,6 +14,7 @@ mock_context(struct drm_i915_private *i915,
>>>>    {
>>>>    	struct i915_gem_context *ctx;
>>>>    	struct i915_gem_engines *e;
>>>> +	struct intel_sseu null_sseu = {};
>>>>    	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
>>>>    	if (!ctx)
>>>> @@ -31,7 +32,7 @@ mock_context(struct drm_i915_private *i915,
>>>>    	i915_gem_context_set_persistence(ctx);
>>>>    	mutex_init(&ctx->engines_mutex);
>>>> -	e = default_engines(ctx);
>>>> +	e = default_engines(ctx, null_sseu);
>>>>    	if (IS_ERR(e))
>>>>    		goto err_free;
>>>>    	RCU_INIT_POINTER(ctx->engines, e);
>>>> @@ -112,6 +113,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>>>>    {
>>>>    	struct i915_gem_engines *engines;
>>>>    	struct i915_gem_context *ctx;
>>>> +	struct intel_sseu null_sseu = {};
>>>>    	struct intel_context *ce;
>>>>    	engines = alloc_engines(1);
>>>> @@ -130,7 +132,7 @@ live_context_for_engine(struct intel_engine_cs *engine, struct file *file)
>>>>    		return ERR_CAST(ce);
>>>>    	}
>>>> -	intel_context_set_gem(ce, ctx);
>>>> +	intel_context_set_gem(ce, ctx, null_sseu);
>>>>    	engines->engines[0] = ce;
>>>>    	engines->num_engines = 1;
>>>> -- 
>>>> 2.31.1
>>>>
>>>> _______________________________________________
>>>> Intel-gfx mailing list
>>>> Intel-gfx@lists.freedesktop.org
>>>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
>>>
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 26/27] i915/gem/selftests: Assign the VM at context creation in igt_shared_ctx_exec
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-05  9:53     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-05  9:53 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:47AM -0500, Jason Ekstrand wrote:
> We want to delete __assign_ppgtt and, generally, stop setting the VM
> after context creation.  This is the one place I could find in the
> selftests where we set a VM after the fact.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> index 76029d7143f6c..76dd5cfe11b3c 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> @@ -813,16 +813,12 @@ static int igt_shared_ctx_exec(void *arg)
>  			struct i915_gem_context *ctx;
>  			struct intel_context *ce;
>  
> -			ctx = kernel_context(i915, NULL);
> +			ctx = kernel_context(i915, ctx_vm(parent));
>  			if (IS_ERR(ctx)) {
>  				err = PTR_ERR(ctx);
>  				goto out_test;
>  			}
>  
> -			mutex_lock(&ctx->mutex);
> -			__assign_ppgtt(ctx, ctx_vm(parent));
> -			mutex_unlock(&ctx->mutex);
> -
>  			ce = i915_gem_context_get_engine(ctx, engine->legacy_idx);
>  			GEM_BUG_ON(IS_ERR(ce));
>  
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 26/27] i915/gem/selftests: Assign the VM at context creation in igt_shared_ctx_exec
@ 2021-05-05  9:53     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-05  9:53 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:47AM -0500, Jason Ekstrand wrote:
> We want to delete __assign_ppgtt and, generally, stop setting the VM
> after context creation.  This is the one place I could find in the
> selftests where we set a VM after the fact.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> index 76029d7143f6c..76dd5cfe11b3c 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
> @@ -813,16 +813,12 @@ static int igt_shared_ctx_exec(void *arg)
>  			struct i915_gem_context *ctx;
>  			struct intel_context *ce;
>  
> -			ctx = kernel_context(i915, NULL);
> +			ctx = kernel_context(i915, ctx_vm(parent));
>  			if (IS_ERR(ctx)) {
>  				err = PTR_ERR(ctx);
>  				goto out_test;
>  			}
>  
> -			mutex_lock(&ctx->mutex);
> -			__assign_ppgtt(ctx, ctx_vm(parent));
> -			mutex_unlock(&ctx->mutex);
> -
>  			ce = i915_gem_context_get_engine(ctx, engine->legacy_idx);
>  			GEM_BUG_ON(IS_ERR(ce));
>  
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 12/27] drm/i915/gem: Disallow creating contexts with too many engines
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-05  9:56     ` Tvrtko Ursulin
  -1 siblings, 0 replies; 135+ messages in thread
From: Tvrtko Ursulin @ 2021-05-05  9:56 UTC (permalink / raw)
  To: Jason Ekstrand, intel-gfx, dri-devel; +Cc: Daniel Vetter


On 03/05/2021 16:57, Jason Ekstrand wrote:
> There's no sense in allowing userspace to create more engines than it
> can possibly access via execbuf.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

FWIW, again for the record, my advice is not to land this one. It makes 
no sense and it is actively disruptive for no benefit.

Regards,

Tvrtko

> ---
>   drivers/gpu/drm/i915/gem/i915_gem_context.c | 8 ++++----
>   1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index be42dc918ef6f..8e254d83d65f2 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1640,11 +1640,11 @@ set_engines(struct i915_gem_context *ctx,
>   		return -EINVAL;
>   	}
>   
> -	/*
> -	 * Note that I915_EXEC_RING_MASK limits execbuf to only using the
> -	 * first 64 engines defined here.
> -	 */
>   	num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> +	/* RING_MASK has no shift so we can use it directly here */
> +	if (num_engines > I915_EXEC_RING_MASK + 1)
> +		return -EINVAL;
> +
>   	set.engines = alloc_engines(num_engines);
>   	if (!set.engines)
>   		return -ENOMEM;
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 12/27] drm/i915/gem: Disallow creating contexts with too many engines
@ 2021-05-05  9:56     ` Tvrtko Ursulin
  0 siblings, 0 replies; 135+ messages in thread
From: Tvrtko Ursulin @ 2021-05-05  9:56 UTC (permalink / raw)
  To: Jason Ekstrand, intel-gfx, dri-devel; +Cc: Daniel Vetter


On 03/05/2021 16:57, Jason Ekstrand wrote:
> There's no sense in allowing userspace to create more engines than it
> can possibly access via execbuf.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

FWIW, again for the record, my advice is not to land this one. It makes 
no sense and it is actively disruptive for no benefit.

Regards,

Tvrtko

> ---
>   drivers/gpu/drm/i915/gem/i915_gem_context.c | 8 ++++----
>   1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index be42dc918ef6f..8e254d83d65f2 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1640,11 +1640,11 @@ set_engines(struct i915_gem_context *ctx,
>   		return -EINVAL;
>   	}
>   
> -	/*
> -	 * Note that I915_EXEC_RING_MASK limits execbuf to only using the
> -	 * first 64 engines defined here.
> -	 */
>   	num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> +	/* RING_MASK has no shift so we can use it directly here */
> +	if (num_engines > I915_EXEC_RING_MASK + 1)
> +		return -EINVAL;
> +
>   	set.engines = alloc_engines(num_engines);
>   	if (!set.engines)
>   		return -ENOMEM;
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 27/27] drm/i915/gem: Roll all of context creation together
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-05 10:05     ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-05 10:05 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:48AM -0500, Jason Ekstrand wrote:
> Now that we have the whole engine set and VM at context creation time,
> we can just assign those fields instead of creating first and handling
> the VM and engines later.  This lets us avoid creating useless VMs and
> engine sets and lets us get rid of the complex VM setting code.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Ok here comes the cleanup around engine setup control flow and locking and
all that.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

So one thing I noticed that's still in the uapi bucket is that we now
still have all the ctx->user_flags as mutable. I think especially
persistence has a big impact on ctx cleanup, so would be nice if we can
make that one invariant. Recoverable/no_error_capture less so, and
bannable is kinda meh.

Did you look into how much it would be to lock these down too? We could
then split the muttable ones out into a ctx->mutable_user_flags or so and
only use atomic bitops for these.

Anyway the big items are the vm and engines, and that's taken care of now.
-Daniel

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 159 ++++++------------
>  .../gpu/drm/i915/gem/selftests/mock_context.c |  33 ++--
>  2 files changed, 64 insertions(+), 128 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 6e5828fe1a792..6bffb0e579b4e 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1302,56 +1302,6 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
>  	return 0;
>  }
>  
> -static struct i915_gem_context *
> -__create_context(struct drm_i915_private *i915,
> -		 const struct i915_gem_proto_context *pc)
> -{
> -	struct i915_gem_context *ctx;
> -	struct i915_gem_engines *e;
> -	int err;
> -	int i;
> -
> -	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> -	if (!ctx)
> -		return ERR_PTR(-ENOMEM);
> -
> -	kref_init(&ctx->ref);
> -	ctx->i915 = i915;
> -	ctx->sched = pc->sched;
> -	mutex_init(&ctx->mutex);
> -	INIT_LIST_HEAD(&ctx->link);
> -
> -	spin_lock_init(&ctx->stale.lock);
> -	INIT_LIST_HEAD(&ctx->stale.engines);
> -
> -	mutex_init(&ctx->engines_mutex);
> -	e = default_engines(ctx, pc->legacy_rcs_sseu);
> -	if (IS_ERR(e)) {
> -		err = PTR_ERR(e);
> -		goto err_free;
> -	}
> -	RCU_INIT_POINTER(ctx->engines, e);
> -
> -	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
> -	mutex_init(&ctx->lut_mutex);
> -
> -	/* NB: Mark all slices as needing a remap so that when the context first
> -	 * loads it will restore whatever remap state already exists. If there
> -	 * is no remap info, it will be a NOP. */
> -	ctx->remap_slice = ALL_L3_SLICES(i915);
> -
> -	ctx->user_flags = pc->user_flags;
> -
> -	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
> -		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
> -
> -	return ctx;
> -
> -err_free:
> -	kfree(ctx);
> -	return ERR_PTR(err);
> -}
> -
>  static inline struct i915_gem_engines *
>  __context_engines_await(const struct i915_gem_context *ctx,
>  			bool *user_engines)
> @@ -1395,86 +1345,77 @@ context_apply_all(struct i915_gem_context *ctx,
>  	i915_sw_fence_complete(&e->fence);
>  }
>  
> -static void __apply_ppgtt(struct intel_context *ce, void *vm)
> -{
> -	i915_vm_put(ce->vm);
> -	ce->vm = i915_vm_get(vm);
> -}
> -
> -static struct i915_address_space *
> -__set_ppgtt(struct i915_gem_context *ctx, struct i915_address_space *vm)
> -{
> -	struct i915_address_space *old;
> -
> -	old = rcu_replace_pointer(ctx->vm,
> -				  i915_vm_open(vm),
> -				  lockdep_is_held(&ctx->mutex));
> -	GEM_BUG_ON(old && i915_vm_is_4lvl(vm) != i915_vm_is_4lvl(old));
> -
> -	context_apply_all(ctx, __apply_ppgtt, vm);
> -
> -	return old;
> -}
> -
> -static void __assign_ppgtt(struct i915_gem_context *ctx,
> -			   struct i915_address_space *vm)
> -{
> -	if (vm == rcu_access_pointer(ctx->vm))
> -		return;
> -
> -	vm = __set_ppgtt(ctx, vm);
> -	if (vm)
> -		i915_vm_close(vm);
> -}
> -
>  static struct i915_gem_context *
>  i915_gem_create_context(struct drm_i915_private *i915,
>  			const struct i915_gem_proto_context *pc)
>  {
>  	struct i915_gem_context *ctx;
> -	int ret;
> +	struct i915_gem_engines *e;
> +	int err;
> +	int i;
>  
> -	ctx = __create_context(i915, pc);
> -	if (IS_ERR(ctx))
> -		return ctx;
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return ERR_PTR(-ENOMEM);
>  
> -	if (pc->vm) {
> -		mutex_lock(&ctx->mutex);
> -		__assign_ppgtt(ctx, pc->vm);
> -		mutex_unlock(&ctx->mutex);
> -	}
> +	kref_init(&ctx->ref);
> +	ctx->i915 = i915;
> +	ctx->sched = pc->sched;
> +	mutex_init(&ctx->mutex);
> +	INIT_LIST_HEAD(&ctx->link);
>  
> -	if (pc->num_user_engines >= 0) {
> -		struct i915_gem_engines *engines;
> +	spin_lock_init(&ctx->stale.lock);
> +	INIT_LIST_HEAD(&ctx->stale.engines);
>  
> -		engines = user_engines(ctx, pc->num_user_engines,
> -				       pc->user_engines);
> -		if (IS_ERR(engines)) {
> -			context_close(ctx);
> -			return ERR_CAST(engines);
> -		}
> +	if (pc->vm)
> +		RCU_INIT_POINTER(ctx->vm, i915_vm_open(pc->vm));
>  
> -		mutex_lock(&ctx->engines_mutex);
> +	mutex_init(&ctx->engines_mutex);
> +	if (pc->num_user_engines >= 0) {
>  		i915_gem_context_set_user_engines(ctx);
> -		engines = rcu_replace_pointer(ctx->engines, engines, 1);
> -		mutex_unlock(&ctx->engines_mutex);
> -
> -		free_engines(engines);
> +		e = user_engines(ctx, pc->num_user_engines, pc->user_engines);
> +	} else {
> +		i915_gem_context_clear_user_engines(ctx);
> +		e = default_engines(ctx, pc->legacy_rcs_sseu);
>  	}
> +	if (IS_ERR(e)) {
> +		err = PTR_ERR(e);
> +		goto err_vm;
> +	}
> +	RCU_INIT_POINTER(ctx->engines, e);
> +
> +	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
> +	mutex_init(&ctx->lut_mutex);
> +
> +	/* NB: Mark all slices as needing a remap so that when the context first
> +	 * loads it will restore whatever remap state already exists. If there
> +	 * is no remap info, it will be a NOP. */
> +	ctx->remap_slice = ALL_L3_SLICES(i915);
> +
> +	ctx->user_flags = pc->user_flags;
> +
> +	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
> +		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
>  
>  	if (pc->single_timeline) {
> -		ret = drm_syncobj_create(&ctx->syncobj,
> +		err = drm_syncobj_create(&ctx->syncobj,
>  					 DRM_SYNCOBJ_CREATE_SIGNALED,
>  					 NULL);
> -		if (ret) {
> -			context_close(ctx);
> -			return ERR_PTR(ret);
> -		}
> +		if (err)
> +			goto err_engines;
>  	}
>  
>  	trace_i915_context_create(ctx);
>  
>  	return ctx;
> +
> +err_engines:
> +	free_engines(e);
> +err_vm:
> +	if (ctx->vm)
> +		i915_vm_close(ctx->vm);
> +	kfree(ctx);
> +	return ERR_PTR(err);
>  }
>  
>  static void init_contexts(struct i915_gem_contexts *gc)
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index 500ef27ba4771..fee070df1c97b 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -31,15 +31,6 @@ mock_context(struct drm_i915_private *i915,
>  
>  	i915_gem_context_set_persistence(ctx);
>  
> -	mutex_init(&ctx->engines_mutex);
> -	e = default_engines(ctx, null_sseu);
> -	if (IS_ERR(e))
> -		goto err_free;
> -	RCU_INIT_POINTER(ctx->engines, e);
> -
> -	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
> -	mutex_init(&ctx->lut_mutex);
> -
>  	if (name) {
>  		struct i915_ppgtt *ppgtt;
>  
> @@ -47,25 +38,29 @@ mock_context(struct drm_i915_private *i915,
>  
>  		ppgtt = mock_ppgtt(i915, name);
>  		if (!ppgtt)
> -			goto err_put;
> -
> -		mutex_lock(&ctx->mutex);
> -		__set_ppgtt(ctx, &ppgtt->vm);
> -		mutex_unlock(&ctx->mutex);
> +			goto err_free;
>  
> +		ctx->vm = i915_vm_open(&ppgtt->vm);
>  		i915_vm_put(&ppgtt->vm);
>  	}
>  
> +	mutex_init(&ctx->engines_mutex);
> +	e = default_engines(ctx, null_sseu);
> +	if (IS_ERR(e))
> +		goto err_vm;
> +	RCU_INIT_POINTER(ctx->engines, e);
> +
> +	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
> +	mutex_init(&ctx->lut_mutex);
> +
>  	return ctx;
>  
> +err_vm:
> +	if (ctx->vm)
> +		i915_vm_close(ctx->vm);
>  err_free:
>  	kfree(ctx);
>  	return NULL;
> -
> -err_put:
> -	i915_gem_context_set_closed(ctx);
> -	i915_gem_context_put(ctx);
> -	return NULL;
>  }
>  
>  void mock_context_close(struct i915_gem_context *ctx)
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 27/27] drm/i915/gem: Roll all of context creation together
@ 2021-05-05 10:05     ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-05 10:05 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: intel-gfx, dri-devel

On Mon, May 03, 2021 at 10:57:48AM -0500, Jason Ekstrand wrote:
> Now that we have the whole engine set and VM at context creation time,
> we can just assign those fields instead of creating first and handling
> the VM and engines later.  This lets us avoid creating useless VMs and
> engine sets and lets us get rid of the complex VM setting code.
> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>

Ok here comes the cleanup around engine setup control flow and locking and
all that.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

So one thing I noticed that's still in the uapi bucket is that we now
still have all the ctx->user_flags as mutable. I think especially
persistence has a big impact on ctx cleanup, so would be nice if we can
make that one invariant. Recoverable/no_error_capture less so, and
bannable is kinda meh.

Did you look into how much it would be to lock these down too? We could
then split the muttable ones out into a ctx->mutable_user_flags or so and
only use atomic bitops for these.

Anyway the big items are the vm and engines, and that's taken care of now.
-Daniel

> ---
>  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 159 ++++++------------
>  .../gpu/drm/i915/gem/selftests/mock_context.c |  33 ++--
>  2 files changed, 64 insertions(+), 128 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 6e5828fe1a792..6bffb0e579b4e 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -1302,56 +1302,6 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
>  	return 0;
>  }
>  
> -static struct i915_gem_context *
> -__create_context(struct drm_i915_private *i915,
> -		 const struct i915_gem_proto_context *pc)
> -{
> -	struct i915_gem_context *ctx;
> -	struct i915_gem_engines *e;
> -	int err;
> -	int i;
> -
> -	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> -	if (!ctx)
> -		return ERR_PTR(-ENOMEM);
> -
> -	kref_init(&ctx->ref);
> -	ctx->i915 = i915;
> -	ctx->sched = pc->sched;
> -	mutex_init(&ctx->mutex);
> -	INIT_LIST_HEAD(&ctx->link);
> -
> -	spin_lock_init(&ctx->stale.lock);
> -	INIT_LIST_HEAD(&ctx->stale.engines);
> -
> -	mutex_init(&ctx->engines_mutex);
> -	e = default_engines(ctx, pc->legacy_rcs_sseu);
> -	if (IS_ERR(e)) {
> -		err = PTR_ERR(e);
> -		goto err_free;
> -	}
> -	RCU_INIT_POINTER(ctx->engines, e);
> -
> -	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
> -	mutex_init(&ctx->lut_mutex);
> -
> -	/* NB: Mark all slices as needing a remap so that when the context first
> -	 * loads it will restore whatever remap state already exists. If there
> -	 * is no remap info, it will be a NOP. */
> -	ctx->remap_slice = ALL_L3_SLICES(i915);
> -
> -	ctx->user_flags = pc->user_flags;
> -
> -	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
> -		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
> -
> -	return ctx;
> -
> -err_free:
> -	kfree(ctx);
> -	return ERR_PTR(err);
> -}
> -
>  static inline struct i915_gem_engines *
>  __context_engines_await(const struct i915_gem_context *ctx,
>  			bool *user_engines)
> @@ -1395,86 +1345,77 @@ context_apply_all(struct i915_gem_context *ctx,
>  	i915_sw_fence_complete(&e->fence);
>  }
>  
> -static void __apply_ppgtt(struct intel_context *ce, void *vm)
> -{
> -	i915_vm_put(ce->vm);
> -	ce->vm = i915_vm_get(vm);
> -}
> -
> -static struct i915_address_space *
> -__set_ppgtt(struct i915_gem_context *ctx, struct i915_address_space *vm)
> -{
> -	struct i915_address_space *old;
> -
> -	old = rcu_replace_pointer(ctx->vm,
> -				  i915_vm_open(vm),
> -				  lockdep_is_held(&ctx->mutex));
> -	GEM_BUG_ON(old && i915_vm_is_4lvl(vm) != i915_vm_is_4lvl(old));
> -
> -	context_apply_all(ctx, __apply_ppgtt, vm);
> -
> -	return old;
> -}
> -
> -static void __assign_ppgtt(struct i915_gem_context *ctx,
> -			   struct i915_address_space *vm)
> -{
> -	if (vm == rcu_access_pointer(ctx->vm))
> -		return;
> -
> -	vm = __set_ppgtt(ctx, vm);
> -	if (vm)
> -		i915_vm_close(vm);
> -}
> -
>  static struct i915_gem_context *
>  i915_gem_create_context(struct drm_i915_private *i915,
>  			const struct i915_gem_proto_context *pc)
>  {
>  	struct i915_gem_context *ctx;
> -	int ret;
> +	struct i915_gem_engines *e;
> +	int err;
> +	int i;
>  
> -	ctx = __create_context(i915, pc);
> -	if (IS_ERR(ctx))
> -		return ctx;
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return ERR_PTR(-ENOMEM);
>  
> -	if (pc->vm) {
> -		mutex_lock(&ctx->mutex);
> -		__assign_ppgtt(ctx, pc->vm);
> -		mutex_unlock(&ctx->mutex);
> -	}
> +	kref_init(&ctx->ref);
> +	ctx->i915 = i915;
> +	ctx->sched = pc->sched;
> +	mutex_init(&ctx->mutex);
> +	INIT_LIST_HEAD(&ctx->link);
>  
> -	if (pc->num_user_engines >= 0) {
> -		struct i915_gem_engines *engines;
> +	spin_lock_init(&ctx->stale.lock);
> +	INIT_LIST_HEAD(&ctx->stale.engines);
>  
> -		engines = user_engines(ctx, pc->num_user_engines,
> -				       pc->user_engines);
> -		if (IS_ERR(engines)) {
> -			context_close(ctx);
> -			return ERR_CAST(engines);
> -		}
> +	if (pc->vm)
> +		RCU_INIT_POINTER(ctx->vm, i915_vm_open(pc->vm));
>  
> -		mutex_lock(&ctx->engines_mutex);
> +	mutex_init(&ctx->engines_mutex);
> +	if (pc->num_user_engines >= 0) {
>  		i915_gem_context_set_user_engines(ctx);
> -		engines = rcu_replace_pointer(ctx->engines, engines, 1);
> -		mutex_unlock(&ctx->engines_mutex);
> -
> -		free_engines(engines);
> +		e = user_engines(ctx, pc->num_user_engines, pc->user_engines);
> +	} else {
> +		i915_gem_context_clear_user_engines(ctx);
> +		e = default_engines(ctx, pc->legacy_rcs_sseu);
>  	}
> +	if (IS_ERR(e)) {
> +		err = PTR_ERR(e);
> +		goto err_vm;
> +	}
> +	RCU_INIT_POINTER(ctx->engines, e);
> +
> +	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
> +	mutex_init(&ctx->lut_mutex);
> +
> +	/* NB: Mark all slices as needing a remap so that when the context first
> +	 * loads it will restore whatever remap state already exists. If there
> +	 * is no remap info, it will be a NOP. */
> +	ctx->remap_slice = ALL_L3_SLICES(i915);
> +
> +	ctx->user_flags = pc->user_flags;
> +
> +	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
> +		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
>  
>  	if (pc->single_timeline) {
> -		ret = drm_syncobj_create(&ctx->syncobj,
> +		err = drm_syncobj_create(&ctx->syncobj,
>  					 DRM_SYNCOBJ_CREATE_SIGNALED,
>  					 NULL);
> -		if (ret) {
> -			context_close(ctx);
> -			return ERR_PTR(ret);
> -		}
> +		if (err)
> +			goto err_engines;
>  	}
>  
>  	trace_i915_context_create(ctx);
>  
>  	return ctx;
> +
> +err_engines:
> +	free_engines(e);
> +err_vm:
> +	if (ctx->vm)
> +		i915_vm_close(ctx->vm);
> +	kfree(ctx);
> +	return ERR_PTR(err);
>  }
>  
>  static void init_contexts(struct i915_gem_contexts *gc)
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index 500ef27ba4771..fee070df1c97b 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -31,15 +31,6 @@ mock_context(struct drm_i915_private *i915,
>  
>  	i915_gem_context_set_persistence(ctx);
>  
> -	mutex_init(&ctx->engines_mutex);
> -	e = default_engines(ctx, null_sseu);
> -	if (IS_ERR(e))
> -		goto err_free;
> -	RCU_INIT_POINTER(ctx->engines, e);
> -
> -	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
> -	mutex_init(&ctx->lut_mutex);
> -
>  	if (name) {
>  		struct i915_ppgtt *ppgtt;
>  
> @@ -47,25 +38,29 @@ mock_context(struct drm_i915_private *i915,
>  
>  		ppgtt = mock_ppgtt(i915, name);
>  		if (!ppgtt)
> -			goto err_put;
> -
> -		mutex_lock(&ctx->mutex);
> -		__set_ppgtt(ctx, &ppgtt->vm);
> -		mutex_unlock(&ctx->mutex);
> +			goto err_free;
>  
> +		ctx->vm = i915_vm_open(&ppgtt->vm);
>  		i915_vm_put(&ppgtt->vm);
>  	}
>  
> +	mutex_init(&ctx->engines_mutex);
> +	e = default_engines(ctx, null_sseu);
> +	if (IS_ERR(e))
> +		goto err_vm;
> +	RCU_INIT_POINTER(ctx->engines, e);
> +
> +	INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL);
> +	mutex_init(&ctx->lut_mutex);
> +
>  	return ctx;
>  
> +err_vm:
> +	if (ctx->vm)
> +		i915_vm_close(ctx->vm);
>  err_free:
>  	kfree(ctx);
>  	return NULL;
> -
> -err_put:
> -	i915_gem_context_set_closed(ctx);
> -	i915_gem_context_put(ctx);
> -	return NULL;
>  }
>  
>  void mock_context_close(struct i915_gem_context *ctx)
> -- 
> 2.31.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct
  2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-05 10:09     ` Tvrtko Ursulin
  -1 siblings, 0 replies; 135+ messages in thread
From: Tvrtko Ursulin @ 2021-05-05 10:09 UTC (permalink / raw)
  To: Jason Ekstrand, intel-gfx, dri-devel


On 03/05/2021 16:57, Jason Ekstrand wrote:
> The current context uAPI allows for two methods of setting context
> parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
> former is allowed to be called at any time while the later happens as
> part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
> settable via the other.  While some params are fairly simple and setting
> them on a live context is harmless such the context priority, others are
> far trickier such as the VM or the set of engines.  In order to swap out
> the VM, for instance, we have to delay until all current in-flight work
> is complete, swap in the new VM, and then continue.  This leads to a
> plethora of potential race conditions we'd really rather avoid.
> 
> Unfortunately, both methods of setting the VM and engine set are in
> active use today so we can't simply disallow setting the VM or engine
> set vial SET_CONTEXT_PARAM.  In order to work around this wart, this
> commit adds a proto-context struct which contains all the context create
> parameters.

The detailed commentary from "drm/i915/gem: Delay context creation" 
would be useful at this point in the series so it is known what this 
patch tries to do.

For the record, again, my opinion is that from here in the series 
onwards (mostly), there is a negative cost-benefit ratio and most 
certainly isn't something which should be rammed quickly in without a 
consensus.

Regards,

Tvrtko

> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>   drivers/gpu/drm/i915/gem/i915_gem_context.c   | 145 ++++++++++++++----
>   .../gpu/drm/i915/gem/i915_gem_context_types.h |  22 +++
>   .../gpu/drm/i915/gem/selftests/mock_context.c |  16 +-
>   3 files changed, 153 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 4835991898ac9..10bd1b6dd1774 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -191,6 +191,97 @@ static int validate_priority(struct drm_i915_private *i915,
>   	return 0;
>   }
>   
> +static void proto_context_close(struct i915_gem_proto_context *pc)
> +{
> +	if (pc->vm)
> +		i915_vm_put(pc->vm);
> +	kfree(pc);
> +}
> +
> +static int proto_context_set_persistence(struct drm_i915_private *i915,
> +					 struct i915_gem_proto_context *pc,
> +					 bool persist)
> +{
> +	if (persist) {
> +		/*
> +		 * Only contexts that are short-lived [that will expire or be
> +		 * reset] are allowed to survive past termination. We require
> +		 * hangcheck to ensure that the persistent requests are healthy.
> +		 */
> +		if (!i915->params.enable_hangcheck)
> +			return -EINVAL;
> +
> +		__set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> +	} else {
> +		/* To cancel a context we use "preempt-to-idle" */
> +		if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
> +			return -ENODEV;
> +
> +		/*
> +		 * If the cancel fails, we then need to reset, cleanly!
> +		 *
> +		 * If the per-engine reset fails, all hope is lost! We resort
> +		 * to a full GPU reset in that unlikely case, but realistically
> +		 * if the engine could not reset, the full reset does not fare
> +		 * much better. The damage has been done.
> +		 *
> +		 * However, if we cannot reset an engine by itself, we cannot
> +		 * cleanup a hanging persistent context without causing
> +		 * colateral damage, and we should not pretend we can by
> +		 * exposing the interface.
> +		 */
> +		if (!intel_has_reset_engine(&i915->gt))
> +			return -ENODEV;
> +
> +		__clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> +	}
> +
> +	return 0;
> +}
> +
> +static struct i915_gem_proto_context *
> +proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> +{
> +	struct i915_gem_proto_context *pc, *err;
> +
> +	pc = kzalloc(sizeof(*pc), GFP_KERNEL);
> +	if (!pc)
> +		return ERR_PTR(-ENOMEM);
> +
> +	if (HAS_FULL_PPGTT(i915)) {
> +		struct i915_ppgtt *ppgtt;
> +
> +		ppgtt = i915_ppgtt_create(&i915->gt);
> +		if (IS_ERR(ppgtt)) {
> +			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> +				PTR_ERR(ppgtt));
> +			err = ERR_CAST(ppgtt);
> +			goto proto_close;
> +		}
> +		pc->vm = &ppgtt->vm;
> +	}
> +
> +	pc->user_flags = 0;
> +	__set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> +	__set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> +	proto_context_set_persistence(i915, pc, true);
> +	pc->sched.priority = I915_PRIORITY_NORMAL;
> +
> +	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> +		if (!HAS_EXECLISTS(i915)) {
> +			err = ERR_PTR(-EINVAL);
> +			goto proto_close;
> +		}
> +		pc->single_timeline = true;
> +	}
> +
> +	return pc;
> +
> +proto_close:
> +	proto_context_close(pc);
> +	return err;
> +}
> +
>   static struct i915_address_space *
>   context_get_vm_rcu(struct i915_gem_context *ctx)
>   {
> @@ -660,7 +751,8 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
>   }
>   
>   static struct i915_gem_context *
> -__create_context(struct drm_i915_private *i915)
> +__create_context(struct drm_i915_private *i915,
> +		 const struct i915_gem_proto_context *pc)
>   {
>   	struct i915_gem_context *ctx;
>   	struct i915_gem_engines *e;
> @@ -673,7 +765,7 @@ __create_context(struct drm_i915_private *i915)
>   
>   	kref_init(&ctx->ref);
>   	ctx->i915 = i915;
> -	ctx->sched.priority = I915_PRIORITY_NORMAL;
> +	ctx->sched = pc->sched;
>   	mutex_init(&ctx->mutex);
>   	INIT_LIST_HEAD(&ctx->link);
>   
> @@ -696,9 +788,7 @@ __create_context(struct drm_i915_private *i915)
>   	 * is no remap info, it will be a NOP. */
>   	ctx->remap_slice = ALL_L3_SLICES(i915);
>   
> -	i915_gem_context_set_bannable(ctx);
> -	i915_gem_context_set_recoverable(ctx);
> -	__context_set_persistence(ctx, true /* cgroup hook? */);
> +	ctx->user_flags = pc->user_flags;
>   
>   	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
>   		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
> @@ -786,38 +876,23 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
>   }
>   
>   static struct i915_gem_context *
> -i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
> +i915_gem_create_context(struct drm_i915_private *i915,
> +			const struct i915_gem_proto_context *pc)
>   {
>   	struct i915_gem_context *ctx;
>   	int ret;
>   
> -	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
> -	    !HAS_EXECLISTS(i915))
> -		return ERR_PTR(-EINVAL);
> -
> -	ctx = __create_context(i915);
> +	ctx = __create_context(i915, pc);
>   	if (IS_ERR(ctx))
>   		return ctx;
>   
> -	if (HAS_FULL_PPGTT(i915)) {
> -		struct i915_ppgtt *ppgtt;
> -
> -		ppgtt = i915_ppgtt_create(&i915->gt);
> -		if (IS_ERR(ppgtt)) {
> -			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> -				PTR_ERR(ppgtt));
> -			context_close(ctx);
> -			return ERR_CAST(ppgtt);
> -		}
> -
> +	if (pc->vm) {
>   		mutex_lock(&ctx->mutex);
> -		__assign_ppgtt(ctx, &ppgtt->vm);
> +		__assign_ppgtt(ctx, pc->vm);
>   		mutex_unlock(&ctx->mutex);
> -
> -		i915_vm_put(&ppgtt->vm);
>   	}
>   
> -	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> +	if (pc->single_timeline) {
>   		ret = drm_syncobj_create(&ctx->syncobj,
>   					 DRM_SYNCOBJ_CREATE_SIGNALED,
>   					 NULL);
> @@ -883,6 +958,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>   			  struct drm_file *file)
>   {
>   	struct drm_i915_file_private *file_priv = file->driver_priv;
> +	struct i915_gem_proto_context *pc;
>   	struct i915_gem_context *ctx;
>   	int err;
>   	u32 id;
> @@ -892,7 +968,14 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>   	/* 0 reserved for invalid/unassigned ppgtt */
>   	xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
>   
> -	ctx = i915_gem_create_context(i915, 0);
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc)) {
> +		err = PTR_ERR(pc);
> +		goto err;
> +	}
> +
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>   	if (IS_ERR(ctx)) {
>   		err = PTR_ERR(ctx);
>   		goto err;
> @@ -1885,6 +1968,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>   {
>   	struct drm_i915_private *i915 = to_i915(dev);
>   	struct drm_i915_gem_context_create_ext *args = data;
> +	struct i915_gem_proto_context *pc;
>   	struct create_ext ext_data;
>   	int ret;
>   	u32 id;
> @@ -1907,7 +1991,12 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>   		return -EIO;
>   	}
>   
> -	ext_data.ctx = i915_gem_create_context(i915, args->flags);
> +	pc = proto_context_create(i915, args->flags);
> +	if (IS_ERR(pc))
> +		return PTR_ERR(pc);
> +
> +	ext_data.ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>   	if (IS_ERR(ext_data.ctx))
>   		return PTR_ERR(ext_data.ctx);
>   
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index 5f0673a2129f9..0bf337b6d89ac 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -66,6 +66,28 @@ struct i915_gem_engines_iter {
>   	const struct i915_gem_engines *engines;
>   };
>   
> +/**
> + * struct i915_gem_proto_context - prototype context
> + *
> + * The struct i915_gem_proto_context represents the creation parameters for
> + * an i915_gem_context.  This is used to gather parameters provided either
> + * through creation flags or via SET_CONTEXT_PARAM so that, when we create
> + * the final i915_gem_context, those parameters can be immutable.
> + */
> +struct i915_gem_proto_context {
> +	/** @vm: See i915_gem_context::vm */
> +	struct i915_address_space *vm;
> +
> +	/** @user_flags: See i915_gem_context::user_flags */
> +	unsigned long user_flags;
> +
> +	/** @sched: See i915_gem_context::sched */
> +	struct i915_sched_attr sched;
> +
> +	/** @single_timeline: See See i915_gem_context::syncobj */
> +	bool single_timeline;
> +};
> +
>   /**
>    * struct i915_gem_context - client state
>    *
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index 51b5a3421b400..e0f512ef7f3c6 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -80,11 +80,17 @@ void mock_init_contexts(struct drm_i915_private *i915)
>   struct i915_gem_context *
>   live_context(struct drm_i915_private *i915, struct file *file)
>   {
> +	struct i915_gem_proto_context *pc;
>   	struct i915_gem_context *ctx;
>   	int err;
>   	u32 id;
>   
> -	ctx = i915_gem_create_context(i915, 0);
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc))
> +		return ERR_CAST(pc);
> +
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>   	if (IS_ERR(ctx))
>   		return ctx;
>   
> @@ -142,8 +148,14 @@ struct i915_gem_context *
>   kernel_context(struct drm_i915_private *i915)
>   {
>   	struct i915_gem_context *ctx;
> +	struct i915_gem_proto_context *pc;
> +
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc))
> +		return ERR_CAST(pc);
>   
> -	ctx = i915_gem_create_context(i915, 0);
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>   	if (IS_ERR(ctx))
>   		return ctx;
>   
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct
@ 2021-05-05 10:09     ` Tvrtko Ursulin
  0 siblings, 0 replies; 135+ messages in thread
From: Tvrtko Ursulin @ 2021-05-05 10:09 UTC (permalink / raw)
  To: Jason Ekstrand, intel-gfx, dri-devel


On 03/05/2021 16:57, Jason Ekstrand wrote:
> The current context uAPI allows for two methods of setting context
> parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
> former is allowed to be called at any time while the later happens as
> part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
> settable via the other.  While some params are fairly simple and setting
> them on a live context is harmless such the context priority, others are
> far trickier such as the VM or the set of engines.  In order to swap out
> the VM, for instance, we have to delay until all current in-flight work
> is complete, swap in the new VM, and then continue.  This leads to a
> plethora of potential race conditions we'd really rather avoid.
> 
> Unfortunately, both methods of setting the VM and engine set are in
> active use today so we can't simply disallow setting the VM or engine
> set vial SET_CONTEXT_PARAM.  In order to work around this wart, this
> commit adds a proto-context struct which contains all the context create
> parameters.

The detailed commentary from "drm/i915/gem: Delay context creation" 
would be useful at this point in the series so it is known what this 
patch tries to do.

For the record, again, my opinion is that from here in the series 
onwards (mostly), there is a negative cost-benefit ratio and most 
certainly isn't something which should be rammed quickly in without a 
consensus.

Regards,

Tvrtko

> 
> Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> ---
>   drivers/gpu/drm/i915/gem/i915_gem_context.c   | 145 ++++++++++++++----
>   .../gpu/drm/i915/gem/i915_gem_context_types.h |  22 +++
>   .../gpu/drm/i915/gem/selftests/mock_context.c |  16 +-
>   3 files changed, 153 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> index 4835991898ac9..10bd1b6dd1774 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> @@ -191,6 +191,97 @@ static int validate_priority(struct drm_i915_private *i915,
>   	return 0;
>   }
>   
> +static void proto_context_close(struct i915_gem_proto_context *pc)
> +{
> +	if (pc->vm)
> +		i915_vm_put(pc->vm);
> +	kfree(pc);
> +}
> +
> +static int proto_context_set_persistence(struct drm_i915_private *i915,
> +					 struct i915_gem_proto_context *pc,
> +					 bool persist)
> +{
> +	if (persist) {
> +		/*
> +		 * Only contexts that are short-lived [that will expire or be
> +		 * reset] are allowed to survive past termination. We require
> +		 * hangcheck to ensure that the persistent requests are healthy.
> +		 */
> +		if (!i915->params.enable_hangcheck)
> +			return -EINVAL;
> +
> +		__set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> +	} else {
> +		/* To cancel a context we use "preempt-to-idle" */
> +		if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
> +			return -ENODEV;
> +
> +		/*
> +		 * If the cancel fails, we then need to reset, cleanly!
> +		 *
> +		 * If the per-engine reset fails, all hope is lost! We resort
> +		 * to a full GPU reset in that unlikely case, but realistically
> +		 * if the engine could not reset, the full reset does not fare
> +		 * much better. The damage has been done.
> +		 *
> +		 * However, if we cannot reset an engine by itself, we cannot
> +		 * cleanup a hanging persistent context without causing
> +		 * colateral damage, and we should not pretend we can by
> +		 * exposing the interface.
> +		 */
> +		if (!intel_has_reset_engine(&i915->gt))
> +			return -ENODEV;
> +
> +		__clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> +	}
> +
> +	return 0;
> +}
> +
> +static struct i915_gem_proto_context *
> +proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> +{
> +	struct i915_gem_proto_context *pc, *err;
> +
> +	pc = kzalloc(sizeof(*pc), GFP_KERNEL);
> +	if (!pc)
> +		return ERR_PTR(-ENOMEM);
> +
> +	if (HAS_FULL_PPGTT(i915)) {
> +		struct i915_ppgtt *ppgtt;
> +
> +		ppgtt = i915_ppgtt_create(&i915->gt);
> +		if (IS_ERR(ppgtt)) {
> +			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> +				PTR_ERR(ppgtt));
> +			err = ERR_CAST(ppgtt);
> +			goto proto_close;
> +		}
> +		pc->vm = &ppgtt->vm;
> +	}
> +
> +	pc->user_flags = 0;
> +	__set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> +	__set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> +	proto_context_set_persistence(i915, pc, true);
> +	pc->sched.priority = I915_PRIORITY_NORMAL;
> +
> +	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> +		if (!HAS_EXECLISTS(i915)) {
> +			err = ERR_PTR(-EINVAL);
> +			goto proto_close;
> +		}
> +		pc->single_timeline = true;
> +	}
> +
> +	return pc;
> +
> +proto_close:
> +	proto_context_close(pc);
> +	return err;
> +}
> +
>   static struct i915_address_space *
>   context_get_vm_rcu(struct i915_gem_context *ctx)
>   {
> @@ -660,7 +751,8 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
>   }
>   
>   static struct i915_gem_context *
> -__create_context(struct drm_i915_private *i915)
> +__create_context(struct drm_i915_private *i915,
> +		 const struct i915_gem_proto_context *pc)
>   {
>   	struct i915_gem_context *ctx;
>   	struct i915_gem_engines *e;
> @@ -673,7 +765,7 @@ __create_context(struct drm_i915_private *i915)
>   
>   	kref_init(&ctx->ref);
>   	ctx->i915 = i915;
> -	ctx->sched.priority = I915_PRIORITY_NORMAL;
> +	ctx->sched = pc->sched;
>   	mutex_init(&ctx->mutex);
>   	INIT_LIST_HEAD(&ctx->link);
>   
> @@ -696,9 +788,7 @@ __create_context(struct drm_i915_private *i915)
>   	 * is no remap info, it will be a NOP. */
>   	ctx->remap_slice = ALL_L3_SLICES(i915);
>   
> -	i915_gem_context_set_bannable(ctx);
> -	i915_gem_context_set_recoverable(ctx);
> -	__context_set_persistence(ctx, true /* cgroup hook? */);
> +	ctx->user_flags = pc->user_flags;
>   
>   	for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
>   		ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
> @@ -786,38 +876,23 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
>   }
>   
>   static struct i915_gem_context *
> -i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
> +i915_gem_create_context(struct drm_i915_private *i915,
> +			const struct i915_gem_proto_context *pc)
>   {
>   	struct i915_gem_context *ctx;
>   	int ret;
>   
> -	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
> -	    !HAS_EXECLISTS(i915))
> -		return ERR_PTR(-EINVAL);
> -
> -	ctx = __create_context(i915);
> +	ctx = __create_context(i915, pc);
>   	if (IS_ERR(ctx))
>   		return ctx;
>   
> -	if (HAS_FULL_PPGTT(i915)) {
> -		struct i915_ppgtt *ppgtt;
> -
> -		ppgtt = i915_ppgtt_create(&i915->gt);
> -		if (IS_ERR(ppgtt)) {
> -			drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> -				PTR_ERR(ppgtt));
> -			context_close(ctx);
> -			return ERR_CAST(ppgtt);
> -		}
> -
> +	if (pc->vm) {
>   		mutex_lock(&ctx->mutex);
> -		__assign_ppgtt(ctx, &ppgtt->vm);
> +		__assign_ppgtt(ctx, pc->vm);
>   		mutex_unlock(&ctx->mutex);
> -
> -		i915_vm_put(&ppgtt->vm);
>   	}
>   
> -	if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> +	if (pc->single_timeline) {
>   		ret = drm_syncobj_create(&ctx->syncobj,
>   					 DRM_SYNCOBJ_CREATE_SIGNALED,
>   					 NULL);
> @@ -883,6 +958,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>   			  struct drm_file *file)
>   {
>   	struct drm_i915_file_private *file_priv = file->driver_priv;
> +	struct i915_gem_proto_context *pc;
>   	struct i915_gem_context *ctx;
>   	int err;
>   	u32 id;
> @@ -892,7 +968,14 @@ int i915_gem_context_open(struct drm_i915_private *i915,
>   	/* 0 reserved for invalid/unassigned ppgtt */
>   	xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
>   
> -	ctx = i915_gem_create_context(i915, 0);
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc)) {
> +		err = PTR_ERR(pc);
> +		goto err;
> +	}
> +
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>   	if (IS_ERR(ctx)) {
>   		err = PTR_ERR(ctx);
>   		goto err;
> @@ -1885,6 +1968,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>   {
>   	struct drm_i915_private *i915 = to_i915(dev);
>   	struct drm_i915_gem_context_create_ext *args = data;
> +	struct i915_gem_proto_context *pc;
>   	struct create_ext ext_data;
>   	int ret;
>   	u32 id;
> @@ -1907,7 +1991,12 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
>   		return -EIO;
>   	}
>   
> -	ext_data.ctx = i915_gem_create_context(i915, args->flags);
> +	pc = proto_context_create(i915, args->flags);
> +	if (IS_ERR(pc))
> +		return PTR_ERR(pc);
> +
> +	ext_data.ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>   	if (IS_ERR(ext_data.ctx))
>   		return PTR_ERR(ext_data.ctx);
>   
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> index 5f0673a2129f9..0bf337b6d89ac 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> @@ -66,6 +66,28 @@ struct i915_gem_engines_iter {
>   	const struct i915_gem_engines *engines;
>   };
>   
> +/**
> + * struct i915_gem_proto_context - prototype context
> + *
> + * The struct i915_gem_proto_context represents the creation parameters for
> + * an i915_gem_context.  This is used to gather parameters provided either
> + * through creation flags or via SET_CONTEXT_PARAM so that, when we create
> + * the final i915_gem_context, those parameters can be immutable.
> + */
> +struct i915_gem_proto_context {
> +	/** @vm: See i915_gem_context::vm */
> +	struct i915_address_space *vm;
> +
> +	/** @user_flags: See i915_gem_context::user_flags */
> +	unsigned long user_flags;
> +
> +	/** @sched: See i915_gem_context::sched */
> +	struct i915_sched_attr sched;
> +
> +	/** @single_timeline: See See i915_gem_context::syncobj */
> +	bool single_timeline;
> +};
> +
>   /**
>    * struct i915_gem_context - client state
>    *
> diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> index 51b5a3421b400..e0f512ef7f3c6 100644
> --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> @@ -80,11 +80,17 @@ void mock_init_contexts(struct drm_i915_private *i915)
>   struct i915_gem_context *
>   live_context(struct drm_i915_private *i915, struct file *file)
>   {
> +	struct i915_gem_proto_context *pc;
>   	struct i915_gem_context *ctx;
>   	int err;
>   	u32 id;
>   
> -	ctx = i915_gem_create_context(i915, 0);
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc))
> +		return ERR_CAST(pc);
> +
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>   	if (IS_ERR(ctx))
>   		return ctx;
>   
> @@ -142,8 +148,14 @@ struct i915_gem_context *
>   kernel_context(struct drm_i915_private *i915)
>   {
>   	struct i915_gem_context *ctx;
> +	struct i915_gem_proto_context *pc;
> +
> +	pc = proto_context_create(i915, 0);
> +	if (IS_ERR(pc))
> +		return ERR_CAST(pc);
>   
> -	ctx = i915_gem_create_context(i915, 0);
> +	ctx = i915_gem_create_context(i915, pc);
> +	proto_context_close(pc);
>   	if (IS_ERR(ctx))
>   		return ctx;
>   
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 02/27] drm/i915: Stop storing the ring size in the ring pointer
  2021-05-04  8:47     ` [Intel-gfx] " Daniel Vetter
@ 2021-05-14 18:06       ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-14 18:06 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 3:47 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:23AM -0500, Jason Ekstrand wrote:
> > Previously, we were storing the ring size in the ring pointer before it
> > was actually allocated.  We would then guard setting the ring size on
> > checking for CONTEXT_ALLOC_BIT.  This is error-prone at best and really
> > only saves us a few bytes on something that already burns at least 4K.
> > Instead, this patch adds a new ring_size field and makes everything use
> > that.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 3 +--
> >  drivers/gpu/drm/i915/gt/intel_context.c       | 3 ++-
> >  drivers/gpu/drm/i915/gt/intel_context.h       | 5 -----
> >  drivers/gpu/drm/i915/gt/intel_context_types.h | 1 +
> >  drivers/gpu/drm/i915/gt/intel_lrc.c           | 2 +-
> >  drivers/gpu/drm/i915/gt/selftest_execlists.c  | 2 +-
> >  drivers/gpu/drm/i915/gt/selftest_mocs.c       | 2 +-
> >  drivers/gpu/drm/i915/gt/selftest_timeline.c   | 2 +-
> >  drivers/gpu/drm/i915/gvt/scheduler.c          | 7 ++-----
> >  9 files changed, 10 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index e52b85b8f923d..2ba4c7e4011b4 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -211,8 +211,7 @@ static void intel_context_set_gem(struct intel_context *ce,
> >       GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
> >       RCU_INIT_POINTER(ce->gem_context, ctx);
> >
> > -     if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags))
> > -             ce->ring = __intel_context_ring_size(SZ_16K);
> > +     ce->ring_size = SZ_16K;
> >
> >       if (rcu_access_pointer(ctx->vm)) {
> >               struct i915_address_space *vm;
> > diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c
> > index 17cf2640b082b..342fa7daa08b5 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_context.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_context.c
> > @@ -372,7 +372,8 @@ intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine)
> >       ce->engine = engine;
> >       ce->ops = engine->cops;
> >       ce->sseu = engine->sseu;
> > -     ce->ring = __intel_context_ring_size(SZ_4K);
> > +     ce->ring = NULL;
> > +     ce->ring_size = SZ_4K;
> >
> >       ewma_runtime_init(&ce->runtime.avg);
> >
> > diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h
> > index f83a73a2b39fc..b10cbe8fee992 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_context.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_context.h
> > @@ -175,11 +175,6 @@ int intel_context_prepare_remote_request(struct intel_context *ce,
> >
> >  struct i915_request *intel_context_create_request(struct intel_context *ce);
> >
> > -static inline struct intel_ring *__intel_context_ring_size(u64 sz)
> > -{
> > -     return u64_to_ptr(struct intel_ring, sz);
> > -}
> > -
> >  static inline bool intel_context_is_barrier(const struct intel_context *ce)
> >  {
> >       return test_bit(CONTEXT_BARRIER_BIT, &ce->flags);
> > diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
> > index ed8c447a7346b..90026c1771055 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_context_types.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
> > @@ -82,6 +82,7 @@ struct intel_context {
> >       spinlock_t signal_lock; /* protects signals, the list of requests */
> >
> >       struct i915_vma *state;
> > +     u32 ring_size;
> >       struct intel_ring *ring;
> >       struct intel_timeline *timeline;
> >
> > diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
> > index e86897cde9846..63193c80fb117 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_lrc.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
> > @@ -845,7 +845,7 @@ int lrc_alloc(struct intel_context *ce, struct intel_engine_cs *engine)
> >       if (IS_ERR(vma))
> >               return PTR_ERR(vma);
> >
> > -     ring = intel_engine_create_ring(engine, (unsigned long)ce->ring);
> > +     ring = intel_engine_create_ring(engine, ce->ring_size);
> >       if (IS_ERR(ring)) {
> >               err = PTR_ERR(ring);
> >               goto err_vma;
> > diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > index 1081cd36a2bd3..01d9896dd4844 100644
> > --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > @@ -2793,7 +2793,7 @@ static int __live_preempt_ring(struct intel_engine_cs *engine,
> >                       goto err_ce;
> >               }
> >
> > -             tmp->ring = __intel_context_ring_size(ring_sz);
> > +             tmp->ring_size = ring_sz;
> >
> >               err = intel_context_pin(tmp);
> >               if (err) {
> > diff --git a/drivers/gpu/drm/i915/gt/selftest_mocs.c b/drivers/gpu/drm/i915/gt/selftest_mocs.c
> > index e55a887d11e2b..f343fa5fd986f 100644
> > --- a/drivers/gpu/drm/i915/gt/selftest_mocs.c
> > +++ b/drivers/gpu/drm/i915/gt/selftest_mocs.c
> > @@ -28,7 +28,7 @@ static struct intel_context *mocs_context_create(struct intel_engine_cs *engine)
> >               return ce;
> >
> >       /* We build large requests to read the registers from the ring */
> > -     ce->ring = __intel_context_ring_size(SZ_16K);
> > +     ce->ring_size = SZ_16K;
> >
> >       return ce;
> >  }
> > diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c
> > index 9adbd9d147bea..7eedecfb86e59 100644
> > --- a/drivers/gpu/drm/i915/gt/selftest_timeline.c
> > +++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c
> > @@ -874,7 +874,7 @@ static int create_watcher(struct hwsp_watcher *w,
> >       if (IS_ERR(ce))
> >               return PTR_ERR(ce);
> >
> > -     ce->ring = __intel_context_ring_size(ringsz);
> > +     ce->ring_size = ringsz;
> >       w->rq = intel_context_create_request(ce);
> >       intel_context_put(ce);
> >       if (IS_ERR(w->rq))
> > diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
> > index fc735692f21fb..99bc9fed6fbb6 100644
> > --- a/drivers/gpu/drm/i915/gvt/scheduler.c
> > +++ b/drivers/gpu/drm/i915/gvt/scheduler.c
> > @@ -1409,11 +1409,8 @@ int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
> >               intel_context_set_single_submission(ce);
> >
> >               /* Max ring buffer size */
> > -             if (!intel_uc_wants_guc_submission(&engine->gt->uc)) {
> > -                     const unsigned int ring_size = 512 * SZ_4K;
> > -
> > -                     ce->ring = __intel_context_ring_size(ring_size);
> > -             }
> > +             if (!intel_uc_wants_guc_submission(&engine->gt->uc))
> > +                     ce->ring_size = 512 * SZ_4K;
>
> A rather funny way of saying SZ_2M. Maybe fix that if you feel like. W/ or
> w/o that:

Done.

> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>
> >
> >               s->shadow[i] = ce;
> >       }
> > --
> > 2.31.1
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 02/27] drm/i915: Stop storing the ring size in the ring pointer
@ 2021-05-14 18:06       ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-14 18:06 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 3:47 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:23AM -0500, Jason Ekstrand wrote:
> > Previously, we were storing the ring size in the ring pointer before it
> > was actually allocated.  We would then guard setting the ring size on
> > checking for CONTEXT_ALLOC_BIT.  This is error-prone at best and really
> > only saves us a few bytes on something that already burns at least 4K.
> > Instead, this patch adds a new ring_size field and makes everything use
> > that.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 3 +--
> >  drivers/gpu/drm/i915/gt/intel_context.c       | 3 ++-
> >  drivers/gpu/drm/i915/gt/intel_context.h       | 5 -----
> >  drivers/gpu/drm/i915/gt/intel_context_types.h | 1 +
> >  drivers/gpu/drm/i915/gt/intel_lrc.c           | 2 +-
> >  drivers/gpu/drm/i915/gt/selftest_execlists.c  | 2 +-
> >  drivers/gpu/drm/i915/gt/selftest_mocs.c       | 2 +-
> >  drivers/gpu/drm/i915/gt/selftest_timeline.c   | 2 +-
> >  drivers/gpu/drm/i915/gvt/scheduler.c          | 7 ++-----
> >  9 files changed, 10 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index e52b85b8f923d..2ba4c7e4011b4 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -211,8 +211,7 @@ static void intel_context_set_gem(struct intel_context *ce,
> >       GEM_BUG_ON(rcu_access_pointer(ce->gem_context));
> >       RCU_INIT_POINTER(ce->gem_context, ctx);
> >
> > -     if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags))
> > -             ce->ring = __intel_context_ring_size(SZ_16K);
> > +     ce->ring_size = SZ_16K;
> >
> >       if (rcu_access_pointer(ctx->vm)) {
> >               struct i915_address_space *vm;
> > diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c
> > index 17cf2640b082b..342fa7daa08b5 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_context.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_context.c
> > @@ -372,7 +372,8 @@ intel_context_init(struct intel_context *ce, struct intel_engine_cs *engine)
> >       ce->engine = engine;
> >       ce->ops = engine->cops;
> >       ce->sseu = engine->sseu;
> > -     ce->ring = __intel_context_ring_size(SZ_4K);
> > +     ce->ring = NULL;
> > +     ce->ring_size = SZ_4K;
> >
> >       ewma_runtime_init(&ce->runtime.avg);
> >
> > diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h
> > index f83a73a2b39fc..b10cbe8fee992 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_context.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_context.h
> > @@ -175,11 +175,6 @@ int intel_context_prepare_remote_request(struct intel_context *ce,
> >
> >  struct i915_request *intel_context_create_request(struct intel_context *ce);
> >
> > -static inline struct intel_ring *__intel_context_ring_size(u64 sz)
> > -{
> > -     return u64_to_ptr(struct intel_ring, sz);
> > -}
> > -
> >  static inline bool intel_context_is_barrier(const struct intel_context *ce)
> >  {
> >       return test_bit(CONTEXT_BARRIER_BIT, &ce->flags);
> > diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h
> > index ed8c447a7346b..90026c1771055 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_context_types.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h
> > @@ -82,6 +82,7 @@ struct intel_context {
> >       spinlock_t signal_lock; /* protects signals, the list of requests */
> >
> >       struct i915_vma *state;
> > +     u32 ring_size;
> >       struct intel_ring *ring;
> >       struct intel_timeline *timeline;
> >
> > diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
> > index e86897cde9846..63193c80fb117 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_lrc.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
> > @@ -845,7 +845,7 @@ int lrc_alloc(struct intel_context *ce, struct intel_engine_cs *engine)
> >       if (IS_ERR(vma))
> >               return PTR_ERR(vma);
> >
> > -     ring = intel_engine_create_ring(engine, (unsigned long)ce->ring);
> > +     ring = intel_engine_create_ring(engine, ce->ring_size);
> >       if (IS_ERR(ring)) {
> >               err = PTR_ERR(ring);
> >               goto err_vma;
> > diff --git a/drivers/gpu/drm/i915/gt/selftest_execlists.c b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > index 1081cd36a2bd3..01d9896dd4844 100644
> > --- a/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > +++ b/drivers/gpu/drm/i915/gt/selftest_execlists.c
> > @@ -2793,7 +2793,7 @@ static int __live_preempt_ring(struct intel_engine_cs *engine,
> >                       goto err_ce;
> >               }
> >
> > -             tmp->ring = __intel_context_ring_size(ring_sz);
> > +             tmp->ring_size = ring_sz;
> >
> >               err = intel_context_pin(tmp);
> >               if (err) {
> > diff --git a/drivers/gpu/drm/i915/gt/selftest_mocs.c b/drivers/gpu/drm/i915/gt/selftest_mocs.c
> > index e55a887d11e2b..f343fa5fd986f 100644
> > --- a/drivers/gpu/drm/i915/gt/selftest_mocs.c
> > +++ b/drivers/gpu/drm/i915/gt/selftest_mocs.c
> > @@ -28,7 +28,7 @@ static struct intel_context *mocs_context_create(struct intel_engine_cs *engine)
> >               return ce;
> >
> >       /* We build large requests to read the registers from the ring */
> > -     ce->ring = __intel_context_ring_size(SZ_16K);
> > +     ce->ring_size = SZ_16K;
> >
> >       return ce;
> >  }
> > diff --git a/drivers/gpu/drm/i915/gt/selftest_timeline.c b/drivers/gpu/drm/i915/gt/selftest_timeline.c
> > index 9adbd9d147bea..7eedecfb86e59 100644
> > --- a/drivers/gpu/drm/i915/gt/selftest_timeline.c
> > +++ b/drivers/gpu/drm/i915/gt/selftest_timeline.c
> > @@ -874,7 +874,7 @@ static int create_watcher(struct hwsp_watcher *w,
> >       if (IS_ERR(ce))
> >               return PTR_ERR(ce);
> >
> > -     ce->ring = __intel_context_ring_size(ringsz);
> > +     ce->ring_size = ringsz;
> >       w->rq = intel_context_create_request(ce);
> >       intel_context_put(ce);
> >       if (IS_ERR(w->rq))
> > diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
> > index fc735692f21fb..99bc9fed6fbb6 100644
> > --- a/drivers/gpu/drm/i915/gvt/scheduler.c
> > +++ b/drivers/gpu/drm/i915/gvt/scheduler.c
> > @@ -1409,11 +1409,8 @@ int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
> >               intel_context_set_single_submission(ce);
> >
> >               /* Max ring buffer size */
> > -             if (!intel_uc_wants_guc_submission(&engine->gt->uc)) {
> > -                     const unsigned int ring_size = 512 * SZ_4K;
> > -
> > -                     ce->ring = __intel_context_ring_size(ring_size);
> > -             }
> > +             if (!intel_uc_wants_guc_submission(&engine->gt->uc))
> > +                     ce->ring_size = 512 * SZ_4K;
>
> A rather funny way of saying SZ_2M. Maybe fix that if you feel like. W/ or
> w/o that:

Done.

> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>
> >
> >               s->shadow[i] = ce;
> >       }
> > --
> > 2.31.1
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 06/27] drm/i915: Drop the CONTEXT_CLONE API
  2021-05-04  8:50     ` Daniel Vetter
@ 2021-05-14 18:07       ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-14 18:07 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 3:50 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:27AM -0500, Jason Ekstrand wrote:
> > This API allows one context to grab bits out of another context upon
> > creation.  It can be used as a short-cut for setparam(getparam()) for
> > things like I915_CONTEXT_PARAM_VM.  However, it's never been used by any
> > real userspace.  It's used by a few IGT tests and that's it.  Since it
> > doesn't add any real value (most of the stuff you can CLONE you can copy
> > in other ways), drop it.
> >
> > There is one thing that this API allows you to clone which you cannot
> > clone via getparam/setparam: timelines.  However, timelines are an
> > implementation detail of i915 and not really something that needs to be
> > exposed to userspace.  Also, sharing timelines between contexts isn't
> > obviously useful and supporting it has the potential to complicate i915
> > internally.  It also doesn't add any functionality that the client can't
> > get in other ways.  If a client really wants a shared timeline, they can
> > use a syncobj and set it as an in and out fence on every submit.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>
> This aint gitlab MR, so please include a per-patch (and also per-revision)
> changelog summary here. With that added:

I don't think this patch has changed.  I'll scroll through to make sure, though.

> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 199 +-----------------
> >  .../drm/i915/gt/intel_execlists_submission.c  |  28 ---
> >  .../drm/i915/gt/intel_execlists_submission.h  |   3 -
> >  include/uapi/drm/i915_drm.h                   |  16 +-
> >  4 files changed, 6 insertions(+), 240 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index d6f342e605254..308a63f778faf 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -1958,207 +1958,14 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
> >       return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> >  }
> >
> > -static int clone_engines(struct i915_gem_context *dst,
> > -                      struct i915_gem_context *src)
> > +static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> >  {
> > -     struct i915_gem_engines *clone, *e;
> > -     bool user_engines;
> > -     unsigned long n;
> > -
> > -     e = __context_engines_await(src, &user_engines);
> > -     if (!e)
> > -             return -ENOENT;
> > -
> > -     clone = alloc_engines(e->num_engines);
> > -     if (!clone)
> > -             goto err_unlock;
> > -
> > -     for (n = 0; n < e->num_engines; n++) {
> > -             struct intel_engine_cs *engine;
> > -
> > -             if (!e->engines[n]) {
> > -                     clone->engines[n] = NULL;
> > -                     continue;
> > -             }
> > -             engine = e->engines[n]->engine;
> > -
> > -             /*
> > -              * Virtual engines are singletons; they can only exist
> > -              * inside a single context, because they embed their
> > -              * HW context... As each virtual context implies a single
> > -              * timeline (each engine can only dequeue a single request
> > -              * at any time), it would be surprising for two contexts
> > -              * to use the same engine. So let's create a copy of
> > -              * the virtual engine instead.
> > -              */
> > -             if (intel_engine_is_virtual(engine))
> > -                     clone->engines[n] =
> > -                             intel_execlists_clone_virtual(engine);
> > -             else
> > -                     clone->engines[n] = intel_context_create(engine);
> > -             if (IS_ERR_OR_NULL(clone->engines[n])) {
> > -                     __free_engines(clone, n);
> > -                     goto err_unlock;
> > -             }
> > -
> > -             intel_context_set_gem(clone->engines[n], dst);
> > -     }
> > -     clone->num_engines = n;
> > -     i915_sw_fence_complete(&e->fence);
> > -
> > -     /* Serialised by constructor */
> > -     engines_idle_release(dst, rcu_replace_pointer(dst->engines, clone, 1));
> > -     if (user_engines)
> > -             i915_gem_context_set_user_engines(dst);
> > -     else
> > -             i915_gem_context_clear_user_engines(dst);
> > -     return 0;
> > -
> > -err_unlock:
> > -     i915_sw_fence_complete(&e->fence);
> > -     return -ENOMEM;
> > -}
> > -
> > -static int clone_flags(struct i915_gem_context *dst,
> > -                    struct i915_gem_context *src)
> > -{
> > -     dst->user_flags = src->user_flags;
> > -     return 0;
> > -}
> > -
> > -static int clone_schedattr(struct i915_gem_context *dst,
> > -                        struct i915_gem_context *src)
> > -{
> > -     dst->sched = src->sched;
> > -     return 0;
> > -}
> > -
> > -static int clone_sseu(struct i915_gem_context *dst,
> > -                   struct i915_gem_context *src)
> > -{
> > -     struct i915_gem_engines *e = i915_gem_context_lock_engines(src);
> > -     struct i915_gem_engines *clone;
> > -     unsigned long n;
> > -     int err;
> > -
> > -     /* no locking required; sole access under constructor*/
> > -     clone = __context_engines_static(dst);
> > -     if (e->num_engines != clone->num_engines) {
> > -             err = -EINVAL;
> > -             goto unlock;
> > -     }
> > -
> > -     for (n = 0; n < e->num_engines; n++) {
> > -             struct intel_context *ce = e->engines[n];
> > -
> > -             if (clone->engines[n]->engine->class != ce->engine->class) {
> > -                     /* Must have compatible engine maps! */
> > -                     err = -EINVAL;
> > -                     goto unlock;
> > -             }
> > -
> > -             /* serialises with set_sseu */
> > -             err = intel_context_lock_pinned(ce);
> > -             if (err)
> > -                     goto unlock;
> > -
> > -             clone->engines[n]->sseu = ce->sseu;
> > -             intel_context_unlock_pinned(ce);
> > -     }
> > -
> > -     err = 0;
> > -unlock:
> > -     i915_gem_context_unlock_engines(src);
> > -     return err;
> > -}
> > -
> > -static int clone_timeline(struct i915_gem_context *dst,
> > -                       struct i915_gem_context *src)
> > -{
> > -     if (src->timeline)
> > -             __assign_timeline(dst, src->timeline);
> > -
> > -     return 0;
> > -}
> > -
> > -static int clone_vm(struct i915_gem_context *dst,
> > -                 struct i915_gem_context *src)
> > -{
> > -     struct i915_address_space *vm;
> > -     int err = 0;
> > -
> > -     if (!rcu_access_pointer(src->vm))
> > -             return 0;
> > -
> > -     rcu_read_lock();
> > -     vm = context_get_vm_rcu(src);
> > -     rcu_read_unlock();
> > -
> > -     if (!mutex_lock_interruptible(&dst->mutex)) {
> > -             __assign_ppgtt(dst, vm);
> > -             mutex_unlock(&dst->mutex);
> > -     } else {
> > -             err = -EINTR;
> > -     }
> > -
> > -     i915_vm_put(vm);
> > -     return err;
> > -}
> > -
> > -static int create_clone(struct i915_user_extension __user *ext, void *data)
> > -{
> > -     static int (* const fn[])(struct i915_gem_context *dst,
> > -                               struct i915_gem_context *src) = {
> > -#define MAP(x, y) [ilog2(I915_CONTEXT_CLONE_##x)] = y
> > -             MAP(ENGINES, clone_engines),
> > -             MAP(FLAGS, clone_flags),
> > -             MAP(SCHEDATTR, clone_schedattr),
> > -             MAP(SSEU, clone_sseu),
> > -             MAP(TIMELINE, clone_timeline),
> > -             MAP(VM, clone_vm),
> > -#undef MAP
> > -     };
> > -     struct drm_i915_gem_context_create_ext_clone local;
> > -     const struct create_ext *arg = data;
> > -     struct i915_gem_context *dst = arg->ctx;
> > -     struct i915_gem_context *src;
> > -     int err, bit;
> > -
> > -     if (copy_from_user(&local, ext, sizeof(local)))
> > -             return -EFAULT;
> > -
> > -     BUILD_BUG_ON(GENMASK(BITS_PER_TYPE(local.flags) - 1, ARRAY_SIZE(fn)) !=
> > -                  I915_CONTEXT_CLONE_UNKNOWN);
> > -
> > -     if (local.flags & I915_CONTEXT_CLONE_UNKNOWN)
> > -             return -EINVAL;
> > -
> > -     if (local.rsvd)
> > -             return -EINVAL;
> > -
> > -     rcu_read_lock();
> > -     src = __i915_gem_context_lookup_rcu(arg->fpriv, local.clone_id);
> > -     rcu_read_unlock();
> > -     if (!src)
> > -             return -ENOENT;
> > -
> > -     GEM_BUG_ON(src == dst);
> > -
> > -     for (bit = 0; bit < ARRAY_SIZE(fn); bit++) {
> > -             if (!(local.flags & BIT(bit)))
> > -                     continue;
> > -
> > -             err = fn[bit](dst, src);
> > -             if (err)
> > -                     return err;
> > -     }
> > -
> > -     return 0;
> > +     return -EINVAL;
> >  }
> >
> >  static const i915_user_extension_fn create_extensions[] = {
> >       [I915_CONTEXT_CREATE_EXT_SETPARAM] = create_setparam,
> > -     [I915_CONTEXT_CREATE_EXT_CLONE] = create_clone,
> > +     [I915_CONTEXT_CREATE_EXT_CLONE] = invalid_ext,
> >  };
> >
> >  static bool client_is_banned(struct drm_i915_file_private *file_priv)
> > diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > index de124870af44d..0e8c320927d15 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > @@ -3736,34 +3736,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
> >       return ERR_PTR(err);
> >  }
> >
> > -struct intel_context *
> > -intel_execlists_clone_virtual(struct intel_engine_cs *src)
> > -{
> > -     struct virtual_engine *se = to_virtual_engine(src);
> > -     struct intel_context *dst;
> > -
> > -     dst = intel_execlists_create_virtual(se->siblings,
> > -                                          se->num_siblings);
> > -     if (IS_ERR(dst))
> > -             return dst;
> > -
> > -     if (se->num_bonds) {
> > -             struct virtual_engine *de = to_virtual_engine(dst->engine);
> > -
> > -             de->bonds = kmemdup(se->bonds,
> > -                                 sizeof(*se->bonds) * se->num_bonds,
> > -                                 GFP_KERNEL);
> > -             if (!de->bonds) {
> > -                     intel_context_put(dst);
> > -                     return ERR_PTR(-ENOMEM);
> > -             }
> > -
> > -             de->num_bonds = se->num_bonds;
> > -     }
> > -
> > -     return dst;
> > -}
> > -
> >  int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
> >                                    const struct intel_engine_cs *master,
> >                                    const struct intel_engine_cs *sibling)
> > diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> > index fd61dae820e9e..bab3d37cf3f98 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> > @@ -36,9 +36,6 @@ struct intel_context *
> >  intel_execlists_create_virtual(struct intel_engine_cs **siblings,
> >                              unsigned int count);
> >
> > -struct intel_context *
> > -intel_execlists_clone_virtual(struct intel_engine_cs *src);
> > -
> >  int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
> >                                    const struct intel_engine_cs *master,
> >                                    const struct intel_engine_cs *sibling);
> > diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
> > index a0aaa8298f28d..75a71b6756ed8 100644
> > --- a/include/uapi/drm/i915_drm.h
> > +++ b/include/uapi/drm/i915_drm.h
> > @@ -1887,20 +1887,10 @@ struct drm_i915_gem_context_create_ext_setparam {
> >       struct drm_i915_gem_context_param param;
> >  };
> >
> > -struct drm_i915_gem_context_create_ext_clone {
> > +/* This API has been removed.  On the off chance someone somewhere has
> > + * attempted to use it, never re-use this extension number.
> > + */
> >  #define I915_CONTEXT_CREATE_EXT_CLONE 1
> > -     struct i915_user_extension base;
> > -     __u32 clone_id;
> > -     __u32 flags;
> > -#define I915_CONTEXT_CLONE_ENGINES   (1u << 0)
> > -#define I915_CONTEXT_CLONE_FLAGS     (1u << 1)
> > -#define I915_CONTEXT_CLONE_SCHEDATTR (1u << 2)
> > -#define I915_CONTEXT_CLONE_SSEU              (1u << 3)
> > -#define I915_CONTEXT_CLONE_TIMELINE  (1u << 4)
> > -#define I915_CONTEXT_CLONE_VM                (1u << 5)
> > -#define I915_CONTEXT_CLONE_UNKNOWN -(I915_CONTEXT_CLONE_VM << 1)
> > -     __u64 rsvd;
> > -};
> >
> >  struct drm_i915_gem_context_destroy {
> >       __u32 ctx_id;
> > --
> > 2.31.1
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 06/27] drm/i915: Drop the CONTEXT_CLONE API
@ 2021-05-14 18:07       ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-14 18:07 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 3:50 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:27AM -0500, Jason Ekstrand wrote:
> > This API allows one context to grab bits out of another context upon
> > creation.  It can be used as a short-cut for setparam(getparam()) for
> > things like I915_CONTEXT_PARAM_VM.  However, it's never been used by any
> > real userspace.  It's used by a few IGT tests and that's it.  Since it
> > doesn't add any real value (most of the stuff you can CLONE you can copy
> > in other ways), drop it.
> >
> > There is one thing that this API allows you to clone which you cannot
> > clone via getparam/setparam: timelines.  However, timelines are an
> > implementation detail of i915 and not really something that needs to be
> > exposed to userspace.  Also, sharing timelines between contexts isn't
> > obviously useful and supporting it has the potential to complicate i915
> > internally.  It also doesn't add any functionality that the client can't
> > get in other ways.  If a client really wants a shared timeline, they can
> > use a syncobj and set it as an in and out fence on every submit.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>
> This aint gitlab MR, so please include a per-patch (and also per-revision)
> changelog summary here. With that added:

I don't think this patch has changed.  I'll scroll through to make sure, though.

> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 199 +-----------------
> >  .../drm/i915/gt/intel_execlists_submission.c  |  28 ---
> >  .../drm/i915/gt/intel_execlists_submission.h  |   3 -
> >  include/uapi/drm/i915_drm.h                   |  16 +-
> >  4 files changed, 6 insertions(+), 240 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index d6f342e605254..308a63f778faf 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -1958,207 +1958,14 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
> >       return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> >  }
> >
> > -static int clone_engines(struct i915_gem_context *dst,
> > -                      struct i915_gem_context *src)
> > +static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> >  {
> > -     struct i915_gem_engines *clone, *e;
> > -     bool user_engines;
> > -     unsigned long n;
> > -
> > -     e = __context_engines_await(src, &user_engines);
> > -     if (!e)
> > -             return -ENOENT;
> > -
> > -     clone = alloc_engines(e->num_engines);
> > -     if (!clone)
> > -             goto err_unlock;
> > -
> > -     for (n = 0; n < e->num_engines; n++) {
> > -             struct intel_engine_cs *engine;
> > -
> > -             if (!e->engines[n]) {
> > -                     clone->engines[n] = NULL;
> > -                     continue;
> > -             }
> > -             engine = e->engines[n]->engine;
> > -
> > -             /*
> > -              * Virtual engines are singletons; they can only exist
> > -              * inside a single context, because they embed their
> > -              * HW context... As each virtual context implies a single
> > -              * timeline (each engine can only dequeue a single request
> > -              * at any time), it would be surprising for two contexts
> > -              * to use the same engine. So let's create a copy of
> > -              * the virtual engine instead.
> > -              */
> > -             if (intel_engine_is_virtual(engine))
> > -                     clone->engines[n] =
> > -                             intel_execlists_clone_virtual(engine);
> > -             else
> > -                     clone->engines[n] = intel_context_create(engine);
> > -             if (IS_ERR_OR_NULL(clone->engines[n])) {
> > -                     __free_engines(clone, n);
> > -                     goto err_unlock;
> > -             }
> > -
> > -             intel_context_set_gem(clone->engines[n], dst);
> > -     }
> > -     clone->num_engines = n;
> > -     i915_sw_fence_complete(&e->fence);
> > -
> > -     /* Serialised by constructor */
> > -     engines_idle_release(dst, rcu_replace_pointer(dst->engines, clone, 1));
> > -     if (user_engines)
> > -             i915_gem_context_set_user_engines(dst);
> > -     else
> > -             i915_gem_context_clear_user_engines(dst);
> > -     return 0;
> > -
> > -err_unlock:
> > -     i915_sw_fence_complete(&e->fence);
> > -     return -ENOMEM;
> > -}
> > -
> > -static int clone_flags(struct i915_gem_context *dst,
> > -                    struct i915_gem_context *src)
> > -{
> > -     dst->user_flags = src->user_flags;
> > -     return 0;
> > -}
> > -
> > -static int clone_schedattr(struct i915_gem_context *dst,
> > -                        struct i915_gem_context *src)
> > -{
> > -     dst->sched = src->sched;
> > -     return 0;
> > -}
> > -
> > -static int clone_sseu(struct i915_gem_context *dst,
> > -                   struct i915_gem_context *src)
> > -{
> > -     struct i915_gem_engines *e = i915_gem_context_lock_engines(src);
> > -     struct i915_gem_engines *clone;
> > -     unsigned long n;
> > -     int err;
> > -
> > -     /* no locking required; sole access under constructor*/
> > -     clone = __context_engines_static(dst);
> > -     if (e->num_engines != clone->num_engines) {
> > -             err = -EINVAL;
> > -             goto unlock;
> > -     }
> > -
> > -     for (n = 0; n < e->num_engines; n++) {
> > -             struct intel_context *ce = e->engines[n];
> > -
> > -             if (clone->engines[n]->engine->class != ce->engine->class) {
> > -                     /* Must have compatible engine maps! */
> > -                     err = -EINVAL;
> > -                     goto unlock;
> > -             }
> > -
> > -             /* serialises with set_sseu */
> > -             err = intel_context_lock_pinned(ce);
> > -             if (err)
> > -                     goto unlock;
> > -
> > -             clone->engines[n]->sseu = ce->sseu;
> > -             intel_context_unlock_pinned(ce);
> > -     }
> > -
> > -     err = 0;
> > -unlock:
> > -     i915_gem_context_unlock_engines(src);
> > -     return err;
> > -}
> > -
> > -static int clone_timeline(struct i915_gem_context *dst,
> > -                       struct i915_gem_context *src)
> > -{
> > -     if (src->timeline)
> > -             __assign_timeline(dst, src->timeline);
> > -
> > -     return 0;
> > -}
> > -
> > -static int clone_vm(struct i915_gem_context *dst,
> > -                 struct i915_gem_context *src)
> > -{
> > -     struct i915_address_space *vm;
> > -     int err = 0;
> > -
> > -     if (!rcu_access_pointer(src->vm))
> > -             return 0;
> > -
> > -     rcu_read_lock();
> > -     vm = context_get_vm_rcu(src);
> > -     rcu_read_unlock();
> > -
> > -     if (!mutex_lock_interruptible(&dst->mutex)) {
> > -             __assign_ppgtt(dst, vm);
> > -             mutex_unlock(&dst->mutex);
> > -     } else {
> > -             err = -EINTR;
> > -     }
> > -
> > -     i915_vm_put(vm);
> > -     return err;
> > -}
> > -
> > -static int create_clone(struct i915_user_extension __user *ext, void *data)
> > -{
> > -     static int (* const fn[])(struct i915_gem_context *dst,
> > -                               struct i915_gem_context *src) = {
> > -#define MAP(x, y) [ilog2(I915_CONTEXT_CLONE_##x)] = y
> > -             MAP(ENGINES, clone_engines),
> > -             MAP(FLAGS, clone_flags),
> > -             MAP(SCHEDATTR, clone_schedattr),
> > -             MAP(SSEU, clone_sseu),
> > -             MAP(TIMELINE, clone_timeline),
> > -             MAP(VM, clone_vm),
> > -#undef MAP
> > -     };
> > -     struct drm_i915_gem_context_create_ext_clone local;
> > -     const struct create_ext *arg = data;
> > -     struct i915_gem_context *dst = arg->ctx;
> > -     struct i915_gem_context *src;
> > -     int err, bit;
> > -
> > -     if (copy_from_user(&local, ext, sizeof(local)))
> > -             return -EFAULT;
> > -
> > -     BUILD_BUG_ON(GENMASK(BITS_PER_TYPE(local.flags) - 1, ARRAY_SIZE(fn)) !=
> > -                  I915_CONTEXT_CLONE_UNKNOWN);
> > -
> > -     if (local.flags & I915_CONTEXT_CLONE_UNKNOWN)
> > -             return -EINVAL;
> > -
> > -     if (local.rsvd)
> > -             return -EINVAL;
> > -
> > -     rcu_read_lock();
> > -     src = __i915_gem_context_lookup_rcu(arg->fpriv, local.clone_id);
> > -     rcu_read_unlock();
> > -     if (!src)
> > -             return -ENOENT;
> > -
> > -     GEM_BUG_ON(src == dst);
> > -
> > -     for (bit = 0; bit < ARRAY_SIZE(fn); bit++) {
> > -             if (!(local.flags & BIT(bit)))
> > -                     continue;
> > -
> > -             err = fn[bit](dst, src);
> > -             if (err)
> > -                     return err;
> > -     }
> > -
> > -     return 0;
> > +     return -EINVAL;
> >  }
> >
> >  static const i915_user_extension_fn create_extensions[] = {
> >       [I915_CONTEXT_CREATE_EXT_SETPARAM] = create_setparam,
> > -     [I915_CONTEXT_CREATE_EXT_CLONE] = create_clone,
> > +     [I915_CONTEXT_CREATE_EXT_CLONE] = invalid_ext,
> >  };
> >
> >  static bool client_is_banned(struct drm_i915_file_private *file_priv)
> > diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > index de124870af44d..0e8c320927d15 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > @@ -3736,34 +3736,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
> >       return ERR_PTR(err);
> >  }
> >
> > -struct intel_context *
> > -intel_execlists_clone_virtual(struct intel_engine_cs *src)
> > -{
> > -     struct virtual_engine *se = to_virtual_engine(src);
> > -     struct intel_context *dst;
> > -
> > -     dst = intel_execlists_create_virtual(se->siblings,
> > -                                          se->num_siblings);
> > -     if (IS_ERR(dst))
> > -             return dst;
> > -
> > -     if (se->num_bonds) {
> > -             struct virtual_engine *de = to_virtual_engine(dst->engine);
> > -
> > -             de->bonds = kmemdup(se->bonds,
> > -                                 sizeof(*se->bonds) * se->num_bonds,
> > -                                 GFP_KERNEL);
> > -             if (!de->bonds) {
> > -                     intel_context_put(dst);
> > -                     return ERR_PTR(-ENOMEM);
> > -             }
> > -
> > -             de->num_bonds = se->num_bonds;
> > -     }
> > -
> > -     return dst;
> > -}
> > -
> >  int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
> >                                    const struct intel_engine_cs *master,
> >                                    const struct intel_engine_cs *sibling)
> > diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> > index fd61dae820e9e..bab3d37cf3f98 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.h
> > @@ -36,9 +36,6 @@ struct intel_context *
> >  intel_execlists_create_virtual(struct intel_engine_cs **siblings,
> >                              unsigned int count);
> >
> > -struct intel_context *
> > -intel_execlists_clone_virtual(struct intel_engine_cs *src);
> > -
> >  int intel_virtual_engine_attach_bond(struct intel_engine_cs *engine,
> >                                    const struct intel_engine_cs *master,
> >                                    const struct intel_engine_cs *sibling);
> > diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
> > index a0aaa8298f28d..75a71b6756ed8 100644
> > --- a/include/uapi/drm/i915_drm.h
> > +++ b/include/uapi/drm/i915_drm.h
> > @@ -1887,20 +1887,10 @@ struct drm_i915_gem_context_create_ext_setparam {
> >       struct drm_i915_gem_context_param param;
> >  };
> >
> > -struct drm_i915_gem_context_create_ext_clone {
> > +/* This API has been removed.  On the off chance someone somewhere has
> > + * attempted to use it, never re-use this extension number.
> > + */
> >  #define I915_CONTEXT_CREATE_EXT_CLONE 1
> > -     struct i915_user_extension base;
> > -     __u32 clone_id;
> > -     __u32 flags;
> > -#define I915_CONTEXT_CLONE_ENGINES   (1u << 0)
> > -#define I915_CONTEXT_CLONE_FLAGS     (1u << 1)
> > -#define I915_CONTEXT_CLONE_SCHEDATTR (1u << 2)
> > -#define I915_CONTEXT_CLONE_SSEU              (1u << 3)
> > -#define I915_CONTEXT_CLONE_TIMELINE  (1u << 4)
> > -#define I915_CONTEXT_CLONE_VM                (1u << 5)
> > -#define I915_CONTEXT_CLONE_UNKNOWN -(I915_CONTEXT_CLONE_VM << 1)
> > -     __u64 rsvd;
> > -};
> >
> >  struct drm_i915_gem_context_destroy {
> >       __u32 ctx_id;
> > --
> > 2.31.1
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 10/27] drm/i915/gem: Remove engine auto-magic with FENCE_SUBMIT
  2021-05-04  8:56     ` [Intel-gfx] " Daniel Vetter
@ 2021-05-14 18:19       ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-14 18:19 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 3:56 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:31AM -0500, Jason Ekstrand wrote:
> > Even though FENCE_SUBMIT is only documented to wait until the request in
> > the in-fence starts instead of waiting until it completes, it has a bit
> > more magic than that.  If FENCE_SUBMIT is used to submit something to a
> > balanced engine, we would wait to assign engines until the primary
> > request was ready to start and then attempt to assign it to a different
> > engine than the primary.  There is an IGT test which exercises this by
> > submitting a primary batch to a specific VCS and then using FENCE_SUBMIT
> > to submit a secondary which can run on any VCS and have i915 figure out
> > which VCS to run it on such that they can run in parallel.
> >
> > However, this functionality has never been used in the real world.  The
> > media driver (the only user of FENCE_SUBMIT) always picks exactly two
> > physical engines to bond and never asks us to pick which to use.
>
> Maybe reference the specific igt you're break (and removing in the igt
> series to match this) here. Just for the record and all that.

Done.

> -Daniel
>
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c  |  2 +-
> >  drivers/gpu/drm/i915/gt/intel_engine_types.h    |  7 -------
> >  .../drm/i915/gt/intel_execlists_submission.c    | 17 -----------------
> >  3 files changed, 1 insertion(+), 25 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > index d640bba6ad9ab..efb2fa3522a42 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > @@ -3474,7 +3474,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
> >               if (args->flags & I915_EXEC_FENCE_SUBMIT)
> >                       err = i915_request_await_execution(eb.request,
> >                                                          in_fence,
> > -                                                        eb.engine->bond_execute);
> > +                                                        NULL);
> >               else
> >                       err = i915_request_await_dma_fence(eb.request,
> >                                                          in_fence);
> > diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
> > index 883bafc449024..68cfe5080325c 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
> > @@ -446,13 +446,6 @@ struct intel_engine_cs {
> >        */
> >       void            (*submit_request)(struct i915_request *rq);
> >
> > -     /*
> > -      * Called on signaling of a SUBMIT_FENCE, passing along the signaling
> > -      * request down to the bonded pairs.
> > -      */
> > -     void            (*bond_execute)(struct i915_request *rq,
> > -                                     struct dma_fence *signal);
> > -
> >       /*
> >        * Call when the priority on a request has changed and it and its
> >        * dependencies may need rescheduling. Note the request itself may
> > diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > index 14378b28169b7..635d6d2494d26 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > @@ -3547,22 +3547,6 @@ static void virtual_submit_request(struct i915_request *rq)
> >       spin_unlock_irqrestore(&ve->base.active.lock, flags);
> >  }
> >
> > -static void
> > -virtual_bond_execute(struct i915_request *rq, struct dma_fence *signal)
> > -{
> > -     intel_engine_mask_t allowed, exec;
> > -
> > -     allowed = ~to_request(signal)->engine->mask;
> > -
> > -     /* Restrict the bonded request to run on only the available engines */
> > -     exec = READ_ONCE(rq->execution_mask);
> > -     while (!try_cmpxchg(&rq->execution_mask, &exec, exec & allowed))
> > -             ;
> > -
> > -     /* Prevent the master from being re-run on the bonded engines */
> > -     to_request(signal)->execution_mask &= ~allowed;
> > -}
> > -
> >  struct intel_context *
> >  intel_execlists_create_virtual(struct intel_engine_cs **siblings,
> >                              unsigned int count)
> > @@ -3616,7 +3600,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
> >
> >       ve->base.schedule = i915_schedule;
> >       ve->base.submit_request = virtual_submit_request;
> > -     ve->base.bond_execute = virtual_bond_execute;
> >
> >       INIT_LIST_HEAD(virtual_queue(ve));
> >       ve->base.execlists.queue_priority_hint = INT_MIN;
> > --
> > 2.31.1
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 10/27] drm/i915/gem: Remove engine auto-magic with FENCE_SUBMIT
@ 2021-05-14 18:19       ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-14 18:19 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 3:56 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:31AM -0500, Jason Ekstrand wrote:
> > Even though FENCE_SUBMIT is only documented to wait until the request in
> > the in-fence starts instead of waiting until it completes, it has a bit
> > more magic than that.  If FENCE_SUBMIT is used to submit something to a
> > balanced engine, we would wait to assign engines until the primary
> > request was ready to start and then attempt to assign it to a different
> > engine than the primary.  There is an IGT test which exercises this by
> > submitting a primary batch to a specific VCS and then using FENCE_SUBMIT
> > to submit a secondary which can run on any VCS and have i915 figure out
> > which VCS to run it on such that they can run in parallel.
> >
> > However, this functionality has never been used in the real world.  The
> > media driver (the only user of FENCE_SUBMIT) always picks exactly two
> > physical engines to bond and never asks us to pick which to use.
>
> Maybe reference the specific igt you're break (and removing in the igt
> series to match this) here. Just for the record and all that.

Done.

> -Daniel
>
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c  |  2 +-
> >  drivers/gpu/drm/i915/gt/intel_engine_types.h    |  7 -------
> >  .../drm/i915/gt/intel_execlists_submission.c    | 17 -----------------
> >  3 files changed, 1 insertion(+), 25 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > index d640bba6ad9ab..efb2fa3522a42 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
> > @@ -3474,7 +3474,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
> >               if (args->flags & I915_EXEC_FENCE_SUBMIT)
> >                       err = i915_request_await_execution(eb.request,
> >                                                          in_fence,
> > -                                                        eb.engine->bond_execute);
> > +                                                        NULL);
> >               else
> >                       err = i915_request_await_dma_fence(eb.request,
> >                                                          in_fence);
> > diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
> > index 883bafc449024..68cfe5080325c 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
> > +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
> > @@ -446,13 +446,6 @@ struct intel_engine_cs {
> >        */
> >       void            (*submit_request)(struct i915_request *rq);
> >
> > -     /*
> > -      * Called on signaling of a SUBMIT_FENCE, passing along the signaling
> > -      * request down to the bonded pairs.
> > -      */
> > -     void            (*bond_execute)(struct i915_request *rq,
> > -                                     struct dma_fence *signal);
> > -
> >       /*
> >        * Call when the priority on a request has changed and it and its
> >        * dependencies may need rescheduling. Note the request itself may
> > diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > index 14378b28169b7..635d6d2494d26 100644
> > --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
> > @@ -3547,22 +3547,6 @@ static void virtual_submit_request(struct i915_request *rq)
> >       spin_unlock_irqrestore(&ve->base.active.lock, flags);
> >  }
> >
> > -static void
> > -virtual_bond_execute(struct i915_request *rq, struct dma_fence *signal)
> > -{
> > -     intel_engine_mask_t allowed, exec;
> > -
> > -     allowed = ~to_request(signal)->engine->mask;
> > -
> > -     /* Restrict the bonded request to run on only the available engines */
> > -     exec = READ_ONCE(rq->execution_mask);
> > -     while (!try_cmpxchg(&rq->execution_mask, &exec, exec & allowed))
> > -             ;
> > -
> > -     /* Prevent the master from being re-run on the bonded engines */
> > -     to_request(signal)->execution_mask &= ~allowed;
> > -}
> > -
> >  struct intel_context *
> >  intel_execlists_create_virtual(struct intel_engine_cs **siblings,
> >                              unsigned int count)
> > @@ -3616,7 +3600,6 @@ intel_execlists_create_virtual(struct intel_engine_cs **siblings,
> >
> >       ve->base.schedule = i915_schedule;
> >       ve->base.submit_request = virtual_submit_request;
> > -     ve->base.bond_execute = virtual_bond_execute;
> >
> >       INIT_LIST_HEAD(virtual_queue(ve));
> >       ve->base.execlists.queue_priority_hint = INT_MIN;
> > --
> > 2.31.1
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 17/27] drm/i915/gem: Rework error handling in default_engines
  2021-05-04 16:17     ` Daniel Vetter
@ 2021-05-14 18:21       ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-14 18:21 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 11:17 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:38AM -0500, Jason Ekstrand wrote:
> > Since free_engines works for partially constructed engine sets, we can
> > use the usual goto pattern.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
>
> I guess subsequent patches apply the same for the set_engines command and
> __free_engines disappears? Otherwise feels a bit silly.

Working towards that.

> Anyway looks correct.
>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_context.c | 13 ++++++++-----
> >  1 file changed, 8 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index 10bd1b6dd1774..ce729e640bbf7 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -420,7 +420,7 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> >  {
> >       const struct intel_gt *gt = &ctx->i915->gt;
> >       struct intel_engine_cs *engine;
> > -     struct i915_gem_engines *e;
> > +     struct i915_gem_engines *e, *err;
> >       enum intel_engine_id id;
> >
> >       e = alloc_engines(I915_NUM_ENGINES);
> > @@ -438,18 +438,21 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> >
> >               ce = intel_context_create(engine);
> >               if (IS_ERR(ce)) {
> > -                     __free_engines(e, e->num_engines + 1);
> > -                     return ERR_CAST(ce);
> > +                     err = ERR_CAST(ce);
> > +                     goto free_engines;
> >               }
> >
> >               intel_context_set_gem(ce, ctx);
> >
> >               e->engines[engine->legacy_idx] = ce;
> > -             e->num_engines = max(e->num_engines, engine->legacy_idx);
> > +             e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
> >       }
> > -     e->num_engines++;
> >
> >       return e;
> > +
> > +free_engines:
> > +     free_engines(e);
> > +     return err;
> >  }
> >
> >  void i915_gem_context_release(struct kref *ref)
> > --
> > 2.31.1
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 17/27] drm/i915/gem: Rework error handling in default_engines
@ 2021-05-14 18:21       ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-14 18:21 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 11:17 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:38AM -0500, Jason Ekstrand wrote:
> > Since free_engines works for partially constructed engine sets, we can
> > use the usual goto pattern.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
>
> I guess subsequent patches apply the same for the set_engines command and
> __free_engines disappears? Otherwise feels a bit silly.

Working towards that.

> Anyway looks correct.
>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_context.c | 13 ++++++++-----
> >  1 file changed, 8 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index 10bd1b6dd1774..ce729e640bbf7 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -420,7 +420,7 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> >  {
> >       const struct intel_gt *gt = &ctx->i915->gt;
> >       struct intel_engine_cs *engine;
> > -     struct i915_gem_engines *e;
> > +     struct i915_gem_engines *e, *err;
> >       enum intel_engine_id id;
> >
> >       e = alloc_engines(I915_NUM_ENGINES);
> > @@ -438,18 +438,21 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
> >
> >               ce = intel_context_create(engine);
> >               if (IS_ERR(ce)) {
> > -                     __free_engines(e, e->num_engines + 1);
> > -                     return ERR_CAST(ce);
> > +                     err = ERR_CAST(ce);
> > +                     goto free_engines;
> >               }
> >
> >               intel_context_set_gem(ce, ctx);
> >
> >               e->engines[engine->legacy_idx] = ce;
> > -             e->num_engines = max(e->num_engines, engine->legacy_idx);
> > +             e->num_engines = max(e->num_engines, engine->legacy_idx + 1);
> >       }
> > -     e->num_engines++;
> >
> >       return e;
> > +
> > +free_engines:
> > +     free_engines(e);
> > +     return err;
> >  }
> >
> >  void i915_gem_context_release(struct kref *ref)
> > --
> > 2.31.1
> >
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
  2021-05-04 20:33     ` [Intel-gfx] " Daniel Vetter
@ 2021-05-14 19:13       ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-14 19:13 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 3:33 PM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:40AM -0500, Jason Ekstrand wrote:
> > This means that the proto-context needs to grow support for engine
> > configuration information as well as setparam logic.  Fortunately, we'll
> > be deleting a lot of setparam logic on the primary context shortly so it
> > will hopefully balance out.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
> >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
> >  2 files changed, 587 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index 6dd50d669c5b9..aa4edfbf7ed48 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
> >
> >  static void proto_context_close(struct i915_gem_proto_context *pc)
> >  {
> > +     int i;
> > +
> >       if (pc->vm)
> >               i915_vm_put(pc->vm);
> > +     if (pc->user_engines) {
> > +             for (i = 0; i < pc->num_user_engines; i++)
> > +                     kfree(pc->user_engines[i].siblings);
> > +             kfree(pc->user_engines);
>
>                 free_engines(&pc->user_engines);
>
> Maybe even stuff that if check into free_engines. Except I realized this
> is proto engines here now :-(
>
> > +     }
> >       kfree(pc);
> >  }
> >
> > @@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> >       if (!pc)
> >               return ERR_PTR(-ENOMEM);
> >
> > +     pc->num_user_engines = -1;
> > +     pc->user_engines = NULL;
> > +
> >       if (HAS_FULL_PPGTT(i915)) {
> >               struct i915_ppgtt *ppgtt;
> >
> > @@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> >       return err;
> >  }
> >
> > +static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
> > +                         struct i915_gem_proto_context *pc,
> > +                         const struct drm_i915_gem_context_param *args)
> > +{
> > +     struct i915_address_space *vm;
> > +
> > +     if (args->size)
> > +             return -EINVAL;
> > +
> > +     if (!pc->vm)
> > +             return -ENODEV;
> > +
> > +     if (upper_32_bits(args->value))
> > +             return -ENOENT;
> > +
> > +     rcu_read_lock();
> > +     vm = xa_load(&fpriv->vm_xa, args->value);
> > +     if (vm && !kref_get_unless_zero(&vm->ref))
> > +             vm = NULL;
> > +     rcu_read_unlock();
>
> vm lookup helpers would be nice I guess, but perhaps something that
> vm_bind patches should do.

I can add those.  I just don't know where to put it.  We don't have an
i915_gem_vm.h.  Suggestions?

>
> > +     if (!vm)
> > +             return -ENOENT;
> > +
> > +     i915_vm_put(pc->vm);
>
> Ah I guess I've found why you went with "pc->vm is always set". *shrug*
>
> > +     pc->vm = vm;
> > +
> > +     return 0;
> > +}
> > +
> > +struct set_proto_ctx_engines {
> > +     struct drm_i915_private *i915;
> > +     unsigned num_engines;
> > +     struct i915_gem_proto_engine *engines;
> > +};
> > +
> > +static int
> > +set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
> > +                           void *data)
> > +{
> > +     struct i915_context_engines_load_balance __user *ext =
> > +             container_of_user(base, typeof(*ext), base);
> > +     const struct set_proto_ctx_engines *set = data;
> > +     struct drm_i915_private *i915 = set->i915;
> > +     struct intel_engine_cs **siblings;
> > +     u16 num_siblings, idx;
> > +     unsigned int n;
> > +     int err;
> > +
> > +     if (!HAS_EXECLISTS(i915))
> > +             return -ENODEV;
> > +
> > +     if (intel_uc_uses_guc_submission(&i915->gt.uc))
> > +             return -ENODEV; /* not implement yet */
> > +
> > +     if (get_user(idx, &ext->engine_index))
> > +             return -EFAULT;
> > +
> > +     if (idx >= set->num_engines) {
> > +             drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> > +                     idx, set->num_engines);
> > +             return -EINVAL;
> > +     }
> > +
> > +     idx = array_index_nospec(idx, set->num_engines);
> > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
> > +             drm_dbg(&i915->drm,
> > +                     "Invalid placement[%d], already occupied\n", idx);
> > +             return -EEXIST;
> > +     }
> > +
> > +     if (get_user(num_siblings, &ext->num_siblings))
> > +             return -EFAULT;
> > +
> > +     err = check_user_mbz(&ext->flags);
> > +     if (err)
> > +             return err;
> > +
> > +     err = check_user_mbz(&ext->mbz64);
> > +     if (err)
> > +             return err;
> > +
> > +     if (num_siblings == 0)
> > +             return 0;
>
> You deleted the on-stack siblings micro-optimization.
>
> I'm shocked.

Yup.  If balanced engine create overhead when balancing across a
single engine ever becomes a bottleneck in some UMD, I'm happy to deal
with it then.  And I intend to deal with it by banning whatever
developer decided balancing across single engine was a good idea.

> > +
> > +     siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);
>
> If you want to pay back your micro-opt budget: GFP_TEMPORARY.
>
> But then I realized much wiser heads than me removed this in 2017 from the
> kernel! That commit is a rather interesting story btw, if you're bored:
>
> commit 0ee931c4e31a5efb134c76440405e9219f896e33
> Author: Michal Hocko <mhocko@suse.com>
> Date:   Wed Sep 13 16:28:29 2017 -0700
>
>     mm: treewide: remove GFP_TEMPORARY allocation flag
>
> > +     if (!siblings)
> > +             return -ENOMEM;
> > +
> > +     for (n = 0; n < num_siblings; n++) {
> > +             struct i915_engine_class_instance ci;
> > +
> > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> > +                     err = -EFAULT;
> > +                     goto err_siblings;
> > +             }
> > +
> > +             siblings[n] = intel_engine_lookup_user(i915,
> > +                                                    ci.engine_class,
> > +                                                    ci.engine_instance);
>
> intel_engine_user.c
>
> ...
>
> Maybe I should just stop looking.

Don't think too hard.  It hurts.

> > +             if (!siblings[n]) {
> > +                     drm_dbg(&i915->drm,
> > +                             "Invalid sibling[%d]: { class:%d, inst:%d }\n",
> > +                             n, ci.engine_class, ci.engine_instance);
> > +                     err = -EINVAL;
> > +                     goto err_siblings;
> > +             }
> > +     }
> > +
> > +     if (num_siblings == 1) {
> > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > +             set->engines[idx].engine = siblings[0];
> > +             kfree(siblings);
> > +     } else {
> > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
> > +             set->engines[idx].num_siblings = num_siblings;
> > +             set->engines[idx].siblings = siblings;
> > +     }
> > +
> > +     return 0;
> > +
> > +err_siblings:
> > +     kfree(siblings);
> > +
> > +     return err;
> > +}
> > +
> > +static int
> > +set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
> > +{
> > +     struct i915_context_engines_bond __user *ext =
> > +             container_of_user(base, typeof(*ext), base);
> > +     const struct set_proto_ctx_engines *set = data;
> > +     struct drm_i915_private *i915 = set->i915;
> > +     struct i915_engine_class_instance ci;
> > +     struct intel_engine_cs *master;
> > +     u16 idx, num_bonds;
> > +     int err, n;
> > +
> > +     if (get_user(idx, &ext->virtual_index))
> > +             return -EFAULT;
> > +
> > +     if (idx >= set->num_engines) {
> > +             drm_dbg(&i915->drm,
> > +                     "Invalid index for virtual engine: %d >= %d\n",
> > +                     idx, set->num_engines);
> > +             return -EINVAL;
> > +     }
> > +
> > +     idx = array_index_nospec(idx, set->num_engines);
> > +     if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
> > +             drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> > +             return -EINVAL;
> > +     }
> > +
> > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
> > +             drm_dbg(&i915->drm,
> > +                     "Bonding with virtual engines not allowed\n");
> > +             return -EINVAL;
> > +     }
> > +
> > +     err = check_user_mbz(&ext->flags);
> > +     if (err)
> > +             return err;
> > +
> > +     for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> > +             err = check_user_mbz(&ext->mbz64[n]);
> > +             if (err)
> > +                     return err;
> > +     }
> > +
> > +     if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> > +             return -EFAULT;
> > +
> > +     master = intel_engine_lookup_user(i915,
> > +                                       ci.engine_class,
> > +                                       ci.engine_instance);
> > +     if (!master) {
>
> It's 100% orthogonal annoyance, but maybe we can start the "what's a good
> name here" discussion.
>
> I'm thinking s/master/first/ and s/slave/subsequent/ that reflect how this
> is actually used on the execbuf side. But then this entire bonded
> extension is so disconnected from the actual use-case, maybe we should
> just sun-set it before we bother.

primary/secondary come to mind.  But, also, I'd rather do that as a
separate patch since I was trying to make this mostly match.  Happy to
up my i915 patch count with a rename follow-on, if you want.

> Since we might need to keep the execlist backend implementation the
> renaming might still be needed.
>
> > +             drm_dbg(&i915->drm,
> > +                     "Unrecognised master engine: { class:%u, instance:%u }\n",
> > +                     ci.engine_class, ci.engine_instance);
> > +             return -EINVAL;
> > +     }
> > +
> > +     if (get_user(num_bonds, &ext->num_bonds))
> > +             return -EFAULT;
> > +
> > +     for (n = 0; n < num_bonds; n++) {
> > +             struct intel_engine_cs *bond;
> > +
> > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> > +                     return -EFAULT;
> > +
> > +             bond = intel_engine_lookup_user(i915,
> > +                                             ci.engine_class,
> > +                                             ci.engine_instance);
> > +             if (!bond) {
> > +                     drm_dbg(&i915->drm,
> > +                             "Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> > +                             n, ci.engine_class, ci.engine_instance);
> > +                     return -EINVAL;
> > +             }
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
> > +     [I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
> > +     [I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
> > +};
> > +
> > +static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
> > +                              struct i915_gem_proto_context *pc,
> > +                              const struct drm_i915_gem_context_param *args)
> > +{
> > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > +     struct set_proto_ctx_engines set = { .i915 = i915 };
> > +     struct i915_context_param_engines __user *user =
> > +             u64_to_user_ptr(args->value);
> > +     unsigned int n;
> > +     u64 extensions;
> > +     int err;
> > +
> > +     if (!args->size) {
> > +             kfree(pc->user_engines);
> > +             pc->num_user_engines = -1;
>
> Is this case actually used by actual userspace, or just more stuff igt
> loved to do?
>
> If so more uapi to ditch, and check in an igt that it's rejected.
>
> Plus standard !args->size handling here with appropriate drm_debug line
> and all that.
>
> > +             pc->user_engines = NULL;
> > +             memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
> > +             return 0;
> > +     }
> > +
> > +     BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
>
> I frankly don't know what this is checking, but it also looks harmless.

Yeah..... All I can see is that it lets us avoid doing a subtraction
in the alignment check below.  Kind-of silly, IMO.

> > +     if (args->size < sizeof(*user) ||
> > +         !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> > +             drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> > +                     args->size);
> > +             return -EINVAL;
> > +     }
> > +
> > +     set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> > +     /* RING_MASK has no shift so we can use it directly here */
> > +     if (set.num_engines > I915_EXEC_RING_MASK + 1)
> > +             return -EINVAL;
> > +
> > +     set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
> > +     if (!set.engines)
> > +             return -ENOMEM;
> > +
> > +     for (n = 0; n < set.num_engines; n++) {
> > +             struct i915_engine_class_instance ci;
> > +             struct intel_engine_cs *engine;
> > +
> > +             if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> > +                     kfree(set.engines);
> > +                     return -EFAULT;
> > +             }
> > +
> > +             memset(&set.engines[n], 0, sizeof(set.engines[n]));
> > +
> > +             if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> > +                 ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
> > +                     continue;
> > +
> > +             engine = intel_engine_lookup_user(i915,
> > +                                               ci.engine_class,
> > +                                               ci.engine_instance);
> > +             if (!engine) {
> > +                     drm_dbg(&i915->drm,
> > +                             "Invalid engine[%d]: { class:%d, instance:%d }\n",
> > +                             n, ci.engine_class, ci.engine_instance);
> > +                     kfree(set.engines);
> > +                     return -ENOENT;
> > +             }
> > +
> > +             set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > +             set.engines[n].engine = engine;
> > +     }
> > +
> > +     err = -EFAULT;
> > +     if (!get_user(extensions, &user->extensions))
> > +             err = i915_user_extensions(u64_to_user_ptr(extensions),
> > +                                        set_proto_ctx_engines_extensions,
> > +                                        ARRAY_SIZE(set_proto_ctx_engines_extensions),
> > +                                        &set);
> > +     if (err) {
> > +             kfree(set.engines);
> > +             return err;
> > +     }
> > +
> > +     kfree(pc->user_engines);
>
> Both of these kfree potentially leak engines[].siblings. I think you need
> to extract a proto_context_free_engines helper and use that 2x here and
> once at the very top in proto_context_close().

Good catch. Done.

> > +     pc->num_user_engines = set.num_engines;
> > +     pc->user_engines = set.engines;
> > +
> > +     return 0;
> > +}
> > +
> > +static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
> > +                           struct i915_gem_proto_context *pc,
> > +                           struct drm_i915_gem_context_param *args)
> > +{
> > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > +     struct drm_i915_gem_context_param_sseu user_sseu;
> > +     struct intel_sseu *sseu;
> > +     int ret;
> > +
> > +     if (args->size < sizeof(user_sseu))
> > +             return -EINVAL;
> > +
> > +     if (!IS_GEN(i915, 11))
> > +             return -ENODEV;
> > +
> > +     if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
> > +                        sizeof(user_sseu)))
> > +             return -EFAULT;
> > +
> > +     if (user_sseu.rsvd)
> > +             return -EINVAL;
> > +
> > +     if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
> > +             return -EINVAL;
> > +
> > +     if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
> > +             return -EINVAL;
> > +
> > +     if (pc->num_user_engines >= 0) {
> > +             int idx = user_sseu.engine.engine_instance;
> > +             struct i915_gem_proto_engine *pe;
> > +
> > +             if (idx >= pc->num_user_engines)
> > +                     return -EINVAL;
> > +
> > +             pe = &pc->user_engines[idx];
> > +
> > +             /* Only render engine supports RPCS configuration. */
> > +             if (pe->engine->class != RENDER_CLASS)
> > +                     return -EINVAL;
> > +
> > +             sseu = &pe->sseu;
> > +     } else {
> > +             /* Only render engine supports RPCS configuration. */
> > +             if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
> > +                     return -EINVAL;
> > +
> > +             /* There is only one render engine */
> > +             if (user_sseu.engine.engine_instance != 0)
> > +                     return -EINVAL;
> > +
> > +             sseu = &pc->legacy_rcs_sseu;
> > +     }
>
> I think this faithfully rebuilds the convoluted and I think largely
> accidental semantics of SSEU for all combinations of ordering against
> set_engines.
>
> Maybe add a commit message note about this particular kind of fun here. I
> don't think a code comment is warranted since I don't think I've seen a
> userspace rely on how sseu interacts with set_engines

Done.

> > +
> > +     ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
> > +     if (ret)
> > +             return ret;
> > +
> > +     args->size = sizeof(user_sseu);
> > +
> > +     return 0;
> > +}
> > +
> > +static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
> > +                            struct i915_gem_proto_context *pc,
> > +                            struct drm_i915_gem_context_param *args)
> > +{
> > +     int ret = 0;
> > +
> > +     switch (args->param) {
> > +     case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
> > +             if (args->size)
> > +                     ret = -EINVAL;
> > +             else if (args->value)
> > +                     __set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > +             else
> > +                     __clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
>
> Open code please and double check I caught them all ...

As I commented the first time around, __set/clear_bit are static
inlines that unroll to "*field |= (1 << bit)" or "*field &= ~(1 <<
bit)" as appropriate.  The non-__ versions do atomics.  I could
hand-roll them but that seems error-prone and it gains us nothing.

> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_BANNABLE:
> > +             if (args->size)
> > +                     ret = -EINVAL;
> > +             else if (!capable(CAP_SYS_ADMIN) && !args->value)
> > +                     ret = -EPERM;
> > +             else if (args->value)
> > +                     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > +             else
> > +                     __clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_RECOVERABLE:
> > +             if (args->size)
> > +                     ret = -EINVAL;
> > +             else if (args->value)
> > +                     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > +             else
> > +                     __clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_PRIORITY:
> > +             ret = validate_priority(fpriv->dev_priv, args);
> > +             if (!ret)
> > +                     pc->sched.priority = args->value;
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_SSEU:
> > +             ret = set_proto_ctx_sseu(fpriv, pc, args);
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_VM:
> > +             ret = set_proto_ctx_vm(fpriv, pc, args);
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_ENGINES:
> > +             ret = set_proto_ctx_engines(fpriv, pc, args);
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_PERSISTENCE:
> > +             if (args->size)
> > +                     ret = -EINVAL;
> > +             else if (args->value)
> > +                     __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > +             else
> > +                     __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
>
> I think we have a nice mess here. You created this
> proto_context_set_persistence helper, but don't use it here. Oversight?

Yeah, I should use it.  Done.

> Aside from the validation fun around persistence, but that's better
> discussed in another patch I think.
>
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_NO_ZEROMAP:
> > +     case I915_CONTEXT_PARAM_BAN_PERIOD:
> > +     case I915_CONTEXT_PARAM_RINGSIZE:
> > +     default:
> > +             ret = -EINVAL;
> > +             break;
> > +     }
> > +
> > +     return ret;
> > +}
> > +
> >  static struct i915_address_space *
> >  context_get_vm_rcu(struct i915_gem_context *ctx)
> >  {
> > @@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> >       return err;
> >  }
> >
> > +static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
> > +                                          unsigned int num_engines,
> > +                                          struct i915_gem_proto_engine *pe)
> > +{
> > +     struct i915_gem_engines *e, *err;
> > +     unsigned int n;
> > +
> > +     e = alloc_engines(num_engines);
> > +     for (n = 0; n < num_engines; n++) {
> > +             struct intel_context *ce;
> > +             int ret;
> > +
> > +             switch (pe[n].type) {
> > +             case I915_GEM_ENGINE_TYPE_PHYSICAL:
> > +                     ce = intel_context_create(pe[n].engine);
> > +                     break;
> > +
> > +             case I915_GEM_ENGINE_TYPE_BALANCED:
> > +                     ce = intel_execlists_create_virtual(pe[n].siblings,
> > +                                                         pe[n].num_siblings);
> > +                     break;
> > +
> > +             case I915_GEM_ENGINE_TYPE_INVALID:
> > +             default:
> > +                     GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
> > +                     continue;
> > +             }
> > +
> > +             if (IS_ERR(ce)) {
> > +                     err = ERR_CAST(ce);
> > +                     goto free_engines;
> > +             }
> > +
> > +             e->engines[n] = ce;
> > +
> > +             ret = intel_context_set_gem(ce, ctx, pe->sseu);
> > +             if (ret) {
> > +                     err = ERR_PTR(ret);
> > +                     goto free_engines;
> > +             }
> > +     }
> > +     e->num_engines = num_engines;
> > +
> > +     return e;
> > +
> > +free_engines:
> > +     free_engines(e);
> > +     return err;
> > +}
> > +
> >  void i915_gem_context_release(struct kref *ref)
> >  {
> >       struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
> > @@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
> >  {
> >       struct i915_gem_context *ctx;
> >       struct i915_gem_engines *e;
> > -     struct intel_sseu null_sseu = {};
> >       int err;
> >       int i;
> >
> > @@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
> >       INIT_LIST_HEAD(&ctx->stale.engines);
> >
> >       mutex_init(&ctx->engines_mutex);
> > -     e = default_engines(ctx, null_sseu);
> > +     e = default_engines(ctx, pc->legacy_rcs_sseu);
> >       if (IS_ERR(e)) {
> >               err = PTR_ERR(e);
> >               goto err_free;
> > @@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
> >               mutex_unlock(&ctx->mutex);
> >       }
> >
> > +     if (pc->num_user_engines >= 0) {
> > +             struct i915_gem_engines *engines;
> > +
> > +             engines = user_engines(ctx, pc->num_user_engines,
> > +                                    pc->user_engines);
> > +             if (IS_ERR(engines)) {
> > +                     context_close(ctx);
> > +                     return ERR_CAST(engines);
> > +             }
> > +
> > +             mutex_lock(&ctx->engines_mutex);
> > +             i915_gem_context_set_user_engines(ctx);
> > +             engines = rcu_replace_pointer(ctx->engines, engines, 1);
> > +             mutex_unlock(&ctx->engines_mutex);
>
> More locking code to ditch I guess.

Sure.  Is it safe to just drop it?  I guess it is?  I'm really shaky
around all the RCU requirements and things.

> > +
> > +             free_engines(engines);
>
> Also I guess we shouldn't first create the legacy engines for this case?

That's fixed in the last patch.

> > +     }
> > +
> >       if (pc->single_timeline) {
> >               ret = drm_syncobj_create(&ctx->syncobj,
> >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> > @@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
> >  }
> >
> >  struct create_ext {
> > -     struct i915_gem_context *ctx;
> > +     struct i915_gem_proto_context *pc;
> >       struct drm_i915_file_private *fpriv;
> >  };
> >
> > @@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
> >       if (local.param.ctx_id)
> >               return -EINVAL;
> >
> > -     return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> > +     return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
> >  }
> >
> >  static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> > @@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> >  {
> >       struct drm_i915_private *i915 = to_i915(dev);
> >       struct drm_i915_gem_context_create_ext *args = data;
> > -     struct i915_gem_proto_context *pc;
> > +     struct i915_gem_context *ctx;
> >       struct create_ext ext_data;
> >       int ret;
> >       u32 id;
> > @@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> >               return -EIO;
> >       }
> >
> > -     pc = proto_context_create(i915, args->flags);
> > -     if (IS_ERR(pc))
> > -             return PTR_ERR(pc);
> > -
> > -     ext_data.ctx = i915_gem_create_context(i915, pc);
> > -     proto_context_close(pc);
> > -     if (IS_ERR(ext_data.ctx))
> > -             return PTR_ERR(ext_data.ctx);
> > +     ext_data.pc = proto_context_create(i915, args->flags);
> > +     if (IS_ERR(ext_data.pc))
> > +             return PTR_ERR(ext_data.pc);
> >
> >       if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
> >               ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
> >                                          create_extensions,
> >                                          ARRAY_SIZE(create_extensions),
> >                                          &ext_data);
> > -             if (ret)
> > -                     goto err_ctx;
> > +             if (ret) {
> > +                     proto_context_close(ext_data.pc);
> > +                     return ret;
> > +             }
> >       }
> >
> > -     ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
> > +     ctx = i915_gem_create_context(i915, ext_data.pc);
> > +     proto_context_close(ext_data.pc);
> > +     if (IS_ERR(ctx))
> > +             return PTR_ERR(ctx);
> > +
> > +     ret = gem_context_register(ctx, ext_data.fpriv, &id);
> >       if (ret < 0)
> >               goto err_ctx;
> >
> > @@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> >       return 0;
> >
> >  err_ctx:
> > -     context_close(ext_data.ctx);
> > +     context_close(ctx);
> >       return ret;
> >  }
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > index 0bf337b6d89ac..2ac341f805c8f 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > @@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
> >       const struct i915_gem_engines *engines;
> >  };
> >
> > +/**
> > + * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
> > + */
> > +enum i915_gem_engine_type {
> > +     /** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
> > +     I915_GEM_ENGINE_TYPE_INVALID = 0,
> > +
> > +     /** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
> > +     I915_GEM_ENGINE_TYPE_PHYSICAL,
> > +
> > +     /** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
> > +     I915_GEM_ENGINE_TYPE_BALANCED,
> > +};
> > +
> > +/**
> > + * struct i915_gem_proto_engine - prototype engine
> > + *
> > + * This struct describes an engine that a context may contain.  Engines
> > + * have three types:
> > + *
> > + *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
> > + *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
> > + *    use them by the user results in -EINVAL.  They are also useful during
> > + *    proto-context construction because the client may create invalid
> > + *    engines and then set them up later as bonded engines.
> > + *
> > + *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
> > + *    i915_gem_proto_engine::engine.
> > + *
> > + *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
> > + *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
> > + */
> > +struct i915_gem_proto_engine {
> > +     /** @type: Type of this engine */
> > +     enum i915_gem_engine_type type;
> > +
> > +     /** @engine: Engine, for physical */
> > +     struct intel_engine_cs *engine;
> > +
> > +     /** @num_siblings: Number of balanced siblings */
> > +     unsigned int num_siblings;
> > +
> > +     /** @siblings: Balanced siblings */
> > +     struct intel_engine_cs **siblings;
> > +
> > +     /** @sseu: Client-set SSEU parameters */
> > +     struct intel_sseu sseu;
> > +};
> > +
> >  /**
> >   * struct i915_gem_proto_context - prototype context
> >   *
> > @@ -84,6 +133,15 @@ struct i915_gem_proto_context {
> >       /** @sched: See i915_gem_context::sched */
> >       struct i915_sched_attr sched;
> >
> > +     /** @num_user_engines: Number of user-specified engines or -1 */
> > +     int num_user_engines;
> > +
> > +     /** @user_engines: User-specified engines */
> > +     struct i915_gem_proto_engine *user_engines;
> > +
> > +     /** @sseu: Client-set SSEU parameters for the legacy RCS */
> > +     struct intel_sseu legacy_rcs_sseu;
> > +
> >       /** @single_timeline: See See i915_gem_context::syncobj */
> >       bool single_timeline;
> >  };
> > --
> > 2.31.1
>
> Man is this all nasty. Since I don't want to re-review the entire pile,
> assuming we figure out solutions to all the real issues I've raised (and
> not the snarky bikesheds) this is
>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Ok.  I'm leaving it off for now to remind myself to ensure that we
close on everything.  I'll add it once I've heard back from you on my
questions above.

--Jason

> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
@ 2021-05-14 19:13       ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-14 19:13 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 3:33 PM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:40AM -0500, Jason Ekstrand wrote:
> > This means that the proto-context needs to grow support for engine
> > configuration information as well as setparam logic.  Fortunately, we'll
> > be deleting a lot of setparam logic on the primary context shortly so it
> > will hopefully balance out.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
> >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
> >  2 files changed, 587 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index 6dd50d669c5b9..aa4edfbf7ed48 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
> >
> >  static void proto_context_close(struct i915_gem_proto_context *pc)
> >  {
> > +     int i;
> > +
> >       if (pc->vm)
> >               i915_vm_put(pc->vm);
> > +     if (pc->user_engines) {
> > +             for (i = 0; i < pc->num_user_engines; i++)
> > +                     kfree(pc->user_engines[i].siblings);
> > +             kfree(pc->user_engines);
>
>                 free_engines(&pc->user_engines);
>
> Maybe even stuff that if check into free_engines. Except I realized this
> is proto engines here now :-(
>
> > +     }
> >       kfree(pc);
> >  }
> >
> > @@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> >       if (!pc)
> >               return ERR_PTR(-ENOMEM);
> >
> > +     pc->num_user_engines = -1;
> > +     pc->user_engines = NULL;
> > +
> >       if (HAS_FULL_PPGTT(i915)) {
> >               struct i915_ppgtt *ppgtt;
> >
> > @@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> >       return err;
> >  }
> >
> > +static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
> > +                         struct i915_gem_proto_context *pc,
> > +                         const struct drm_i915_gem_context_param *args)
> > +{
> > +     struct i915_address_space *vm;
> > +
> > +     if (args->size)
> > +             return -EINVAL;
> > +
> > +     if (!pc->vm)
> > +             return -ENODEV;
> > +
> > +     if (upper_32_bits(args->value))
> > +             return -ENOENT;
> > +
> > +     rcu_read_lock();
> > +     vm = xa_load(&fpriv->vm_xa, args->value);
> > +     if (vm && !kref_get_unless_zero(&vm->ref))
> > +             vm = NULL;
> > +     rcu_read_unlock();
>
> vm lookup helpers would be nice I guess, but perhaps something that
> vm_bind patches should do.

I can add those.  I just don't know where to put it.  We don't have an
i915_gem_vm.h.  Suggestions?

>
> > +     if (!vm)
> > +             return -ENOENT;
> > +
> > +     i915_vm_put(pc->vm);
>
> Ah I guess I've found why you went with "pc->vm is always set". *shrug*
>
> > +     pc->vm = vm;
> > +
> > +     return 0;
> > +}
> > +
> > +struct set_proto_ctx_engines {
> > +     struct drm_i915_private *i915;
> > +     unsigned num_engines;
> > +     struct i915_gem_proto_engine *engines;
> > +};
> > +
> > +static int
> > +set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
> > +                           void *data)
> > +{
> > +     struct i915_context_engines_load_balance __user *ext =
> > +             container_of_user(base, typeof(*ext), base);
> > +     const struct set_proto_ctx_engines *set = data;
> > +     struct drm_i915_private *i915 = set->i915;
> > +     struct intel_engine_cs **siblings;
> > +     u16 num_siblings, idx;
> > +     unsigned int n;
> > +     int err;
> > +
> > +     if (!HAS_EXECLISTS(i915))
> > +             return -ENODEV;
> > +
> > +     if (intel_uc_uses_guc_submission(&i915->gt.uc))
> > +             return -ENODEV; /* not implement yet */
> > +
> > +     if (get_user(idx, &ext->engine_index))
> > +             return -EFAULT;
> > +
> > +     if (idx >= set->num_engines) {
> > +             drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> > +                     idx, set->num_engines);
> > +             return -EINVAL;
> > +     }
> > +
> > +     idx = array_index_nospec(idx, set->num_engines);
> > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
> > +             drm_dbg(&i915->drm,
> > +                     "Invalid placement[%d], already occupied\n", idx);
> > +             return -EEXIST;
> > +     }
> > +
> > +     if (get_user(num_siblings, &ext->num_siblings))
> > +             return -EFAULT;
> > +
> > +     err = check_user_mbz(&ext->flags);
> > +     if (err)
> > +             return err;
> > +
> > +     err = check_user_mbz(&ext->mbz64);
> > +     if (err)
> > +             return err;
> > +
> > +     if (num_siblings == 0)
> > +             return 0;
>
> You deleted the on-stack siblings micro-optimization.
>
> I'm shocked.

Yup.  If balanced engine create overhead when balancing across a
single engine ever becomes a bottleneck in some UMD, I'm happy to deal
with it then.  And I intend to deal with it by banning whatever
developer decided balancing across single engine was a good idea.

> > +
> > +     siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);
>
> If you want to pay back your micro-opt budget: GFP_TEMPORARY.
>
> But then I realized much wiser heads than me removed this in 2017 from the
> kernel! That commit is a rather interesting story btw, if you're bored:
>
> commit 0ee931c4e31a5efb134c76440405e9219f896e33
> Author: Michal Hocko <mhocko@suse.com>
> Date:   Wed Sep 13 16:28:29 2017 -0700
>
>     mm: treewide: remove GFP_TEMPORARY allocation flag
>
> > +     if (!siblings)
> > +             return -ENOMEM;
> > +
> > +     for (n = 0; n < num_siblings; n++) {
> > +             struct i915_engine_class_instance ci;
> > +
> > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> > +                     err = -EFAULT;
> > +                     goto err_siblings;
> > +             }
> > +
> > +             siblings[n] = intel_engine_lookup_user(i915,
> > +                                                    ci.engine_class,
> > +                                                    ci.engine_instance);
>
> intel_engine_user.c
>
> ...
>
> Maybe I should just stop looking.

Don't think too hard.  It hurts.

> > +             if (!siblings[n]) {
> > +                     drm_dbg(&i915->drm,
> > +                             "Invalid sibling[%d]: { class:%d, inst:%d }\n",
> > +                             n, ci.engine_class, ci.engine_instance);
> > +                     err = -EINVAL;
> > +                     goto err_siblings;
> > +             }
> > +     }
> > +
> > +     if (num_siblings == 1) {
> > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > +             set->engines[idx].engine = siblings[0];
> > +             kfree(siblings);
> > +     } else {
> > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
> > +             set->engines[idx].num_siblings = num_siblings;
> > +             set->engines[idx].siblings = siblings;
> > +     }
> > +
> > +     return 0;
> > +
> > +err_siblings:
> > +     kfree(siblings);
> > +
> > +     return err;
> > +}
> > +
> > +static int
> > +set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
> > +{
> > +     struct i915_context_engines_bond __user *ext =
> > +             container_of_user(base, typeof(*ext), base);
> > +     const struct set_proto_ctx_engines *set = data;
> > +     struct drm_i915_private *i915 = set->i915;
> > +     struct i915_engine_class_instance ci;
> > +     struct intel_engine_cs *master;
> > +     u16 idx, num_bonds;
> > +     int err, n;
> > +
> > +     if (get_user(idx, &ext->virtual_index))
> > +             return -EFAULT;
> > +
> > +     if (idx >= set->num_engines) {
> > +             drm_dbg(&i915->drm,
> > +                     "Invalid index for virtual engine: %d >= %d\n",
> > +                     idx, set->num_engines);
> > +             return -EINVAL;
> > +     }
> > +
> > +     idx = array_index_nospec(idx, set->num_engines);
> > +     if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
> > +             drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> > +             return -EINVAL;
> > +     }
> > +
> > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
> > +             drm_dbg(&i915->drm,
> > +                     "Bonding with virtual engines not allowed\n");
> > +             return -EINVAL;
> > +     }
> > +
> > +     err = check_user_mbz(&ext->flags);
> > +     if (err)
> > +             return err;
> > +
> > +     for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> > +             err = check_user_mbz(&ext->mbz64[n]);
> > +             if (err)
> > +                     return err;
> > +     }
> > +
> > +     if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> > +             return -EFAULT;
> > +
> > +     master = intel_engine_lookup_user(i915,
> > +                                       ci.engine_class,
> > +                                       ci.engine_instance);
> > +     if (!master) {
>
> It's 100% orthogonal annoyance, but maybe we can start the "what's a good
> name here" discussion.
>
> I'm thinking s/master/first/ and s/slave/subsequent/ that reflect how this
> is actually used on the execbuf side. But then this entire bonded
> extension is so disconnected from the actual use-case, maybe we should
> just sun-set it before we bother.

primary/secondary come to mind.  But, also, I'd rather do that as a
separate patch since I was trying to make this mostly match.  Happy to
up my i915 patch count with a rename follow-on, if you want.

> Since we might need to keep the execlist backend implementation the
> renaming might still be needed.
>
> > +             drm_dbg(&i915->drm,
> > +                     "Unrecognised master engine: { class:%u, instance:%u }\n",
> > +                     ci.engine_class, ci.engine_instance);
> > +             return -EINVAL;
> > +     }
> > +
> > +     if (get_user(num_bonds, &ext->num_bonds))
> > +             return -EFAULT;
> > +
> > +     for (n = 0; n < num_bonds; n++) {
> > +             struct intel_engine_cs *bond;
> > +
> > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> > +                     return -EFAULT;
> > +
> > +             bond = intel_engine_lookup_user(i915,
> > +                                             ci.engine_class,
> > +                                             ci.engine_instance);
> > +             if (!bond) {
> > +                     drm_dbg(&i915->drm,
> > +                             "Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> > +                             n, ci.engine_class, ci.engine_instance);
> > +                     return -EINVAL;
> > +             }
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
> > +     [I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
> > +     [I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
> > +};
> > +
> > +static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
> > +                              struct i915_gem_proto_context *pc,
> > +                              const struct drm_i915_gem_context_param *args)
> > +{
> > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > +     struct set_proto_ctx_engines set = { .i915 = i915 };
> > +     struct i915_context_param_engines __user *user =
> > +             u64_to_user_ptr(args->value);
> > +     unsigned int n;
> > +     u64 extensions;
> > +     int err;
> > +
> > +     if (!args->size) {
> > +             kfree(pc->user_engines);
> > +             pc->num_user_engines = -1;
>
> Is this case actually used by actual userspace, or just more stuff igt
> loved to do?
>
> If so more uapi to ditch, and check in an igt that it's rejected.
>
> Plus standard !args->size handling here with appropriate drm_debug line
> and all that.
>
> > +             pc->user_engines = NULL;
> > +             memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
> > +             return 0;
> > +     }
> > +
> > +     BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
>
> I frankly don't know what this is checking, but it also looks harmless.

Yeah..... All I can see is that it lets us avoid doing a subtraction
in the alignment check below.  Kind-of silly, IMO.

> > +     if (args->size < sizeof(*user) ||
> > +         !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> > +             drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> > +                     args->size);
> > +             return -EINVAL;
> > +     }
> > +
> > +     set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> > +     /* RING_MASK has no shift so we can use it directly here */
> > +     if (set.num_engines > I915_EXEC_RING_MASK + 1)
> > +             return -EINVAL;
> > +
> > +     set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
> > +     if (!set.engines)
> > +             return -ENOMEM;
> > +
> > +     for (n = 0; n < set.num_engines; n++) {
> > +             struct i915_engine_class_instance ci;
> > +             struct intel_engine_cs *engine;
> > +
> > +             if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> > +                     kfree(set.engines);
> > +                     return -EFAULT;
> > +             }
> > +
> > +             memset(&set.engines[n], 0, sizeof(set.engines[n]));
> > +
> > +             if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> > +                 ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
> > +                     continue;
> > +
> > +             engine = intel_engine_lookup_user(i915,
> > +                                               ci.engine_class,
> > +                                               ci.engine_instance);
> > +             if (!engine) {
> > +                     drm_dbg(&i915->drm,
> > +                             "Invalid engine[%d]: { class:%d, instance:%d }\n",
> > +                             n, ci.engine_class, ci.engine_instance);
> > +                     kfree(set.engines);
> > +                     return -ENOENT;
> > +             }
> > +
> > +             set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > +             set.engines[n].engine = engine;
> > +     }
> > +
> > +     err = -EFAULT;
> > +     if (!get_user(extensions, &user->extensions))
> > +             err = i915_user_extensions(u64_to_user_ptr(extensions),
> > +                                        set_proto_ctx_engines_extensions,
> > +                                        ARRAY_SIZE(set_proto_ctx_engines_extensions),
> > +                                        &set);
> > +     if (err) {
> > +             kfree(set.engines);
> > +             return err;
> > +     }
> > +
> > +     kfree(pc->user_engines);
>
> Both of these kfree potentially leak engines[].siblings. I think you need
> to extract a proto_context_free_engines helper and use that 2x here and
> once at the very top in proto_context_close().

Good catch. Done.

> > +     pc->num_user_engines = set.num_engines;
> > +     pc->user_engines = set.engines;
> > +
> > +     return 0;
> > +}
> > +
> > +static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
> > +                           struct i915_gem_proto_context *pc,
> > +                           struct drm_i915_gem_context_param *args)
> > +{
> > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > +     struct drm_i915_gem_context_param_sseu user_sseu;
> > +     struct intel_sseu *sseu;
> > +     int ret;
> > +
> > +     if (args->size < sizeof(user_sseu))
> > +             return -EINVAL;
> > +
> > +     if (!IS_GEN(i915, 11))
> > +             return -ENODEV;
> > +
> > +     if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
> > +                        sizeof(user_sseu)))
> > +             return -EFAULT;
> > +
> > +     if (user_sseu.rsvd)
> > +             return -EINVAL;
> > +
> > +     if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
> > +             return -EINVAL;
> > +
> > +     if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
> > +             return -EINVAL;
> > +
> > +     if (pc->num_user_engines >= 0) {
> > +             int idx = user_sseu.engine.engine_instance;
> > +             struct i915_gem_proto_engine *pe;
> > +
> > +             if (idx >= pc->num_user_engines)
> > +                     return -EINVAL;
> > +
> > +             pe = &pc->user_engines[idx];
> > +
> > +             /* Only render engine supports RPCS configuration. */
> > +             if (pe->engine->class != RENDER_CLASS)
> > +                     return -EINVAL;
> > +
> > +             sseu = &pe->sseu;
> > +     } else {
> > +             /* Only render engine supports RPCS configuration. */
> > +             if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
> > +                     return -EINVAL;
> > +
> > +             /* There is only one render engine */
> > +             if (user_sseu.engine.engine_instance != 0)
> > +                     return -EINVAL;
> > +
> > +             sseu = &pc->legacy_rcs_sseu;
> > +     }
>
> I think this faithfully rebuilds the convoluted and I think largely
> accidental semantics of SSEU for all combinations of ordering against
> set_engines.
>
> Maybe add a commit message note about this particular kind of fun here. I
> don't think a code comment is warranted since I don't think I've seen a
> userspace rely on how sseu interacts with set_engines

Done.

> > +
> > +     ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
> > +     if (ret)
> > +             return ret;
> > +
> > +     args->size = sizeof(user_sseu);
> > +
> > +     return 0;
> > +}
> > +
> > +static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
> > +                            struct i915_gem_proto_context *pc,
> > +                            struct drm_i915_gem_context_param *args)
> > +{
> > +     int ret = 0;
> > +
> > +     switch (args->param) {
> > +     case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
> > +             if (args->size)
> > +                     ret = -EINVAL;
> > +             else if (args->value)
> > +                     __set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > +             else
> > +                     __clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
>
> Open code please and double check I caught them all ...

As I commented the first time around, __set/clear_bit are static
inlines that unroll to "*field |= (1 << bit)" or "*field &= ~(1 <<
bit)" as appropriate.  The non-__ versions do atomics.  I could
hand-roll them but that seems error-prone and it gains us nothing.

> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_BANNABLE:
> > +             if (args->size)
> > +                     ret = -EINVAL;
> > +             else if (!capable(CAP_SYS_ADMIN) && !args->value)
> > +                     ret = -EPERM;
> > +             else if (args->value)
> > +                     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > +             else
> > +                     __clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_RECOVERABLE:
> > +             if (args->size)
> > +                     ret = -EINVAL;
> > +             else if (args->value)
> > +                     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > +             else
> > +                     __clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_PRIORITY:
> > +             ret = validate_priority(fpriv->dev_priv, args);
> > +             if (!ret)
> > +                     pc->sched.priority = args->value;
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_SSEU:
> > +             ret = set_proto_ctx_sseu(fpriv, pc, args);
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_VM:
> > +             ret = set_proto_ctx_vm(fpriv, pc, args);
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_ENGINES:
> > +             ret = set_proto_ctx_engines(fpriv, pc, args);
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_PERSISTENCE:
> > +             if (args->size)
> > +                     ret = -EINVAL;
> > +             else if (args->value)
> > +                     __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > +             else
> > +                     __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
>
> I think we have a nice mess here. You created this
> proto_context_set_persistence helper, but don't use it here. Oversight?

Yeah, I should use it.  Done.

> Aside from the validation fun around persistence, but that's better
> discussed in another patch I think.
>
> > +             break;
> > +
> > +     case I915_CONTEXT_PARAM_NO_ZEROMAP:
> > +     case I915_CONTEXT_PARAM_BAN_PERIOD:
> > +     case I915_CONTEXT_PARAM_RINGSIZE:
> > +     default:
> > +             ret = -EINVAL;
> > +             break;
> > +     }
> > +
> > +     return ret;
> > +}
> > +
> >  static struct i915_address_space *
> >  context_get_vm_rcu(struct i915_gem_context *ctx)
> >  {
> > @@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> >       return err;
> >  }
> >
> > +static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
> > +                                          unsigned int num_engines,
> > +                                          struct i915_gem_proto_engine *pe)
> > +{
> > +     struct i915_gem_engines *e, *err;
> > +     unsigned int n;
> > +
> > +     e = alloc_engines(num_engines);
> > +     for (n = 0; n < num_engines; n++) {
> > +             struct intel_context *ce;
> > +             int ret;
> > +
> > +             switch (pe[n].type) {
> > +             case I915_GEM_ENGINE_TYPE_PHYSICAL:
> > +                     ce = intel_context_create(pe[n].engine);
> > +                     break;
> > +
> > +             case I915_GEM_ENGINE_TYPE_BALANCED:
> > +                     ce = intel_execlists_create_virtual(pe[n].siblings,
> > +                                                         pe[n].num_siblings);
> > +                     break;
> > +
> > +             case I915_GEM_ENGINE_TYPE_INVALID:
> > +             default:
> > +                     GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
> > +                     continue;
> > +             }
> > +
> > +             if (IS_ERR(ce)) {
> > +                     err = ERR_CAST(ce);
> > +                     goto free_engines;
> > +             }
> > +
> > +             e->engines[n] = ce;
> > +
> > +             ret = intel_context_set_gem(ce, ctx, pe->sseu);
> > +             if (ret) {
> > +                     err = ERR_PTR(ret);
> > +                     goto free_engines;
> > +             }
> > +     }
> > +     e->num_engines = num_engines;
> > +
> > +     return e;
> > +
> > +free_engines:
> > +     free_engines(e);
> > +     return err;
> > +}
> > +
> >  void i915_gem_context_release(struct kref *ref)
> >  {
> >       struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
> > @@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
> >  {
> >       struct i915_gem_context *ctx;
> >       struct i915_gem_engines *e;
> > -     struct intel_sseu null_sseu = {};
> >       int err;
> >       int i;
> >
> > @@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
> >       INIT_LIST_HEAD(&ctx->stale.engines);
> >
> >       mutex_init(&ctx->engines_mutex);
> > -     e = default_engines(ctx, null_sseu);
> > +     e = default_engines(ctx, pc->legacy_rcs_sseu);
> >       if (IS_ERR(e)) {
> >               err = PTR_ERR(e);
> >               goto err_free;
> > @@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
> >               mutex_unlock(&ctx->mutex);
> >       }
> >
> > +     if (pc->num_user_engines >= 0) {
> > +             struct i915_gem_engines *engines;
> > +
> > +             engines = user_engines(ctx, pc->num_user_engines,
> > +                                    pc->user_engines);
> > +             if (IS_ERR(engines)) {
> > +                     context_close(ctx);
> > +                     return ERR_CAST(engines);
> > +             }
> > +
> > +             mutex_lock(&ctx->engines_mutex);
> > +             i915_gem_context_set_user_engines(ctx);
> > +             engines = rcu_replace_pointer(ctx->engines, engines, 1);
> > +             mutex_unlock(&ctx->engines_mutex);
>
> More locking code to ditch I guess.

Sure.  Is it safe to just drop it?  I guess it is?  I'm really shaky
around all the RCU requirements and things.

> > +
> > +             free_engines(engines);
>
> Also I guess we shouldn't first create the legacy engines for this case?

That's fixed in the last patch.

> > +     }
> > +
> >       if (pc->single_timeline) {
> >               ret = drm_syncobj_create(&ctx->syncobj,
> >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> > @@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
> >  }
> >
> >  struct create_ext {
> > -     struct i915_gem_context *ctx;
> > +     struct i915_gem_proto_context *pc;
> >       struct drm_i915_file_private *fpriv;
> >  };
> >
> > @@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
> >       if (local.param.ctx_id)
> >               return -EINVAL;
> >
> > -     return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> > +     return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
> >  }
> >
> >  static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> > @@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> >  {
> >       struct drm_i915_private *i915 = to_i915(dev);
> >       struct drm_i915_gem_context_create_ext *args = data;
> > -     struct i915_gem_proto_context *pc;
> > +     struct i915_gem_context *ctx;
> >       struct create_ext ext_data;
> >       int ret;
> >       u32 id;
> > @@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> >               return -EIO;
> >       }
> >
> > -     pc = proto_context_create(i915, args->flags);
> > -     if (IS_ERR(pc))
> > -             return PTR_ERR(pc);
> > -
> > -     ext_data.ctx = i915_gem_create_context(i915, pc);
> > -     proto_context_close(pc);
> > -     if (IS_ERR(ext_data.ctx))
> > -             return PTR_ERR(ext_data.ctx);
> > +     ext_data.pc = proto_context_create(i915, args->flags);
> > +     if (IS_ERR(ext_data.pc))
> > +             return PTR_ERR(ext_data.pc);
> >
> >       if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
> >               ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
> >                                          create_extensions,
> >                                          ARRAY_SIZE(create_extensions),
> >                                          &ext_data);
> > -             if (ret)
> > -                     goto err_ctx;
> > +             if (ret) {
> > +                     proto_context_close(ext_data.pc);
> > +                     return ret;
> > +             }
> >       }
> >
> > -     ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
> > +     ctx = i915_gem_create_context(i915, ext_data.pc);
> > +     proto_context_close(ext_data.pc);
> > +     if (IS_ERR(ctx))
> > +             return PTR_ERR(ctx);
> > +
> > +     ret = gem_context_register(ctx, ext_data.fpriv, &id);
> >       if (ret < 0)
> >               goto err_ctx;
> >
> > @@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> >       return 0;
> >
> >  err_ctx:
> > -     context_close(ext_data.ctx);
> > +     context_close(ctx);
> >       return ret;
> >  }
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > index 0bf337b6d89ac..2ac341f805c8f 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > @@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
> >       const struct i915_gem_engines *engines;
> >  };
> >
> > +/**
> > + * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
> > + */
> > +enum i915_gem_engine_type {
> > +     /** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
> > +     I915_GEM_ENGINE_TYPE_INVALID = 0,
> > +
> > +     /** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
> > +     I915_GEM_ENGINE_TYPE_PHYSICAL,
> > +
> > +     /** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
> > +     I915_GEM_ENGINE_TYPE_BALANCED,
> > +};
> > +
> > +/**
> > + * struct i915_gem_proto_engine - prototype engine
> > + *
> > + * This struct describes an engine that a context may contain.  Engines
> > + * have three types:
> > + *
> > + *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
> > + *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
> > + *    use them by the user results in -EINVAL.  They are also useful during
> > + *    proto-context construction because the client may create invalid
> > + *    engines and then set them up later as bonded engines.
> > + *
> > + *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
> > + *    i915_gem_proto_engine::engine.
> > + *
> > + *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
> > + *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
> > + */
> > +struct i915_gem_proto_engine {
> > +     /** @type: Type of this engine */
> > +     enum i915_gem_engine_type type;
> > +
> > +     /** @engine: Engine, for physical */
> > +     struct intel_engine_cs *engine;
> > +
> > +     /** @num_siblings: Number of balanced siblings */
> > +     unsigned int num_siblings;
> > +
> > +     /** @siblings: Balanced siblings */
> > +     struct intel_engine_cs **siblings;
> > +
> > +     /** @sseu: Client-set SSEU parameters */
> > +     struct intel_sseu sseu;
> > +};
> > +
> >  /**
> >   * struct i915_gem_proto_context - prototype context
> >   *
> > @@ -84,6 +133,15 @@ struct i915_gem_proto_context {
> >       /** @sched: See i915_gem_context::sched */
> >       struct i915_sched_attr sched;
> >
> > +     /** @num_user_engines: Number of user-specified engines or -1 */
> > +     int num_user_engines;
> > +
> > +     /** @user_engines: User-specified engines */
> > +     struct i915_gem_proto_engine *user_engines;
> > +
> > +     /** @sseu: Client-set SSEU parameters for the legacy RCS */
> > +     struct intel_sseu legacy_rcs_sseu;
> > +
> >       /** @single_timeline: See See i915_gem_context::syncobj */
> >       bool single_timeline;
> >  };
> > --
> > 2.31.1
>
> Man is this all nasty. Since I don't want to re-review the entire pile,
> assuming we figure out solutions to all the real issues I've raised (and
> not the snarky bikesheds) this is
>
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Ok.  I'm leaving it off for now to remind myself to ensure that we
close on everything.  I'll add it once I've heard back from you on my
questions above.

--Jason

> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
  2021-05-14 19:13       ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-17 13:40         ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-17 13:40 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: Intel GFX, Maling list - DRI developers

On Fri, May 14, 2021 at 02:13:57PM -0500, Jason Ekstrand wrote:
> On Tue, May 4, 2021 at 3:33 PM Daniel Vetter <daniel@ffwll.ch> wrote:
> >
> > On Mon, May 03, 2021 at 10:57:40AM -0500, Jason Ekstrand wrote:
> > > This means that the proto-context needs to grow support for engine
> > > configuration information as well as setparam logic.  Fortunately, we'll
> > > be deleting a lot of setparam logic on the primary context shortly so it
> > > will hopefully balance out.
> > >
> > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > > ---
> > >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
> > >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
> > >  2 files changed, 587 insertions(+), 17 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > index 6dd50d669c5b9..aa4edfbf7ed48 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > @@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
> > >
> > >  static void proto_context_close(struct i915_gem_proto_context *pc)
> > >  {
> > > +     int i;
> > > +
> > >       if (pc->vm)
> > >               i915_vm_put(pc->vm);
> > > +     if (pc->user_engines) {
> > > +             for (i = 0; i < pc->num_user_engines; i++)
> > > +                     kfree(pc->user_engines[i].siblings);
> > > +             kfree(pc->user_engines);
> >
> >                 free_engines(&pc->user_engines);
> >
> > Maybe even stuff that if check into free_engines. Except I realized this
> > is proto engines here now :-(
> >
> > > +     }
> > >       kfree(pc);
> > >  }
> > >
> > > @@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > >       if (!pc)
> > >               return ERR_PTR(-ENOMEM);
> > >
> > > +     pc->num_user_engines = -1;
> > > +     pc->user_engines = NULL;
> > > +
> > >       if (HAS_FULL_PPGTT(i915)) {
> > >               struct i915_ppgtt *ppgtt;
> > >
> > > @@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > >       return err;
> > >  }
> > >
> > > +static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
> > > +                         struct i915_gem_proto_context *pc,
> > > +                         const struct drm_i915_gem_context_param *args)
> > > +{
> > > +     struct i915_address_space *vm;
> > > +
> > > +     if (args->size)
> > > +             return -EINVAL;
> > > +
> > > +     if (!pc->vm)
> > > +             return -ENODEV;
> > > +
> > > +     if (upper_32_bits(args->value))
> > > +             return -ENOENT;
> > > +
> > > +     rcu_read_lock();
> > > +     vm = xa_load(&fpriv->vm_xa, args->value);
> > > +     if (vm && !kref_get_unless_zero(&vm->ref))
> > > +             vm = NULL;
> > > +     rcu_read_unlock();
> >
> > vm lookup helpers would be nice I guess, but perhaps something that
> > vm_bind patches should do.
> 
> I can add those.  I just don't know where to put it.  We don't have an
> i915_gem_vm.h.  Suggestions?

gt/intel_gtt.h seems to be the header for i915_address_space stuff. Also
contains the i915_vma_ops but not i915_vma.

It's a pretty good mess, but probably the best place for now for these :-/

> 
> >
> > > +     if (!vm)
> > > +             return -ENOENT;
> > > +
> > > +     i915_vm_put(pc->vm);
> >
> > Ah I guess I've found why you went with "pc->vm is always set". *shrug*
> >
> > > +     pc->vm = vm;
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +struct set_proto_ctx_engines {
> > > +     struct drm_i915_private *i915;
> > > +     unsigned num_engines;
> > > +     struct i915_gem_proto_engine *engines;
> > > +};
> > > +
> > > +static int
> > > +set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
> > > +                           void *data)
> > > +{
> > > +     struct i915_context_engines_load_balance __user *ext =
> > > +             container_of_user(base, typeof(*ext), base);
> > > +     const struct set_proto_ctx_engines *set = data;
> > > +     struct drm_i915_private *i915 = set->i915;
> > > +     struct intel_engine_cs **siblings;
> > > +     u16 num_siblings, idx;
> > > +     unsigned int n;
> > > +     int err;
> > > +
> > > +     if (!HAS_EXECLISTS(i915))
> > > +             return -ENODEV;
> > > +
> > > +     if (intel_uc_uses_guc_submission(&i915->gt.uc))
> > > +             return -ENODEV; /* not implement yet */
> > > +
> > > +     if (get_user(idx, &ext->engine_index))
> > > +             return -EFAULT;
> > > +
> > > +     if (idx >= set->num_engines) {
> > > +             drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> > > +                     idx, set->num_engines);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     idx = array_index_nospec(idx, set->num_engines);
> > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
> > > +             drm_dbg(&i915->drm,
> > > +                     "Invalid placement[%d], already occupied\n", idx);
> > > +             return -EEXIST;
> > > +     }
> > > +
> > > +     if (get_user(num_siblings, &ext->num_siblings))
> > > +             return -EFAULT;
> > > +
> > > +     err = check_user_mbz(&ext->flags);
> > > +     if (err)
> > > +             return err;
> > > +
> > > +     err = check_user_mbz(&ext->mbz64);
> > > +     if (err)
> > > +             return err;
> > > +
> > > +     if (num_siblings == 0)

> >
> > You deleted the on-stack siblings micro-optimization.
> >
> > I'm shocked.
> 
> Yup.  If balanced engine create overhead when balancing across a
> single engine ever becomes a bottleneck in some UMD, I'm happy to deal
> with it then.  And I intend to deal with it by banning whatever
> developer decided balancing across single engine was a good idea.

I should have annotated this with /s

> > > +
> > > +     siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);
> >
> > If you want to pay back your micro-opt budget: GFP_TEMPORARY.
> >
> > But then I realized much wiser heads than me removed this in 2017 from the
> > kernel! That commit is a rather interesting story btw, if you're bored:
> >
> > commit 0ee931c4e31a5efb134c76440405e9219f896e33
> > Author: Michal Hocko <mhocko@suse.com>
> > Date:   Wed Sep 13 16:28:29 2017 -0700
> >
> >     mm: treewide: remove GFP_TEMPORARY allocation flag
> >
> > > +     if (!siblings)
> > > +             return -ENOMEM;
> > > +
> > > +     for (n = 0; n < num_siblings; n++) {
> > > +             struct i915_engine_class_instance ci;
> > > +
> > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> > > +                     err = -EFAULT;
> > > +                     goto err_siblings;
> > > +             }
> > > +
> > > +             siblings[n] = intel_engine_lookup_user(i915,
> > > +                                                    ci.engine_class,
> > > +                                                    ci.engine_instance);
> >
> > intel_engine_user.c
> >
> > ...
> >
> > Maybe I should just stop looking.
> 
> Don't think too hard.  It hurts.
> 
> > > +             if (!siblings[n]) {
> > > +                     drm_dbg(&i915->drm,
> > > +                             "Invalid sibling[%d]: { class:%d, inst:%d }\n",
> > > +                             n, ci.engine_class, ci.engine_instance);
> > > +                     err = -EINVAL;
> > > +                     goto err_siblings;
> > > +             }
> > > +     }
> > > +
> > > +     if (num_siblings == 1) {
> > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > +             set->engines[idx].engine = siblings[0];
> > > +             kfree(siblings);
> > > +     } else {
> > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
> > > +             set->engines[idx].num_siblings = num_siblings;
> > > +             set->engines[idx].siblings = siblings;
> > > +     }
> > > +
> > > +     return 0;
> > > +
> > > +err_siblings:
> > > +     kfree(siblings);
> > > +
> > > +     return err;
> > > +}
> > > +
> > > +static int
> > > +set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
> > > +{
> > > +     struct i915_context_engines_bond __user *ext =
> > > +             container_of_user(base, typeof(*ext), base);
> > > +     const struct set_proto_ctx_engines *set = data;
> > > +     struct drm_i915_private *i915 = set->i915;
> > > +     struct i915_engine_class_instance ci;
> > > +     struct intel_engine_cs *master;
> > > +     u16 idx, num_bonds;
> > > +     int err, n;
> > > +
> > > +     if (get_user(idx, &ext->virtual_index))
> > > +             return -EFAULT;
> > > +
> > > +     if (idx >= set->num_engines) {
> > > +             drm_dbg(&i915->drm,
> > > +                     "Invalid index for virtual engine: %d >= %d\n",
> > > +                     idx, set->num_engines);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     idx = array_index_nospec(idx, set->num_engines);
> > > +     if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
> > > +             drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
> > > +             drm_dbg(&i915->drm,
> > > +                     "Bonding with virtual engines not allowed\n");
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     err = check_user_mbz(&ext->flags);
> > > +     if (err)
> > > +             return err;
> > > +
> > > +     for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> > > +             err = check_user_mbz(&ext->mbz64[n]);
> > > +             if (err)
> > > +                     return err;
> > > +     }
> > > +
> > > +     if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> > > +             return -EFAULT;
> > > +
> > > +     master = intel_engine_lookup_user(i915,
> > > +                                       ci.engine_class,
> > > +                                       ci.engine_instance);
> > > +     if (!master) {
> >
> > It's 100% orthogonal annoyance, but maybe we can start the "what's a good
> > name here" discussion.
> >
> > I'm thinking s/master/first/ and s/slave/subsequent/ that reflect how this
> > is actually used on the execbuf side. But then this entire bonded
> > extension is so disconnected from the actual use-case, maybe we should
> > just sun-set it before we bother.
> 
> primary/secondary come to mind.  But, also, I'd rather do that as a
> separate patch since I was trying to make this mostly match.  Happy to
> up my i915 patch count with a rename follow-on, if you want.

Yeah I think we can repaint that shed as part of merging the new parallel
submit support.

> > Since we might need to keep the execlist backend implementation the
> > renaming might still be needed.
> >
> > > +             drm_dbg(&i915->drm,
> > > +                     "Unrecognised master engine: { class:%u, instance:%u }\n",
> > > +                     ci.engine_class, ci.engine_instance);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     if (get_user(num_bonds, &ext->num_bonds))
> > > +             return -EFAULT;
> > > +
> > > +     for (n = 0; n < num_bonds; n++) {
> > > +             struct intel_engine_cs *bond;
> > > +
> > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> > > +                     return -EFAULT;
> > > +
> > > +             bond = intel_engine_lookup_user(i915,
> > > +                                             ci.engine_class,
> > > +                                             ci.engine_instance);
> > > +             if (!bond) {
> > > +                     drm_dbg(&i915->drm,
> > > +                             "Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> > > +                             n, ci.engine_class, ci.engine_instance);
> > > +                     return -EINVAL;
> > > +             }
> > > +     }
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
> > > +     [I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
> > > +     [I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
> > > +};
> > > +
> > > +static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
> > > +                              struct i915_gem_proto_context *pc,
> > > +                              const struct drm_i915_gem_context_param *args)
> > > +{
> > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > +     struct set_proto_ctx_engines set = { .i915 = i915 };
> > > +     struct i915_context_param_engines __user *user =
> > > +             u64_to_user_ptr(args->value);
> > > +     unsigned int n;
> > > +     u64 extensions;
> > > +     int err;
> > > +
> > > +     if (!args->size) {
> > > +             kfree(pc->user_engines);
> > > +             pc->num_user_engines = -1;
> >
> > Is this case actually used by actual userspace, or just more stuff igt
> > loved to do?
> >
> > If so more uapi to ditch, and check in an igt that it's rejected.
> >
> > Plus standard !args->size handling here with appropriate drm_debug line
> > and all that.
> >
> > > +             pc->user_engines = NULL;
> > > +             memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
> > > +             return 0;
> > > +     }
> > > +
> > > +     BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
> >
> > I frankly don't know what this is checking, but it also looks harmless.
> 
> Yeah..... All I can see is that it lets us avoid doing a subtraction
> in the alignment check below.  Kind-of silly, IMO.

I'm not seeing even that? Care to help the blind?

> > > +     if (args->size < sizeof(*user) ||
> > > +         !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> > > +             drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> > > +                     args->size);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> > > +     /* RING_MASK has no shift so we can use it directly here */
> > > +     if (set.num_engines > I915_EXEC_RING_MASK + 1)
> > > +             return -EINVAL;
> > > +
> > > +     set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
> > > +     if (!set.engines)
> > > +             return -ENOMEM;
> > > +
> > > +     for (n = 0; n < set.num_engines; n++) {
> > > +             struct i915_engine_class_instance ci;
> > > +             struct intel_engine_cs *engine;
> > > +
> > > +             if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> > > +                     kfree(set.engines);
> > > +                     return -EFAULT;
> > > +             }
> > > +
> > > +             memset(&set.engines[n], 0, sizeof(set.engines[n]));
> > > +
> > > +             if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> > > +                 ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
> > > +                     continue;
> > > +
> > > +             engine = intel_engine_lookup_user(i915,
> > > +                                               ci.engine_class,
> > > +                                               ci.engine_instance);
> > > +             if (!engine) {
> > > +                     drm_dbg(&i915->drm,
> > > +                             "Invalid engine[%d]: { class:%d, instance:%d }\n",
> > > +                             n, ci.engine_class, ci.engine_instance);
> > > +                     kfree(set.engines);
> > > +                     return -ENOENT;
> > > +             }
> > > +
> > > +             set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > +             set.engines[n].engine = engine;
> > > +     }
> > > +
> > > +     err = -EFAULT;
> > > +     if (!get_user(extensions, &user->extensions))
> > > +             err = i915_user_extensions(u64_to_user_ptr(extensions),
> > > +                                        set_proto_ctx_engines_extensions,
> > > +                                        ARRAY_SIZE(set_proto_ctx_engines_extensions),
> > > +                                        &set);
> > > +     if (err) {
> > > +             kfree(set.engines);
> > > +             return err;
> > > +     }
> > > +
> > > +     kfree(pc->user_engines);
> >
> > Both of these kfree potentially leak engines[].siblings. I think you need
> > to extract a proto_context_free_engines helper and use that 2x here and
> > once at the very top in proto_context_close().
> 
> Good catch. Done.
> 
> > > +     pc->num_user_engines = set.num_engines;
> > > +     pc->user_engines = set.engines;
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
> > > +                           struct i915_gem_proto_context *pc,
> > > +                           struct drm_i915_gem_context_param *args)
> > > +{
> > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > +     struct drm_i915_gem_context_param_sseu user_sseu;
> > > +     struct intel_sseu *sseu;
> > > +     int ret;
> > > +
> > > +     if (args->size < sizeof(user_sseu))
> > > +             return -EINVAL;
> > > +
> > > +     if (!IS_GEN(i915, 11))
> > > +             return -ENODEV;
> > > +
> > > +     if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
> > > +                        sizeof(user_sseu)))
> > > +             return -EFAULT;
> > > +
> > > +     if (user_sseu.rsvd)
> > > +             return -EINVAL;
> > > +
> > > +     if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
> > > +             return -EINVAL;
> > > +
> > > +     if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
> > > +             return -EINVAL;
> > > +
> > > +     if (pc->num_user_engines >= 0) {
> > > +             int idx = user_sseu.engine.engine_instance;
> > > +             struct i915_gem_proto_engine *pe;
> > > +
> > > +             if (idx >= pc->num_user_engines)
> > > +                     return -EINVAL;
> > > +
> > > +             pe = &pc->user_engines[idx];
> > > +
> > > +             /* Only render engine supports RPCS configuration. */
> > > +             if (pe->engine->class != RENDER_CLASS)
> > > +                     return -EINVAL;
> > > +
> > > +             sseu = &pe->sseu;
> > > +     } else {
> > > +             /* Only render engine supports RPCS configuration. */
> > > +             if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
> > > +                     return -EINVAL;
> > > +
> > > +             /* There is only one render engine */
> > > +             if (user_sseu.engine.engine_instance != 0)
> > > +                     return -EINVAL;
> > > +
> > > +             sseu = &pc->legacy_rcs_sseu;
> > > +     }
> >
> > I think this faithfully rebuilds the convoluted and I think largely
> > accidental semantics of SSEU for all combinations of ordering against
> > set_engines.
> >
> > Maybe add a commit message note about this particular kind of fun here. I
> > don't think a code comment is warranted since I don't think I've seen a
> > userspace rely on how sseu interacts with set_engines
> 
> Done.
> 
> > > +
> > > +     ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     args->size = sizeof(user_sseu);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
> > > +                            struct i915_gem_proto_context *pc,
> > > +                            struct drm_i915_gem_context_param *args)
> > > +{
> > > +     int ret = 0;
> > > +
> > > +     switch (args->param) {
> > > +     case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
> > > +             if (args->size)
> > > +                     ret = -EINVAL;
> > > +             else if (args->value)
> > > +                     __set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > > +             else
> > > +                     __clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> >
> > Open code please and double check I caught them all ...
> 
> As I commented the first time around, __set/clear_bit are static
> inlines that unroll to "*field |= (1 << bit)" or "*field &= ~(1 <<
> bit)" as appropriate.  The non-__ versions do atomics.  I could
> hand-roll them but that seems error-prone and it gains us nothing.

They do more, they treat this as a potential array of unsigned long as a
bitfield of unlimted size. This comes from the cpuset support afaiu our
history here, and years ago (decades by now?) linux started supporting
more than 64 cpus cores. Our flags are definitely not unlimted and fit in
an unsigned, so we're dropping some compiler checking here.

Also it's not that bad really:

	if (args->value)
		pc->user_flags |= BIT(UCONTEXT_NO_ERROR_CAPTURE);
	else
		pc->user_flags &= ~BIT(UCONTEXT_NO_ERROR_CAPTURE);

Fairly idiomatic construct. Final argument here is that __func() generally
means "beware, check carefuly what's going on here", and nothing funny is
going on here at all, so it's a bit a negative trap :-)

Anyway git grep shows you're not the first (even outside of drm/i915).
Some spot checking with grep shows that bitflag use of __set_bit is about
a third of overall use:

$ git grep '__set_bit.*)' | wc -l
1761

$ git grep '__set_bit.*,\s*&.*)' | wc -l
479

So whatever you feel like.

> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_BANNABLE:
> > > +             if (args->size)
> > > +                     ret = -EINVAL;
> > > +             else if (!capable(CAP_SYS_ADMIN) && !args->value)
> > > +                     ret = -EPERM;
> > > +             else if (args->value)
> > > +                     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > +             else
> > > +                     __clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_RECOVERABLE:
> > > +             if (args->size)
> > > +                     ret = -EINVAL;
> > > +             else if (args->value)
> > > +                     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > +             else
> > > +                     __clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_PRIORITY:
> > > +             ret = validate_priority(fpriv->dev_priv, args);
> > > +             if (!ret)
> > > +                     pc->sched.priority = args->value;
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_SSEU:
> > > +             ret = set_proto_ctx_sseu(fpriv, pc, args);
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_VM:
> > > +             ret = set_proto_ctx_vm(fpriv, pc, args);
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_ENGINES:
> > > +             ret = set_proto_ctx_engines(fpriv, pc, args);
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_PERSISTENCE:
> > > +             if (args->size)
> > > +                     ret = -EINVAL;
> > > +             else if (args->value)
> > > +                     __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > > +             else
> > > +                     __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> >
> > I think we have a nice mess here. You created this
> > proto_context_set_persistence helper, but don't use it here. Oversight?
> 
> Yeah, I should use it.  Done.
> 
> > Aside from the validation fun around persistence, but that's better
> > discussed in another patch I think.
> >
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_NO_ZEROMAP:
> > > +     case I915_CONTEXT_PARAM_BAN_PERIOD:
> > > +     case I915_CONTEXT_PARAM_RINGSIZE:
> > > +     default:
> > > +             ret = -EINVAL;
> > > +             break;
> > > +     }
> > > +
> > > +     return ret;
> > > +}
> > > +
> > >  static struct i915_address_space *
> > >  context_get_vm_rcu(struct i915_gem_context *ctx)
> > >  {
> > > @@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> > >       return err;
> > >  }
> > >
> > > +static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
> > > +                                          unsigned int num_engines,
> > > +                                          struct i915_gem_proto_engine *pe)
> > > +{
> > > +     struct i915_gem_engines *e, *err;
> > > +     unsigned int n;
> > > +
> > > +     e = alloc_engines(num_engines);
> > > +     for (n = 0; n < num_engines; n++) {
> > > +             struct intel_context *ce;
> > > +             int ret;
> > > +
> > > +             switch (pe[n].type) {
> > > +             case I915_GEM_ENGINE_TYPE_PHYSICAL:
> > > +                     ce = intel_context_create(pe[n].engine);
> > > +                     break;
> > > +
> > > +             case I915_GEM_ENGINE_TYPE_BALANCED:
> > > +                     ce = intel_execlists_create_virtual(pe[n].siblings,
> > > +                                                         pe[n].num_siblings);
> > > +                     break;
> > > +
> > > +             case I915_GEM_ENGINE_TYPE_INVALID:
> > > +             default:
> > > +                     GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
> > > +                     continue;
> > > +             }
> > > +
> > > +             if (IS_ERR(ce)) {
> > > +                     err = ERR_CAST(ce);
> > > +                     goto free_engines;
> > > +             }
> > > +
> > > +             e->engines[n] = ce;
> > > +
> > > +             ret = intel_context_set_gem(ce, ctx, pe->sseu);
> > > +             if (ret) {
> > > +                     err = ERR_PTR(ret);
> > > +                     goto free_engines;
> > > +             }
> > > +     }
> > > +     e->num_engines = num_engines;
> > > +
> > > +     return e;
> > > +
> > > +free_engines:
> > > +     free_engines(e);
> > > +     return err;
> > > +}
> > > +
> > >  void i915_gem_context_release(struct kref *ref)
> > >  {
> > >       struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
> > > @@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
> > >  {
> > >       struct i915_gem_context *ctx;
> > >       struct i915_gem_engines *e;
> > > -     struct intel_sseu null_sseu = {};
> > >       int err;
> > >       int i;
> > >
> > > @@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
> > >       INIT_LIST_HEAD(&ctx->stale.engines);
> > >
> > >       mutex_init(&ctx->engines_mutex);
> > > -     e = default_engines(ctx, null_sseu);
> > > +     e = default_engines(ctx, pc->legacy_rcs_sseu);
> > >       if (IS_ERR(e)) {
> > >               err = PTR_ERR(e);
> > >               goto err_free;
> > > @@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
> > >               mutex_unlock(&ctx->mutex);
> > >       }
> > >
> > > +     if (pc->num_user_engines >= 0) {
> > > +             struct i915_gem_engines *engines;
> > > +
> > > +             engines = user_engines(ctx, pc->num_user_engines,
> > > +                                    pc->user_engines);
> > > +             if (IS_ERR(engines)) {
> > > +                     context_close(ctx);
> > > +                     return ERR_CAST(engines);
> > > +             }
> > > +
> > > +             mutex_lock(&ctx->engines_mutex);
> > > +             i915_gem_context_set_user_engines(ctx);
> > > +             engines = rcu_replace_pointer(ctx->engines, engines, 1);
> > > +             mutex_unlock(&ctx->engines_mutex);
> >
> > More locking code to ditch I guess.
> 
> Sure.  Is it safe to just drop it?  I guess it is?  I'm really shaky
> around all the RCU requirements and things.

Well the 1 in here should be replace with
lockdep_is_held(&ctx->engines_mutex), but the engines_mutex also should
go, so really can ditch the entire thing. Also no one can access our
context, so we can't fail.

Now if you do this naively without dropping the __rcu classifier for
ctx->engines then static checkers will complain. So until that's done an
rcu_assign_pointer should do.

> 
> > > +
> > > +             free_engines(engines);
> >
> > Also I guess we shouldn't first create the legacy engines for this case?
> 
> That's fixed in the last patch.

Yeah I noticed later on.

> 
> > > +     }
> > > +
> > >       if (pc->single_timeline) {
> > >               ret = drm_syncobj_create(&ctx->syncobj,
> > >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> > > @@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
> > >  }
> > >
> > >  struct create_ext {
> > > -     struct i915_gem_context *ctx;
> > > +     struct i915_gem_proto_context *pc;
> > >       struct drm_i915_file_private *fpriv;
> > >  };
> > >
> > > @@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
> > >       if (local.param.ctx_id)
> > >               return -EINVAL;
> > >
> > > -     return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> > > +     return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
> > >  }
> > >
> > >  static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> > > @@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > >  {
> > >       struct drm_i915_private *i915 = to_i915(dev);
> > >       struct drm_i915_gem_context_create_ext *args = data;
> > > -     struct i915_gem_proto_context *pc;
> > > +     struct i915_gem_context *ctx;
> > >       struct create_ext ext_data;
> > >       int ret;
> > >       u32 id;
> > > @@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > >               return -EIO;
> > >       }
> > >
> > > -     pc = proto_context_create(i915, args->flags);
> > > -     if (IS_ERR(pc))
> > > -             return PTR_ERR(pc);
> > > -
> > > -     ext_data.ctx = i915_gem_create_context(i915, pc);
> > > -     proto_context_close(pc);
> > > -     if (IS_ERR(ext_data.ctx))
> > > -             return PTR_ERR(ext_data.ctx);
> > > +     ext_data.pc = proto_context_create(i915, args->flags);
> > > +     if (IS_ERR(ext_data.pc))
> > > +             return PTR_ERR(ext_data.pc);
> > >
> > >       if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
> > >               ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
> > >                                          create_extensions,
> > >                                          ARRAY_SIZE(create_extensions),
> > >                                          &ext_data);
> > > -             if (ret)
> > > -                     goto err_ctx;
> > > +             if (ret) {
> > > +                     proto_context_close(ext_data.pc);
> > > +                     return ret;
> > > +             }
> > >       }
> > >
> > > -     ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
> > > +     ctx = i915_gem_create_context(i915, ext_data.pc);
> > > +     proto_context_close(ext_data.pc);
> > > +     if (IS_ERR(ctx))
> > > +             return PTR_ERR(ctx);
> > > +
> > > +     ret = gem_context_register(ctx, ext_data.fpriv, &id);
> > >       if (ret < 0)
> > >               goto err_ctx;
> > >
> > > @@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > >       return 0;
> > >
> > >  err_ctx:
> > > -     context_close(ext_data.ctx);
> > > +     context_close(ctx);
> > >       return ret;
> > >  }
> > >
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > index 0bf337b6d89ac..2ac341f805c8f 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > @@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
> > >       const struct i915_gem_engines *engines;
> > >  };
> > >
> > > +/**
> > > + * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
> > > + */
> > > +enum i915_gem_engine_type {
> > > +     /** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
> > > +     I915_GEM_ENGINE_TYPE_INVALID = 0,
> > > +
> > > +     /** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
> > > +     I915_GEM_ENGINE_TYPE_PHYSICAL,
> > > +
> > > +     /** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
> > > +     I915_GEM_ENGINE_TYPE_BALANCED,
> > > +};
> > > +
> > > +/**
> > > + * struct i915_gem_proto_engine - prototype engine
> > > + *
> > > + * This struct describes an engine that a context may contain.  Engines
> > > + * have three types:
> > > + *
> > > + *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
> > > + *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
> > > + *    use them by the user results in -EINVAL.  They are also useful during
> > > + *    proto-context construction because the client may create invalid
> > > + *    engines and then set them up later as bonded engines.
> > > + *
> > > + *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
> > > + *    i915_gem_proto_engine::engine.
> > > + *
> > > + *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
> > > + *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
> > > + */
> > > +struct i915_gem_proto_engine {
> > > +     /** @type: Type of this engine */
> > > +     enum i915_gem_engine_type type;
> > > +
> > > +     /** @engine: Engine, for physical */
> > > +     struct intel_engine_cs *engine;
> > > +
> > > +     /** @num_siblings: Number of balanced siblings */
> > > +     unsigned int num_siblings;
> > > +
> > > +     /** @siblings: Balanced siblings */
> > > +     struct intel_engine_cs **siblings;
> > > +
> > > +     /** @sseu: Client-set SSEU parameters */
> > > +     struct intel_sseu sseu;
> > > +};
> > > +
> > >  /**
> > >   * struct i915_gem_proto_context - prototype context
> > >   *
> > > @@ -84,6 +133,15 @@ struct i915_gem_proto_context {
> > >       /** @sched: See i915_gem_context::sched */
> > >       struct i915_sched_attr sched;
> > >
> > > +     /** @num_user_engines: Number of user-specified engines or -1 */
> > > +     int num_user_engines;
> > > +
> > > +     /** @user_engines: User-specified engines */
> > > +     struct i915_gem_proto_engine *user_engines;
> > > +
> > > +     /** @sseu: Client-set SSEU parameters for the legacy RCS */
> > > +     struct intel_sseu legacy_rcs_sseu;
> > > +
> > >       /** @single_timeline: See See i915_gem_context::syncobj */
> > >       bool single_timeline;
> > >  };
> > > --
> > > 2.31.1
> >
> > Man is this all nasty. Since I don't want to re-review the entire pile,
> > assuming we figure out solutions to all the real issues I've raised (and
> > not the snarky bikesheds) this is
> >
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Ok.  I'm leaving it off for now to remind myself to ensure that we
> close on everything.  I'll add it once I've heard back from you on my
> questions above.

I think we're all good. Mostly :-/
-Daniel

> 
> --Jason
> 
> > >
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
@ 2021-05-17 13:40         ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-17 13:40 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: Intel GFX, Maling list - DRI developers

On Fri, May 14, 2021 at 02:13:57PM -0500, Jason Ekstrand wrote:
> On Tue, May 4, 2021 at 3:33 PM Daniel Vetter <daniel@ffwll.ch> wrote:
> >
> > On Mon, May 03, 2021 at 10:57:40AM -0500, Jason Ekstrand wrote:
> > > This means that the proto-context needs to grow support for engine
> > > configuration information as well as setparam logic.  Fortunately, we'll
> > > be deleting a lot of setparam logic on the primary context shortly so it
> > > will hopefully balance out.
> > >
> > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > > ---
> > >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
> > >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
> > >  2 files changed, 587 insertions(+), 17 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > index 6dd50d669c5b9..aa4edfbf7ed48 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > @@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
> > >
> > >  static void proto_context_close(struct i915_gem_proto_context *pc)
> > >  {
> > > +     int i;
> > > +
> > >       if (pc->vm)
> > >               i915_vm_put(pc->vm);
> > > +     if (pc->user_engines) {
> > > +             for (i = 0; i < pc->num_user_engines; i++)
> > > +                     kfree(pc->user_engines[i].siblings);
> > > +             kfree(pc->user_engines);
> >
> >                 free_engines(&pc->user_engines);
> >
> > Maybe even stuff that if check into free_engines. Except I realized this
> > is proto engines here now :-(
> >
> > > +     }
> > >       kfree(pc);
> > >  }
> > >
> > > @@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > >       if (!pc)
> > >               return ERR_PTR(-ENOMEM);
> > >
> > > +     pc->num_user_engines = -1;
> > > +     pc->user_engines = NULL;
> > > +
> > >       if (HAS_FULL_PPGTT(i915)) {
> > >               struct i915_ppgtt *ppgtt;
> > >
> > > @@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > >       return err;
> > >  }
> > >
> > > +static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
> > > +                         struct i915_gem_proto_context *pc,
> > > +                         const struct drm_i915_gem_context_param *args)
> > > +{
> > > +     struct i915_address_space *vm;
> > > +
> > > +     if (args->size)
> > > +             return -EINVAL;
> > > +
> > > +     if (!pc->vm)
> > > +             return -ENODEV;
> > > +
> > > +     if (upper_32_bits(args->value))
> > > +             return -ENOENT;
> > > +
> > > +     rcu_read_lock();
> > > +     vm = xa_load(&fpriv->vm_xa, args->value);
> > > +     if (vm && !kref_get_unless_zero(&vm->ref))
> > > +             vm = NULL;
> > > +     rcu_read_unlock();
> >
> > vm lookup helpers would be nice I guess, but perhaps something that
> > vm_bind patches should do.
> 
> I can add those.  I just don't know where to put it.  We don't have an
> i915_gem_vm.h.  Suggestions?

gt/intel_gtt.h seems to be the header for i915_address_space stuff. Also
contains the i915_vma_ops but not i915_vma.

It's a pretty good mess, but probably the best place for now for these :-/

> 
> >
> > > +     if (!vm)
> > > +             return -ENOENT;
> > > +
> > > +     i915_vm_put(pc->vm);
> >
> > Ah I guess I've found why you went with "pc->vm is always set". *shrug*
> >
> > > +     pc->vm = vm;
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +struct set_proto_ctx_engines {
> > > +     struct drm_i915_private *i915;
> > > +     unsigned num_engines;
> > > +     struct i915_gem_proto_engine *engines;
> > > +};
> > > +
> > > +static int
> > > +set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
> > > +                           void *data)
> > > +{
> > > +     struct i915_context_engines_load_balance __user *ext =
> > > +             container_of_user(base, typeof(*ext), base);
> > > +     const struct set_proto_ctx_engines *set = data;
> > > +     struct drm_i915_private *i915 = set->i915;
> > > +     struct intel_engine_cs **siblings;
> > > +     u16 num_siblings, idx;
> > > +     unsigned int n;
> > > +     int err;
> > > +
> > > +     if (!HAS_EXECLISTS(i915))
> > > +             return -ENODEV;
> > > +
> > > +     if (intel_uc_uses_guc_submission(&i915->gt.uc))
> > > +             return -ENODEV; /* not implement yet */
> > > +
> > > +     if (get_user(idx, &ext->engine_index))
> > > +             return -EFAULT;
> > > +
> > > +     if (idx >= set->num_engines) {
> > > +             drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> > > +                     idx, set->num_engines);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     idx = array_index_nospec(idx, set->num_engines);
> > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
> > > +             drm_dbg(&i915->drm,
> > > +                     "Invalid placement[%d], already occupied\n", idx);
> > > +             return -EEXIST;
> > > +     }
> > > +
> > > +     if (get_user(num_siblings, &ext->num_siblings))
> > > +             return -EFAULT;
> > > +
> > > +     err = check_user_mbz(&ext->flags);
> > > +     if (err)
> > > +             return err;
> > > +
> > > +     err = check_user_mbz(&ext->mbz64);
> > > +     if (err)
> > > +             return err;
> > > +
> > > +     if (num_siblings == 0)

> >
> > You deleted the on-stack siblings micro-optimization.
> >
> > I'm shocked.
> 
> Yup.  If balanced engine create overhead when balancing across a
> single engine ever becomes a bottleneck in some UMD, I'm happy to deal
> with it then.  And I intend to deal with it by banning whatever
> developer decided balancing across single engine was a good idea.

I should have annotated this with /s

> > > +
> > > +     siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);
> >
> > If you want to pay back your micro-opt budget: GFP_TEMPORARY.
> >
> > But then I realized much wiser heads than me removed this in 2017 from the
> > kernel! That commit is a rather interesting story btw, if you're bored:
> >
> > commit 0ee931c4e31a5efb134c76440405e9219f896e33
> > Author: Michal Hocko <mhocko@suse.com>
> > Date:   Wed Sep 13 16:28:29 2017 -0700
> >
> >     mm: treewide: remove GFP_TEMPORARY allocation flag
> >
> > > +     if (!siblings)
> > > +             return -ENOMEM;
> > > +
> > > +     for (n = 0; n < num_siblings; n++) {
> > > +             struct i915_engine_class_instance ci;
> > > +
> > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> > > +                     err = -EFAULT;
> > > +                     goto err_siblings;
> > > +             }
> > > +
> > > +             siblings[n] = intel_engine_lookup_user(i915,
> > > +                                                    ci.engine_class,
> > > +                                                    ci.engine_instance);
> >
> > intel_engine_user.c
> >
> > ...
> >
> > Maybe I should just stop looking.
> 
> Don't think too hard.  It hurts.
> 
> > > +             if (!siblings[n]) {
> > > +                     drm_dbg(&i915->drm,
> > > +                             "Invalid sibling[%d]: { class:%d, inst:%d }\n",
> > > +                             n, ci.engine_class, ci.engine_instance);
> > > +                     err = -EINVAL;
> > > +                     goto err_siblings;
> > > +             }
> > > +     }
> > > +
> > > +     if (num_siblings == 1) {
> > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > +             set->engines[idx].engine = siblings[0];
> > > +             kfree(siblings);
> > > +     } else {
> > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
> > > +             set->engines[idx].num_siblings = num_siblings;
> > > +             set->engines[idx].siblings = siblings;
> > > +     }
> > > +
> > > +     return 0;
> > > +
> > > +err_siblings:
> > > +     kfree(siblings);
> > > +
> > > +     return err;
> > > +}
> > > +
> > > +static int
> > > +set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
> > > +{
> > > +     struct i915_context_engines_bond __user *ext =
> > > +             container_of_user(base, typeof(*ext), base);
> > > +     const struct set_proto_ctx_engines *set = data;
> > > +     struct drm_i915_private *i915 = set->i915;
> > > +     struct i915_engine_class_instance ci;
> > > +     struct intel_engine_cs *master;
> > > +     u16 idx, num_bonds;
> > > +     int err, n;
> > > +
> > > +     if (get_user(idx, &ext->virtual_index))
> > > +             return -EFAULT;
> > > +
> > > +     if (idx >= set->num_engines) {
> > > +             drm_dbg(&i915->drm,
> > > +                     "Invalid index for virtual engine: %d >= %d\n",
> > > +                     idx, set->num_engines);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     idx = array_index_nospec(idx, set->num_engines);
> > > +     if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
> > > +             drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
> > > +             drm_dbg(&i915->drm,
> > > +                     "Bonding with virtual engines not allowed\n");
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     err = check_user_mbz(&ext->flags);
> > > +     if (err)
> > > +             return err;
> > > +
> > > +     for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> > > +             err = check_user_mbz(&ext->mbz64[n]);
> > > +             if (err)
> > > +                     return err;
> > > +     }
> > > +
> > > +     if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> > > +             return -EFAULT;
> > > +
> > > +     master = intel_engine_lookup_user(i915,
> > > +                                       ci.engine_class,
> > > +                                       ci.engine_instance);
> > > +     if (!master) {
> >
> > It's 100% orthogonal annoyance, but maybe we can start the "what's a good
> > name here" discussion.
> >
> > I'm thinking s/master/first/ and s/slave/subsequent/ that reflect how this
> > is actually used on the execbuf side. But then this entire bonded
> > extension is so disconnected from the actual use-case, maybe we should
> > just sun-set it before we bother.
> 
> primary/secondary come to mind.  But, also, I'd rather do that as a
> separate patch since I was trying to make this mostly match.  Happy to
> up my i915 patch count with a rename follow-on, if you want.

Yeah I think we can repaint that shed as part of merging the new parallel
submit support.

> > Since we might need to keep the execlist backend implementation the
> > renaming might still be needed.
> >
> > > +             drm_dbg(&i915->drm,
> > > +                     "Unrecognised master engine: { class:%u, instance:%u }\n",
> > > +                     ci.engine_class, ci.engine_instance);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     if (get_user(num_bonds, &ext->num_bonds))
> > > +             return -EFAULT;
> > > +
> > > +     for (n = 0; n < num_bonds; n++) {
> > > +             struct intel_engine_cs *bond;
> > > +
> > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> > > +                     return -EFAULT;
> > > +
> > > +             bond = intel_engine_lookup_user(i915,
> > > +                                             ci.engine_class,
> > > +                                             ci.engine_instance);
> > > +             if (!bond) {
> > > +                     drm_dbg(&i915->drm,
> > > +                             "Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> > > +                             n, ci.engine_class, ci.engine_instance);
> > > +                     return -EINVAL;
> > > +             }
> > > +     }
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
> > > +     [I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
> > > +     [I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
> > > +};
> > > +
> > > +static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
> > > +                              struct i915_gem_proto_context *pc,
> > > +                              const struct drm_i915_gem_context_param *args)
> > > +{
> > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > +     struct set_proto_ctx_engines set = { .i915 = i915 };
> > > +     struct i915_context_param_engines __user *user =
> > > +             u64_to_user_ptr(args->value);
> > > +     unsigned int n;
> > > +     u64 extensions;
> > > +     int err;
> > > +
> > > +     if (!args->size) {
> > > +             kfree(pc->user_engines);
> > > +             pc->num_user_engines = -1;
> >
> > Is this case actually used by actual userspace, or just more stuff igt
> > loved to do?
> >
> > If so more uapi to ditch, and check in an igt that it's rejected.
> >
> > Plus standard !args->size handling here with appropriate drm_debug line
> > and all that.
> >
> > > +             pc->user_engines = NULL;
> > > +             memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
> > > +             return 0;
> > > +     }
> > > +
> > > +     BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
> >
> > I frankly don't know what this is checking, but it also looks harmless.
> 
> Yeah..... All I can see is that it lets us avoid doing a subtraction
> in the alignment check below.  Kind-of silly, IMO.

I'm not seeing even that? Care to help the blind?

> > > +     if (args->size < sizeof(*user) ||
> > > +         !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> > > +             drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> > > +                     args->size);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> > > +     /* RING_MASK has no shift so we can use it directly here */
> > > +     if (set.num_engines > I915_EXEC_RING_MASK + 1)
> > > +             return -EINVAL;
> > > +
> > > +     set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
> > > +     if (!set.engines)
> > > +             return -ENOMEM;
> > > +
> > > +     for (n = 0; n < set.num_engines; n++) {
> > > +             struct i915_engine_class_instance ci;
> > > +             struct intel_engine_cs *engine;
> > > +
> > > +             if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> > > +                     kfree(set.engines);
> > > +                     return -EFAULT;
> > > +             }
> > > +
> > > +             memset(&set.engines[n], 0, sizeof(set.engines[n]));
> > > +
> > > +             if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> > > +                 ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
> > > +                     continue;
> > > +
> > > +             engine = intel_engine_lookup_user(i915,
> > > +                                               ci.engine_class,
> > > +                                               ci.engine_instance);
> > > +             if (!engine) {
> > > +                     drm_dbg(&i915->drm,
> > > +                             "Invalid engine[%d]: { class:%d, instance:%d }\n",
> > > +                             n, ci.engine_class, ci.engine_instance);
> > > +                     kfree(set.engines);
> > > +                     return -ENOENT;
> > > +             }
> > > +
> > > +             set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > +             set.engines[n].engine = engine;
> > > +     }
> > > +
> > > +     err = -EFAULT;
> > > +     if (!get_user(extensions, &user->extensions))
> > > +             err = i915_user_extensions(u64_to_user_ptr(extensions),
> > > +                                        set_proto_ctx_engines_extensions,
> > > +                                        ARRAY_SIZE(set_proto_ctx_engines_extensions),
> > > +                                        &set);
> > > +     if (err) {
> > > +             kfree(set.engines);
> > > +             return err;
> > > +     }
> > > +
> > > +     kfree(pc->user_engines);
> >
> > Both of these kfree potentially leak engines[].siblings. I think you need
> > to extract a proto_context_free_engines helper and use that 2x here and
> > once at the very top in proto_context_close().
> 
> Good catch. Done.
> 
> > > +     pc->num_user_engines = set.num_engines;
> > > +     pc->user_engines = set.engines;
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
> > > +                           struct i915_gem_proto_context *pc,
> > > +                           struct drm_i915_gem_context_param *args)
> > > +{
> > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > +     struct drm_i915_gem_context_param_sseu user_sseu;
> > > +     struct intel_sseu *sseu;
> > > +     int ret;
> > > +
> > > +     if (args->size < sizeof(user_sseu))
> > > +             return -EINVAL;
> > > +
> > > +     if (!IS_GEN(i915, 11))
> > > +             return -ENODEV;
> > > +
> > > +     if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
> > > +                        sizeof(user_sseu)))
> > > +             return -EFAULT;
> > > +
> > > +     if (user_sseu.rsvd)
> > > +             return -EINVAL;
> > > +
> > > +     if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
> > > +             return -EINVAL;
> > > +
> > > +     if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
> > > +             return -EINVAL;
> > > +
> > > +     if (pc->num_user_engines >= 0) {
> > > +             int idx = user_sseu.engine.engine_instance;
> > > +             struct i915_gem_proto_engine *pe;
> > > +
> > > +             if (idx >= pc->num_user_engines)
> > > +                     return -EINVAL;
> > > +
> > > +             pe = &pc->user_engines[idx];
> > > +
> > > +             /* Only render engine supports RPCS configuration. */
> > > +             if (pe->engine->class != RENDER_CLASS)
> > > +                     return -EINVAL;
> > > +
> > > +             sseu = &pe->sseu;
> > > +     } else {
> > > +             /* Only render engine supports RPCS configuration. */
> > > +             if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
> > > +                     return -EINVAL;
> > > +
> > > +             /* There is only one render engine */
> > > +             if (user_sseu.engine.engine_instance != 0)
> > > +                     return -EINVAL;
> > > +
> > > +             sseu = &pc->legacy_rcs_sseu;
> > > +     }
> >
> > I think this faithfully rebuilds the convoluted and I think largely
> > accidental semantics of SSEU for all combinations of ordering against
> > set_engines.
> >
> > Maybe add a commit message note about this particular kind of fun here. I
> > don't think a code comment is warranted since I don't think I've seen a
> > userspace rely on how sseu interacts with set_engines
> 
> Done.
> 
> > > +
> > > +     ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
> > > +     if (ret)
> > > +             return ret;
> > > +
> > > +     args->size = sizeof(user_sseu);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
> > > +                            struct i915_gem_proto_context *pc,
> > > +                            struct drm_i915_gem_context_param *args)
> > > +{
> > > +     int ret = 0;
> > > +
> > > +     switch (args->param) {
> > > +     case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
> > > +             if (args->size)
> > > +                     ret = -EINVAL;
> > > +             else if (args->value)
> > > +                     __set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > > +             else
> > > +                     __clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> >
> > Open code please and double check I caught them all ...
> 
> As I commented the first time around, __set/clear_bit are static
> inlines that unroll to "*field |= (1 << bit)" or "*field &= ~(1 <<
> bit)" as appropriate.  The non-__ versions do atomics.  I could
> hand-roll them but that seems error-prone and it gains us nothing.

They do more, they treat this as a potential array of unsigned long as a
bitfield of unlimted size. This comes from the cpuset support afaiu our
history here, and years ago (decades by now?) linux started supporting
more than 64 cpus cores. Our flags are definitely not unlimted and fit in
an unsigned, so we're dropping some compiler checking here.

Also it's not that bad really:

	if (args->value)
		pc->user_flags |= BIT(UCONTEXT_NO_ERROR_CAPTURE);
	else
		pc->user_flags &= ~BIT(UCONTEXT_NO_ERROR_CAPTURE);

Fairly idiomatic construct. Final argument here is that __func() generally
means "beware, check carefuly what's going on here", and nothing funny is
going on here at all, so it's a bit a negative trap :-)

Anyway git grep shows you're not the first (even outside of drm/i915).
Some spot checking with grep shows that bitflag use of __set_bit is about
a third of overall use:

$ git grep '__set_bit.*)' | wc -l
1761

$ git grep '__set_bit.*,\s*&.*)' | wc -l
479

So whatever you feel like.

> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_BANNABLE:
> > > +             if (args->size)
> > > +                     ret = -EINVAL;
> > > +             else if (!capable(CAP_SYS_ADMIN) && !args->value)
> > > +                     ret = -EPERM;
> > > +             else if (args->value)
> > > +                     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > +             else
> > > +                     __clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_RECOVERABLE:
> > > +             if (args->size)
> > > +                     ret = -EINVAL;
> > > +             else if (args->value)
> > > +                     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > +             else
> > > +                     __clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_PRIORITY:
> > > +             ret = validate_priority(fpriv->dev_priv, args);
> > > +             if (!ret)
> > > +                     pc->sched.priority = args->value;
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_SSEU:
> > > +             ret = set_proto_ctx_sseu(fpriv, pc, args);
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_VM:
> > > +             ret = set_proto_ctx_vm(fpriv, pc, args);
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_ENGINES:
> > > +             ret = set_proto_ctx_engines(fpriv, pc, args);
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_PERSISTENCE:
> > > +             if (args->size)
> > > +                     ret = -EINVAL;
> > > +             else if (args->value)
> > > +                     __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > > +             else
> > > +                     __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> >
> > I think we have a nice mess here. You created this
> > proto_context_set_persistence helper, but don't use it here. Oversight?
> 
> Yeah, I should use it.  Done.
> 
> > Aside from the validation fun around persistence, but that's better
> > discussed in another patch I think.
> >
> > > +             break;
> > > +
> > > +     case I915_CONTEXT_PARAM_NO_ZEROMAP:
> > > +     case I915_CONTEXT_PARAM_BAN_PERIOD:
> > > +     case I915_CONTEXT_PARAM_RINGSIZE:
> > > +     default:
> > > +             ret = -EINVAL;
> > > +             break;
> > > +     }
> > > +
> > > +     return ret;
> > > +}
> > > +
> > >  static struct i915_address_space *
> > >  context_get_vm_rcu(struct i915_gem_context *ctx)
> > >  {
> > > @@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> > >       return err;
> > >  }
> > >
> > > +static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
> > > +                                          unsigned int num_engines,
> > > +                                          struct i915_gem_proto_engine *pe)
> > > +{
> > > +     struct i915_gem_engines *e, *err;
> > > +     unsigned int n;
> > > +
> > > +     e = alloc_engines(num_engines);
> > > +     for (n = 0; n < num_engines; n++) {
> > > +             struct intel_context *ce;
> > > +             int ret;
> > > +
> > > +             switch (pe[n].type) {
> > > +             case I915_GEM_ENGINE_TYPE_PHYSICAL:
> > > +                     ce = intel_context_create(pe[n].engine);
> > > +                     break;
> > > +
> > > +             case I915_GEM_ENGINE_TYPE_BALANCED:
> > > +                     ce = intel_execlists_create_virtual(pe[n].siblings,
> > > +                                                         pe[n].num_siblings);
> > > +                     break;
> > > +
> > > +             case I915_GEM_ENGINE_TYPE_INVALID:
> > > +             default:
> > > +                     GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
> > > +                     continue;
> > > +             }
> > > +
> > > +             if (IS_ERR(ce)) {
> > > +                     err = ERR_CAST(ce);
> > > +                     goto free_engines;
> > > +             }
> > > +
> > > +             e->engines[n] = ce;
> > > +
> > > +             ret = intel_context_set_gem(ce, ctx, pe->sseu);
> > > +             if (ret) {
> > > +                     err = ERR_PTR(ret);
> > > +                     goto free_engines;
> > > +             }
> > > +     }
> > > +     e->num_engines = num_engines;
> > > +
> > > +     return e;
> > > +
> > > +free_engines:
> > > +     free_engines(e);
> > > +     return err;
> > > +}
> > > +
> > >  void i915_gem_context_release(struct kref *ref)
> > >  {
> > >       struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
> > > @@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
> > >  {
> > >       struct i915_gem_context *ctx;
> > >       struct i915_gem_engines *e;
> > > -     struct intel_sseu null_sseu = {};
> > >       int err;
> > >       int i;
> > >
> > > @@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
> > >       INIT_LIST_HEAD(&ctx->stale.engines);
> > >
> > >       mutex_init(&ctx->engines_mutex);
> > > -     e = default_engines(ctx, null_sseu);
> > > +     e = default_engines(ctx, pc->legacy_rcs_sseu);
> > >       if (IS_ERR(e)) {
> > >               err = PTR_ERR(e);
> > >               goto err_free;
> > > @@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
> > >               mutex_unlock(&ctx->mutex);
> > >       }
> > >
> > > +     if (pc->num_user_engines >= 0) {
> > > +             struct i915_gem_engines *engines;
> > > +
> > > +             engines = user_engines(ctx, pc->num_user_engines,
> > > +                                    pc->user_engines);
> > > +             if (IS_ERR(engines)) {
> > > +                     context_close(ctx);
> > > +                     return ERR_CAST(engines);
> > > +             }
> > > +
> > > +             mutex_lock(&ctx->engines_mutex);
> > > +             i915_gem_context_set_user_engines(ctx);
> > > +             engines = rcu_replace_pointer(ctx->engines, engines, 1);
> > > +             mutex_unlock(&ctx->engines_mutex);
> >
> > More locking code to ditch I guess.
> 
> Sure.  Is it safe to just drop it?  I guess it is?  I'm really shaky
> around all the RCU requirements and things.

Well the 1 in here should be replace with
lockdep_is_held(&ctx->engines_mutex), but the engines_mutex also should
go, so really can ditch the entire thing. Also no one can access our
context, so we can't fail.

Now if you do this naively without dropping the __rcu classifier for
ctx->engines then static checkers will complain. So until that's done an
rcu_assign_pointer should do.

> 
> > > +
> > > +             free_engines(engines);
> >
> > Also I guess we shouldn't first create the legacy engines for this case?
> 
> That's fixed in the last patch.

Yeah I noticed later on.

> 
> > > +     }
> > > +
> > >       if (pc->single_timeline) {
> > >               ret = drm_syncobj_create(&ctx->syncobj,
> > >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> > > @@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
> > >  }
> > >
> > >  struct create_ext {
> > > -     struct i915_gem_context *ctx;
> > > +     struct i915_gem_proto_context *pc;
> > >       struct drm_i915_file_private *fpriv;
> > >  };
> > >
> > > @@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
> > >       if (local.param.ctx_id)
> > >               return -EINVAL;
> > >
> > > -     return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> > > +     return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
> > >  }
> > >
> > >  static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> > > @@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > >  {
> > >       struct drm_i915_private *i915 = to_i915(dev);
> > >       struct drm_i915_gem_context_create_ext *args = data;
> > > -     struct i915_gem_proto_context *pc;
> > > +     struct i915_gem_context *ctx;
> > >       struct create_ext ext_data;
> > >       int ret;
> > >       u32 id;
> > > @@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > >               return -EIO;
> > >       }
> > >
> > > -     pc = proto_context_create(i915, args->flags);
> > > -     if (IS_ERR(pc))
> > > -             return PTR_ERR(pc);
> > > -
> > > -     ext_data.ctx = i915_gem_create_context(i915, pc);
> > > -     proto_context_close(pc);
> > > -     if (IS_ERR(ext_data.ctx))
> > > -             return PTR_ERR(ext_data.ctx);
> > > +     ext_data.pc = proto_context_create(i915, args->flags);
> > > +     if (IS_ERR(ext_data.pc))
> > > +             return PTR_ERR(ext_data.pc);
> > >
> > >       if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
> > >               ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
> > >                                          create_extensions,
> > >                                          ARRAY_SIZE(create_extensions),
> > >                                          &ext_data);
> > > -             if (ret)
> > > -                     goto err_ctx;
> > > +             if (ret) {
> > > +                     proto_context_close(ext_data.pc);
> > > +                     return ret;
> > > +             }
> > >       }
> > >
> > > -     ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
> > > +     ctx = i915_gem_create_context(i915, ext_data.pc);
> > > +     proto_context_close(ext_data.pc);
> > > +     if (IS_ERR(ctx))
> > > +             return PTR_ERR(ctx);
> > > +
> > > +     ret = gem_context_register(ctx, ext_data.fpriv, &id);
> > >       if (ret < 0)
> > >               goto err_ctx;
> > >
> > > @@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > >       return 0;
> > >
> > >  err_ctx:
> > > -     context_close(ext_data.ctx);
> > > +     context_close(ctx);
> > >       return ret;
> > >  }
> > >
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > index 0bf337b6d89ac..2ac341f805c8f 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > @@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
> > >       const struct i915_gem_engines *engines;
> > >  };
> > >
> > > +/**
> > > + * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
> > > + */
> > > +enum i915_gem_engine_type {
> > > +     /** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
> > > +     I915_GEM_ENGINE_TYPE_INVALID = 0,
> > > +
> > > +     /** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
> > > +     I915_GEM_ENGINE_TYPE_PHYSICAL,
> > > +
> > > +     /** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
> > > +     I915_GEM_ENGINE_TYPE_BALANCED,
> > > +};
> > > +
> > > +/**
> > > + * struct i915_gem_proto_engine - prototype engine
> > > + *
> > > + * This struct describes an engine that a context may contain.  Engines
> > > + * have three types:
> > > + *
> > > + *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
> > > + *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
> > > + *    use them by the user results in -EINVAL.  They are also useful during
> > > + *    proto-context construction because the client may create invalid
> > > + *    engines and then set them up later as bonded engines.
> > > + *
> > > + *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
> > > + *    i915_gem_proto_engine::engine.
> > > + *
> > > + *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
> > > + *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
> > > + */
> > > +struct i915_gem_proto_engine {
> > > +     /** @type: Type of this engine */
> > > +     enum i915_gem_engine_type type;
> > > +
> > > +     /** @engine: Engine, for physical */
> > > +     struct intel_engine_cs *engine;
> > > +
> > > +     /** @num_siblings: Number of balanced siblings */
> > > +     unsigned int num_siblings;
> > > +
> > > +     /** @siblings: Balanced siblings */
> > > +     struct intel_engine_cs **siblings;
> > > +
> > > +     /** @sseu: Client-set SSEU parameters */
> > > +     struct intel_sseu sseu;
> > > +};
> > > +
> > >  /**
> > >   * struct i915_gem_proto_context - prototype context
> > >   *
> > > @@ -84,6 +133,15 @@ struct i915_gem_proto_context {
> > >       /** @sched: See i915_gem_context::sched */
> > >       struct i915_sched_attr sched;
> > >
> > > +     /** @num_user_engines: Number of user-specified engines or -1 */
> > > +     int num_user_engines;
> > > +
> > > +     /** @user_engines: User-specified engines */
> > > +     struct i915_gem_proto_engine *user_engines;
> > > +
> > > +     /** @sseu: Client-set SSEU parameters for the legacy RCS */
> > > +     struct intel_sseu legacy_rcs_sseu;
> > > +
> > >       /** @single_timeline: See See i915_gem_context::syncobj */
> > >       bool single_timeline;
> > >  };
> > > --
> > > 2.31.1
> >
> > Man is this all nasty. Since I don't want to re-review the entire pile,
> > assuming we figure out solutions to all the real issues I've raised (and
> > not the snarky bikesheds) this is
> >
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Ok.  I'm leaving it off for now to remind myself to ensure that we
> close on everything.  I'll add it once I've heard back from you on my
> questions above.

I think we're all good. Mostly :-/
-Daniel

> 
> --Jason
> 
> > >
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
  2021-05-17 13:40         ` [Intel-gfx] " Daniel Vetter
@ 2021-05-17 17:04           ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-17 17:04 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Mon, May 17, 2021 at 8:40 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Fri, May 14, 2021 at 02:13:57PM -0500, Jason Ekstrand wrote:
> > On Tue, May 4, 2021 at 3:33 PM Daniel Vetter <daniel@ffwll.ch> wrote:
> > >
> > > On Mon, May 03, 2021 at 10:57:40AM -0500, Jason Ekstrand wrote:
> > > > This means that the proto-context needs to grow support for engine
> > > > configuration information as well as setparam logic.  Fortunately, we'll
> > > > be deleting a lot of setparam logic on the primary context shortly so it
> > > > will hopefully balance out.
> > > >
> > > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > > > ---
> > > >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
> > > >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
> > > >  2 files changed, 587 insertions(+), 17 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > index 6dd50d669c5b9..aa4edfbf7ed48 100644
> > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > @@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
> > > >
> > > >  static void proto_context_close(struct i915_gem_proto_context *pc)
> > > >  {
> > > > +     int i;
> > > > +
> > > >       if (pc->vm)
> > > >               i915_vm_put(pc->vm);
> > > > +     if (pc->user_engines) {
> > > > +             for (i = 0; i < pc->num_user_engines; i++)
> > > > +                     kfree(pc->user_engines[i].siblings);
> > > > +             kfree(pc->user_engines);
> > >
> > >                 free_engines(&pc->user_engines);
> > >
> > > Maybe even stuff that if check into free_engines. Except I realized this
> > > is proto engines here now :-(
> > >
> > > > +     }
> > > >       kfree(pc);
> > > >  }
> > > >
> > > > @@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > > >       if (!pc)
> > > >               return ERR_PTR(-ENOMEM);
> > > >
> > > > +     pc->num_user_engines = -1;
> > > > +     pc->user_engines = NULL;
> > > > +
> > > >       if (HAS_FULL_PPGTT(i915)) {
> > > >               struct i915_ppgtt *ppgtt;
> > > >
> > > > @@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > > >       return err;
> > > >  }
> > > >
> > > > +static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
> > > > +                         struct i915_gem_proto_context *pc,
> > > > +                         const struct drm_i915_gem_context_param *args)
> > > > +{
> > > > +     struct i915_address_space *vm;
> > > > +
> > > > +     if (args->size)
> > > > +             return -EINVAL;
> > > > +
> > > > +     if (!pc->vm)
> > > > +             return -ENODEV;
> > > > +
> > > > +     if (upper_32_bits(args->value))
> > > > +             return -ENOENT;
> > > > +
> > > > +     rcu_read_lock();
> > > > +     vm = xa_load(&fpriv->vm_xa, args->value);
> > > > +     if (vm && !kref_get_unless_zero(&vm->ref))
> > > > +             vm = NULL;
> > > > +     rcu_read_unlock();
> > >
> > > vm lookup helpers would be nice I guess, but perhaps something that
> > > vm_bind patches should do.
> >
> > I can add those.  I just don't know where to put it.  We don't have an
> > i915_gem_vm.h.  Suggestions?
>
> gt/intel_gtt.h seems to be the header for i915_address_space stuff. Also
> contains the i915_vma_ops but not i915_vma.
>
> It's a pretty good mess, but probably the best place for now for these :-/

The one for contexts is in i915_drv.h so I put the VM one there too.
Feel free to tell me to move it.  I don't care where it goes.

> >
> > >
> > > > +     if (!vm)
> > > > +             return -ENOENT;
> > > > +
> > > > +     i915_vm_put(pc->vm);
> > >
> > > Ah I guess I've found why you went with "pc->vm is always set". *shrug*
> > >
> > > > +     pc->vm = vm;
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +struct set_proto_ctx_engines {
> > > > +     struct drm_i915_private *i915;
> > > > +     unsigned num_engines;
> > > > +     struct i915_gem_proto_engine *engines;
> > > > +};
> > > > +
> > > > +static int
> > > > +set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
> > > > +                           void *data)
> > > > +{
> > > > +     struct i915_context_engines_load_balance __user *ext =
> > > > +             container_of_user(base, typeof(*ext), base);
> > > > +     const struct set_proto_ctx_engines *set = data;
> > > > +     struct drm_i915_private *i915 = set->i915;
> > > > +     struct intel_engine_cs **siblings;
> > > > +     u16 num_siblings, idx;
> > > > +     unsigned int n;
> > > > +     int err;
> > > > +
> > > > +     if (!HAS_EXECLISTS(i915))
> > > > +             return -ENODEV;
> > > > +
> > > > +     if (intel_uc_uses_guc_submission(&i915->gt.uc))
> > > > +             return -ENODEV; /* not implement yet */
> > > > +
> > > > +     if (get_user(idx, &ext->engine_index))
> > > > +             return -EFAULT;
> > > > +
> > > > +     if (idx >= set->num_engines) {
> > > > +             drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> > > > +                     idx, set->num_engines);
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     idx = array_index_nospec(idx, set->num_engines);
> > > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
> > > > +             drm_dbg(&i915->drm,
> > > > +                     "Invalid placement[%d], already occupied\n", idx);
> > > > +             return -EEXIST;
> > > > +     }
> > > > +
> > > > +     if (get_user(num_siblings, &ext->num_siblings))
> > > > +             return -EFAULT;
> > > > +
> > > > +     err = check_user_mbz(&ext->flags);
> > > > +     if (err)
> > > > +             return err;
> > > > +
> > > > +     err = check_user_mbz(&ext->mbz64);
> > > > +     if (err)
> > > > +             return err;
> > > > +
> > > > +     if (num_siblings == 0)
>
> > >
> > > You deleted the on-stack siblings micro-optimization.
> > >
> > > I'm shocked.
> >
> > Yup.  If balanced engine create overhead when balancing across a
> > single engine ever becomes a bottleneck in some UMD, I'm happy to deal
> > with it then.  And I intend to deal with it by banning whatever
> > developer decided balancing across single engine was a good idea.
>
> I should have annotated this with /s

I detected your sarcasm and returned it. :-P

> > > > +
> > > > +     siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);
> > >
> > > If you want to pay back your micro-opt budget: GFP_TEMPORARY.
> > >
> > > But then I realized much wiser heads than me removed this in 2017 from the
> > > kernel! That commit is a rather interesting story btw, if you're bored:
> > >
> > > commit 0ee931c4e31a5efb134c76440405e9219f896e33
> > > Author: Michal Hocko <mhocko@suse.com>
> > > Date:   Wed Sep 13 16:28:29 2017 -0700
> > >
> > >     mm: treewide: remove GFP_TEMPORARY allocation flag
> > >
> > > > +     if (!siblings)
> > > > +             return -ENOMEM;
> > > > +
> > > > +     for (n = 0; n < num_siblings; n++) {
> > > > +             struct i915_engine_class_instance ci;
> > > > +
> > > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> > > > +                     err = -EFAULT;
> > > > +                     goto err_siblings;
> > > > +             }
> > > > +
> > > > +             siblings[n] = intel_engine_lookup_user(i915,
> > > > +                                                    ci.engine_class,
> > > > +                                                    ci.engine_instance);
> > >
> > > intel_engine_user.c
> > >
> > > ...
> > >
> > > Maybe I should just stop looking.
> >
> > Don't think too hard.  It hurts.
> >
> > > > +             if (!siblings[n]) {
> > > > +                     drm_dbg(&i915->drm,
> > > > +                             "Invalid sibling[%d]: { class:%d, inst:%d }\n",
> > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > +                     err = -EINVAL;
> > > > +                     goto err_siblings;
> > > > +             }
> > > > +     }
> > > > +
> > > > +     if (num_siblings == 1) {
> > > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > > +             set->engines[idx].engine = siblings[0];
> > > > +             kfree(siblings);
> > > > +     } else {
> > > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
> > > > +             set->engines[idx].num_siblings = num_siblings;
> > > > +             set->engines[idx].siblings = siblings;
> > > > +     }
> > > > +
> > > > +     return 0;
> > > > +
> > > > +err_siblings:
> > > > +     kfree(siblings);
> > > > +
> > > > +     return err;
> > > > +}
> > > > +
> > > > +static int
> > > > +set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
> > > > +{
> > > > +     struct i915_context_engines_bond __user *ext =
> > > > +             container_of_user(base, typeof(*ext), base);
> > > > +     const struct set_proto_ctx_engines *set = data;
> > > > +     struct drm_i915_private *i915 = set->i915;
> > > > +     struct i915_engine_class_instance ci;
> > > > +     struct intel_engine_cs *master;
> > > > +     u16 idx, num_bonds;
> > > > +     int err, n;
> > > > +
> > > > +     if (get_user(idx, &ext->virtual_index))
> > > > +             return -EFAULT;
> > > > +
> > > > +     if (idx >= set->num_engines) {
> > > > +             drm_dbg(&i915->drm,
> > > > +                     "Invalid index for virtual engine: %d >= %d\n",
> > > > +                     idx, set->num_engines);
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     idx = array_index_nospec(idx, set->num_engines);
> > > > +     if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
> > > > +             drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
> > > > +             drm_dbg(&i915->drm,
> > > > +                     "Bonding with virtual engines not allowed\n");
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     err = check_user_mbz(&ext->flags);
> > > > +     if (err)
> > > > +             return err;
> > > > +
> > > > +     for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> > > > +             err = check_user_mbz(&ext->mbz64[n]);
> > > > +             if (err)
> > > > +                     return err;
> > > > +     }
> > > > +
> > > > +     if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> > > > +             return -EFAULT;
> > > > +
> > > > +     master = intel_engine_lookup_user(i915,
> > > > +                                       ci.engine_class,
> > > > +                                       ci.engine_instance);
> > > > +     if (!master) {
> > >
> > > It's 100% orthogonal annoyance, but maybe we can start the "what's a good
> > > name here" discussion.
> > >
> > > I'm thinking s/master/first/ and s/slave/subsequent/ that reflect how this
> > > is actually used on the execbuf side. But then this entire bonded
> > > extension is so disconnected from the actual use-case, maybe we should
> > > just sun-set it before we bother.
> >
> > primary/secondary come to mind.  But, also, I'd rather do that as a
> > separate patch since I was trying to make this mostly match.  Happy to
> > up my i915 patch count with a rename follow-on, if you want.
>
> Yeah I think we can repaint that shed as part of merging the new parallel
> submit support.
>
> > > Since we might need to keep the execlist backend implementation the
> > > renaming might still be needed.
> > >
> > > > +             drm_dbg(&i915->drm,
> > > > +                     "Unrecognised master engine: { class:%u, instance:%u }\n",
> > > > +                     ci.engine_class, ci.engine_instance);
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     if (get_user(num_bonds, &ext->num_bonds))
> > > > +             return -EFAULT;
> > > > +
> > > > +     for (n = 0; n < num_bonds; n++) {
> > > > +             struct intel_engine_cs *bond;
> > > > +
> > > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> > > > +                     return -EFAULT;
> > > > +
> > > > +             bond = intel_engine_lookup_user(i915,
> > > > +                                             ci.engine_class,
> > > > +                                             ci.engine_instance);
> > > > +             if (!bond) {
> > > > +                     drm_dbg(&i915->drm,
> > > > +                             "Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > +                     return -EINVAL;
> > > > +             }
> > > > +     }
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
> > > > +     [I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
> > > > +     [I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
> > > > +};
> > > > +
> > > > +static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
> > > > +                              struct i915_gem_proto_context *pc,
> > > > +                              const struct drm_i915_gem_context_param *args)
> > > > +{
> > > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > > +     struct set_proto_ctx_engines set = { .i915 = i915 };
> > > > +     struct i915_context_param_engines __user *user =
> > > > +             u64_to_user_ptr(args->value);
> > > > +     unsigned int n;
> > > > +     u64 extensions;
> > > > +     int err;
> > > > +
> > > > +     if (!args->size) {
> > > > +             kfree(pc->user_engines);
> > > > +             pc->num_user_engines = -1;
> > >
> > > Is this case actually used by actual userspace, or just more stuff igt
> > > loved to do?
> > >
> > > If so more uapi to ditch, and check in an igt that it's rejected.
> > >
> > > Plus standard !args->size handling here with appropriate drm_debug line
> > > and all that.
> > >
> > > > +             pc->user_engines = NULL;
> > > > +             memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
> > > > +             return 0;
> > > > +     }
> > > > +
> > > > +     BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
> > >
> > > I frankly don't know what this is checking, but it also looks harmless.
> >
> > Yeah..... All I can see is that it lets us avoid doing a subtraction
> > in the alignment check below.  Kind-of silly, IMO.
>
> I'm not seeing even that? Care to help the blind?

The array length is calculated as (args->size - sizeof(*user)) /
sizeof(*user->engines) which means that we really want (args->size -
sizeof(*user)) to be divisible by sizeof(*user->engines).  However,
instead of checking

IS_ALIGNED(args->size - sizeof(*user), sizeof(*user->engines))

we first check that sizeof(*user) is divisible by
sizeof(*user->engines) with a static check and then just check the
alignment of args->size.  I'm going to fix this mess.

> > > > +     if (args->size < sizeof(*user) ||
> > > > +         !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> > > > +             drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> > > > +                     args->size);
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> > > > +     /* RING_MASK has no shift so we can use it directly here */
> > > > +     if (set.num_engines > I915_EXEC_RING_MASK + 1)
> > > > +             return -EINVAL;
> > > > +
> > > > +     set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
> > > > +     if (!set.engines)
> > > > +             return -ENOMEM;
> > > > +
> > > > +     for (n = 0; n < set.num_engines; n++) {
> > > > +             struct i915_engine_class_instance ci;
> > > > +             struct intel_engine_cs *engine;
> > > > +
> > > > +             if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> > > > +                     kfree(set.engines);
> > > > +                     return -EFAULT;
> > > > +             }
> > > > +
> > > > +             memset(&set.engines[n], 0, sizeof(set.engines[n]));
> > > > +
> > > > +             if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> > > > +                 ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
> > > > +                     continue;
> > > > +
> > > > +             engine = intel_engine_lookup_user(i915,
> > > > +                                               ci.engine_class,
> > > > +                                               ci.engine_instance);
> > > > +             if (!engine) {
> > > > +                     drm_dbg(&i915->drm,
> > > > +                             "Invalid engine[%d]: { class:%d, instance:%d }\n",
> > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > +                     kfree(set.engines);
> > > > +                     return -ENOENT;
> > > > +             }
> > > > +
> > > > +             set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > > +             set.engines[n].engine = engine;
> > > > +     }
> > > > +
> > > > +     err = -EFAULT;
> > > > +     if (!get_user(extensions, &user->extensions))
> > > > +             err = i915_user_extensions(u64_to_user_ptr(extensions),
> > > > +                                        set_proto_ctx_engines_extensions,
> > > > +                                        ARRAY_SIZE(set_proto_ctx_engines_extensions),
> > > > +                                        &set);
> > > > +     if (err) {
> > > > +             kfree(set.engines);
> > > > +             return err;
> > > > +     }
> > > > +
> > > > +     kfree(pc->user_engines);
> > >
> > > Both of these kfree potentially leak engines[].siblings. I think you need
> > > to extract a proto_context_free_engines helper and use that 2x here and
> > > once at the very top in proto_context_close().
> >
> > Good catch. Done.
> >
> > > > +     pc->num_user_engines = set.num_engines;
> > > > +     pc->user_engines = set.engines;
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
> > > > +                           struct i915_gem_proto_context *pc,
> > > > +                           struct drm_i915_gem_context_param *args)
> > > > +{
> > > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > > +     struct drm_i915_gem_context_param_sseu user_sseu;
> > > > +     struct intel_sseu *sseu;
> > > > +     int ret;
> > > > +
> > > > +     if (args->size < sizeof(user_sseu))
> > > > +             return -EINVAL;
> > > > +
> > > > +     if (!IS_GEN(i915, 11))
> > > > +             return -ENODEV;
> > > > +
> > > > +     if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
> > > > +                        sizeof(user_sseu)))
> > > > +             return -EFAULT;
> > > > +
> > > > +     if (user_sseu.rsvd)
> > > > +             return -EINVAL;
> > > > +
> > > > +     if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
> > > > +             return -EINVAL;
> > > > +
> > > > +     if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
> > > > +             return -EINVAL;
> > > > +
> > > > +     if (pc->num_user_engines >= 0) {
> > > > +             int idx = user_sseu.engine.engine_instance;
> > > > +             struct i915_gem_proto_engine *pe;
> > > > +
> > > > +             if (idx >= pc->num_user_engines)
> > > > +                     return -EINVAL;
> > > > +
> > > > +             pe = &pc->user_engines[idx];
> > > > +
> > > > +             /* Only render engine supports RPCS configuration. */
> > > > +             if (pe->engine->class != RENDER_CLASS)
> > > > +                     return -EINVAL;
> > > > +
> > > > +             sseu = &pe->sseu;
> > > > +     } else {
> > > > +             /* Only render engine supports RPCS configuration. */
> > > > +             if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
> > > > +                     return -EINVAL;
> > > > +
> > > > +             /* There is only one render engine */
> > > > +             if (user_sseu.engine.engine_instance != 0)
> > > > +                     return -EINVAL;
> > > > +
> > > > +             sseu = &pc->legacy_rcs_sseu;
> > > > +     }
> > >
> > > I think this faithfully rebuilds the convoluted and I think largely
> > > accidental semantics of SSEU for all combinations of ordering against
> > > set_engines.
> > >
> > > Maybe add a commit message note about this particular kind of fun here. I
> > > don't think a code comment is warranted since I don't think I've seen a
> > > userspace rely on how sseu interacts with set_engines
> >
> > Done.
> >
> > > > +
> > > > +     ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
> > > > +     if (ret)
> > > > +             return ret;
> > > > +
> > > > +     args->size = sizeof(user_sseu);
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
> > > > +                            struct i915_gem_proto_context *pc,
> > > > +                            struct drm_i915_gem_context_param *args)
> > > > +{
> > > > +     int ret = 0;
> > > > +
> > > > +     switch (args->param) {
> > > > +     case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
> > > > +             if (args->size)
> > > > +                     ret = -EINVAL;
> > > > +             else if (args->value)
> > > > +                     __set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > > > +             else
> > > > +                     __clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > >
> > > Open code please and double check I caught them all ...
> >
> > As I commented the first time around, __set/clear_bit are static
> > inlines that unroll to "*field |= (1 << bit)" or "*field &= ~(1 <<
> > bit)" as appropriate.  The non-__ versions do atomics.  I could
> > hand-roll them but that seems error-prone and it gains us nothing.
>
> They do more, they treat this as a potential array of unsigned long as a
> bitfield of unlimted size. This comes from the cpuset support afaiu our
> history here, and years ago (decades by now?) linux started supporting
> more than 64 cpus cores. Our flags are definitely not unlimted and fit in
> an unsigned, so we're dropping some compiler checking here.
>
> Also it's not that bad really:
>
>         if (args->value)
>                 pc->user_flags |= BIT(UCONTEXT_NO_ERROR_CAPTURE);
>         else
>                 pc->user_flags &= ~BIT(UCONTEXT_NO_ERROR_CAPTURE);
>
> Fairly idiomatic construct. Final argument here is that __func() generally
> means "beware, check carefuly what's going on here", and nothing funny is
> going on here at all, so it's a bit a negative trap :-)
>
> Anyway git grep shows you're not the first (even outside of drm/i915).
> Some spot checking with grep shows that bitflag use of __set_bit is about
> a third of overall use:
>
> $ git grep '__set_bit.*)' | wc -l
> 1761
>
> $ git grep '__set_bit.*,\s*&.*)' | wc -l
> 479
>
> So whatever you feel like.

Your shed, your colors.  I just wanted a reason and to know you
weren't missing something.

> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_BANNABLE:
> > > > +             if (args->size)
> > > > +                     ret = -EINVAL;
> > > > +             else if (!capable(CAP_SYS_ADMIN) && !args->value)
> > > > +                     ret = -EPERM;
> > > > +             else if (args->value)
> > > > +                     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > > +             else
> > > > +                     __clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_RECOVERABLE:
> > > > +             if (args->size)
> > > > +                     ret = -EINVAL;
> > > > +             else if (args->value)
> > > > +                     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > > +             else
> > > > +                     __clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_PRIORITY:
> > > > +             ret = validate_priority(fpriv->dev_priv, args);
> > > > +             if (!ret)
> > > > +                     pc->sched.priority = args->value;
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_SSEU:
> > > > +             ret = set_proto_ctx_sseu(fpriv, pc, args);
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_VM:
> > > > +             ret = set_proto_ctx_vm(fpriv, pc, args);
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_ENGINES:
> > > > +             ret = set_proto_ctx_engines(fpriv, pc, args);
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_PERSISTENCE:
> > > > +             if (args->size)
> > > > +                     ret = -EINVAL;
> > > > +             else if (args->value)
> > > > +                     __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > > > +             else
> > > > +                     __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > >
> > > I think we have a nice mess here. You created this
> > > proto_context_set_persistence helper, but don't use it here. Oversight?
> >
> > Yeah, I should use it.  Done.
> >
> > > Aside from the validation fun around persistence, but that's better
> > > discussed in another patch I think.
> > >
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_NO_ZEROMAP:
> > > > +     case I915_CONTEXT_PARAM_BAN_PERIOD:
> > > > +     case I915_CONTEXT_PARAM_RINGSIZE:
> > > > +     default:
> > > > +             ret = -EINVAL;
> > > > +             break;
> > > > +     }
> > > > +
> > > > +     return ret;
> > > > +}
> > > > +
> > > >  static struct i915_address_space *
> > > >  context_get_vm_rcu(struct i915_gem_context *ctx)
> > > >  {
> > > > @@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> > > >       return err;
> > > >  }
> > > >
> > > > +static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
> > > > +                                          unsigned int num_engines,
> > > > +                                          struct i915_gem_proto_engine *pe)
> > > > +{
> > > > +     struct i915_gem_engines *e, *err;
> > > > +     unsigned int n;
> > > > +
> > > > +     e = alloc_engines(num_engines);
> > > > +     for (n = 0; n < num_engines; n++) {
> > > > +             struct intel_context *ce;
> > > > +             int ret;
> > > > +
> > > > +             switch (pe[n].type) {
> > > > +             case I915_GEM_ENGINE_TYPE_PHYSICAL:
> > > > +                     ce = intel_context_create(pe[n].engine);
> > > > +                     break;
> > > > +
> > > > +             case I915_GEM_ENGINE_TYPE_BALANCED:
> > > > +                     ce = intel_execlists_create_virtual(pe[n].siblings,
> > > > +                                                         pe[n].num_siblings);
> > > > +                     break;
> > > > +
> > > > +             case I915_GEM_ENGINE_TYPE_INVALID:
> > > > +             default:
> > > > +                     GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
> > > > +                     continue;
> > > > +             }
> > > > +
> > > > +             if (IS_ERR(ce)) {
> > > > +                     err = ERR_CAST(ce);
> > > > +                     goto free_engines;
> > > > +             }
> > > > +
> > > > +             e->engines[n] = ce;
> > > > +
> > > > +             ret = intel_context_set_gem(ce, ctx, pe->sseu);
> > > > +             if (ret) {
> > > > +                     err = ERR_PTR(ret);
> > > > +                     goto free_engines;
> > > > +             }
> > > > +     }
> > > > +     e->num_engines = num_engines;
> > > > +
> > > > +     return e;
> > > > +
> > > > +free_engines:
> > > > +     free_engines(e);
> > > > +     return err;
> > > > +}
> > > > +
> > > >  void i915_gem_context_release(struct kref *ref)
> > > >  {
> > > >       struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
> > > > @@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
> > > >  {
> > > >       struct i915_gem_context *ctx;
> > > >       struct i915_gem_engines *e;
> > > > -     struct intel_sseu null_sseu = {};
> > > >       int err;
> > > >       int i;
> > > >
> > > > @@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
> > > >       INIT_LIST_HEAD(&ctx->stale.engines);
> > > >
> > > >       mutex_init(&ctx->engines_mutex);
> > > > -     e = default_engines(ctx, null_sseu);
> > > > +     e = default_engines(ctx, pc->legacy_rcs_sseu);
> > > >       if (IS_ERR(e)) {
> > > >               err = PTR_ERR(e);
> > > >               goto err_free;
> > > > @@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
> > > >               mutex_unlock(&ctx->mutex);
> > > >       }
> > > >
> > > > +     if (pc->num_user_engines >= 0) {
> > > > +             struct i915_gem_engines *engines;
> > > > +
> > > > +             engines = user_engines(ctx, pc->num_user_engines,
> > > > +                                    pc->user_engines);
> > > > +             if (IS_ERR(engines)) {
> > > > +                     context_close(ctx);
> > > > +                     return ERR_CAST(engines);
> > > > +             }
> > > > +
> > > > +             mutex_lock(&ctx->engines_mutex);
> > > > +             i915_gem_context_set_user_engines(ctx);
> > > > +             engines = rcu_replace_pointer(ctx->engines, engines, 1);
> > > > +             mutex_unlock(&ctx->engines_mutex);
> > >
> > > More locking code to ditch I guess.
> >
> > Sure.  Is it safe to just drop it?  I guess it is?  I'm really shaky
> > around all the RCU requirements and things.
>
> Well the 1 in here should be replace with
> lockdep_is_held(&ctx->engines_mutex), but the engines_mutex also should
> go, so really can ditch the entire thing. Also no one can access our
> context, so we can't fail.
>
> Now if you do this naively without dropping the __rcu classifier for
> ctx->engines then static checkers will complain. So until that's done an
> rcu_assign_pointer should do.

This is all nuked by the last patch.  If it's all the same to you, I'd
rather leave the re-typed stupid boiler-plate here and delete it and
do it properly there.  That patch sets up an engine set once and uses
RCU_INIT_POINTER.

--Jason

> >
> > > > +
> > > > +             free_engines(engines);
> > >
> > > Also I guess we shouldn't first create the legacy engines for this case?
> >
> > That's fixed in the last patch.
>
> Yeah I noticed later on.
>
> >
> > > > +     }
> > > > +
> > > >       if (pc->single_timeline) {
> > > >               ret = drm_syncobj_create(&ctx->syncobj,
> > > >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> > > > @@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
> > > >  }
> > > >
> > > >  struct create_ext {
> > > > -     struct i915_gem_context *ctx;
> > > > +     struct i915_gem_proto_context *pc;
> > > >       struct drm_i915_file_private *fpriv;
> > > >  };
> > > >
> > > > @@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
> > > >       if (local.param.ctx_id)
> > > >               return -EINVAL;
> > > >
> > > > -     return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> > > > +     return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
> > > >  }
> > > >
> > > >  static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> > > > @@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > >  {
> > > >       struct drm_i915_private *i915 = to_i915(dev);
> > > >       struct drm_i915_gem_context_create_ext *args = data;
> > > > -     struct i915_gem_proto_context *pc;
> > > > +     struct i915_gem_context *ctx;
> > > >       struct create_ext ext_data;
> > > >       int ret;
> > > >       u32 id;
> > > > @@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > >               return -EIO;
> > > >       }
> > > >
> > > > -     pc = proto_context_create(i915, args->flags);
> > > > -     if (IS_ERR(pc))
> > > > -             return PTR_ERR(pc);
> > > > -
> > > > -     ext_data.ctx = i915_gem_create_context(i915, pc);
> > > > -     proto_context_close(pc);
> > > > -     if (IS_ERR(ext_data.ctx))
> > > > -             return PTR_ERR(ext_data.ctx);
> > > > +     ext_data.pc = proto_context_create(i915, args->flags);
> > > > +     if (IS_ERR(ext_data.pc))
> > > > +             return PTR_ERR(ext_data.pc);
> > > >
> > > >       if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
> > > >               ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
> > > >                                          create_extensions,
> > > >                                          ARRAY_SIZE(create_extensions),
> > > >                                          &ext_data);
> > > > -             if (ret)
> > > > -                     goto err_ctx;
> > > > +             if (ret) {
> > > > +                     proto_context_close(ext_data.pc);
> > > > +                     return ret;
> > > > +             }
> > > >       }
> > > >
> > > > -     ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
> > > > +     ctx = i915_gem_create_context(i915, ext_data.pc);
> > > > +     proto_context_close(ext_data.pc);
> > > > +     if (IS_ERR(ctx))
> > > > +             return PTR_ERR(ctx);
> > > > +
> > > > +     ret = gem_context_register(ctx, ext_data.fpriv, &id);
> > > >       if (ret < 0)
> > > >               goto err_ctx;
> > > >
> > > > @@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > >       return 0;
> > > >
> > > >  err_ctx:
> > > > -     context_close(ext_data.ctx);
> > > > +     context_close(ctx);
> > > >       return ret;
> > > >  }
> > > >
> > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > index 0bf337b6d89ac..2ac341f805c8f 100644
> > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > @@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
> > > >       const struct i915_gem_engines *engines;
> > > >  };
> > > >
> > > > +/**
> > > > + * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
> > > > + */
> > > > +enum i915_gem_engine_type {
> > > > +     /** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
> > > > +     I915_GEM_ENGINE_TYPE_INVALID = 0,
> > > > +
> > > > +     /** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
> > > > +     I915_GEM_ENGINE_TYPE_PHYSICAL,
> > > > +
> > > > +     /** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
> > > > +     I915_GEM_ENGINE_TYPE_BALANCED,
> > > > +};
> > > > +
> > > > +/**
> > > > + * struct i915_gem_proto_engine - prototype engine
> > > > + *
> > > > + * This struct describes an engine that a context may contain.  Engines
> > > > + * have three types:
> > > > + *
> > > > + *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
> > > > + *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
> > > > + *    use them by the user results in -EINVAL.  They are also useful during
> > > > + *    proto-context construction because the client may create invalid
> > > > + *    engines and then set them up later as bonded engines.
> > > > + *
> > > > + *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
> > > > + *    i915_gem_proto_engine::engine.
> > > > + *
> > > > + *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
> > > > + *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
> > > > + */
> > > > +struct i915_gem_proto_engine {
> > > > +     /** @type: Type of this engine */
> > > > +     enum i915_gem_engine_type type;
> > > > +
> > > > +     /** @engine: Engine, for physical */
> > > > +     struct intel_engine_cs *engine;
> > > > +
> > > > +     /** @num_siblings: Number of balanced siblings */
> > > > +     unsigned int num_siblings;
> > > > +
> > > > +     /** @siblings: Balanced siblings */
> > > > +     struct intel_engine_cs **siblings;
> > > > +
> > > > +     /** @sseu: Client-set SSEU parameters */
> > > > +     struct intel_sseu sseu;
> > > > +};
> > > > +
> > > >  /**
> > > >   * struct i915_gem_proto_context - prototype context
> > > >   *
> > > > @@ -84,6 +133,15 @@ struct i915_gem_proto_context {
> > > >       /** @sched: See i915_gem_context::sched */
> > > >       struct i915_sched_attr sched;
> > > >
> > > > +     /** @num_user_engines: Number of user-specified engines or -1 */
> > > > +     int num_user_engines;
> > > > +
> > > > +     /** @user_engines: User-specified engines */
> > > > +     struct i915_gem_proto_engine *user_engines;
> > > > +
> > > > +     /** @sseu: Client-set SSEU parameters for the legacy RCS */
> > > > +     struct intel_sseu legacy_rcs_sseu;
> > > > +
> > > >       /** @single_timeline: See See i915_gem_context::syncobj */
> > > >       bool single_timeline;
> > > >  };
> > > > --
> > > > 2.31.1
> > >
> > > Man is this all nasty. Since I don't want to re-review the entire pile,
> > > assuming we figure out solutions to all the real issues I've raised (and
> > > not the snarky bikesheds) this is
> > >
> > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >
> > Ok.  I'm leaving it off for now to remind myself to ensure that we
> > close on everything.  I'll add it once I've heard back from you on my
> > questions above.
>
> I think we're all good. Mostly :-/
> -Daniel
>
> >
> > --Jason
> >
> > > >
> > > > _______________________________________________
> > > > dri-devel mailing list
> > > > dri-devel@lists.freedesktop.org
> > > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> > >
> > > --
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > http://blog.ffwll.ch
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
@ 2021-05-17 17:04           ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-05-17 17:04 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Mon, May 17, 2021 at 8:40 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Fri, May 14, 2021 at 02:13:57PM -0500, Jason Ekstrand wrote:
> > On Tue, May 4, 2021 at 3:33 PM Daniel Vetter <daniel@ffwll.ch> wrote:
> > >
> > > On Mon, May 03, 2021 at 10:57:40AM -0500, Jason Ekstrand wrote:
> > > > This means that the proto-context needs to grow support for engine
> > > > configuration information as well as setparam logic.  Fortunately, we'll
> > > > be deleting a lot of setparam logic on the primary context shortly so it
> > > > will hopefully balance out.
> > > >
> > > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > > > ---
> > > >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
> > > >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
> > > >  2 files changed, 587 insertions(+), 17 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > index 6dd50d669c5b9..aa4edfbf7ed48 100644
> > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > @@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
> > > >
> > > >  static void proto_context_close(struct i915_gem_proto_context *pc)
> > > >  {
> > > > +     int i;
> > > > +
> > > >       if (pc->vm)
> > > >               i915_vm_put(pc->vm);
> > > > +     if (pc->user_engines) {
> > > > +             for (i = 0; i < pc->num_user_engines; i++)
> > > > +                     kfree(pc->user_engines[i].siblings);
> > > > +             kfree(pc->user_engines);
> > >
> > >                 free_engines(&pc->user_engines);
> > >
> > > Maybe even stuff that if check into free_engines. Except I realized this
> > > is proto engines here now :-(
> > >
> > > > +     }
> > > >       kfree(pc);
> > > >  }
> > > >
> > > > @@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > > >       if (!pc)
> > > >               return ERR_PTR(-ENOMEM);
> > > >
> > > > +     pc->num_user_engines = -1;
> > > > +     pc->user_engines = NULL;
> > > > +
> > > >       if (HAS_FULL_PPGTT(i915)) {
> > > >               struct i915_ppgtt *ppgtt;
> > > >
> > > > @@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > > >       return err;
> > > >  }
> > > >
> > > > +static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
> > > > +                         struct i915_gem_proto_context *pc,
> > > > +                         const struct drm_i915_gem_context_param *args)
> > > > +{
> > > > +     struct i915_address_space *vm;
> > > > +
> > > > +     if (args->size)
> > > > +             return -EINVAL;
> > > > +
> > > > +     if (!pc->vm)
> > > > +             return -ENODEV;
> > > > +
> > > > +     if (upper_32_bits(args->value))
> > > > +             return -ENOENT;
> > > > +
> > > > +     rcu_read_lock();
> > > > +     vm = xa_load(&fpriv->vm_xa, args->value);
> > > > +     if (vm && !kref_get_unless_zero(&vm->ref))
> > > > +             vm = NULL;
> > > > +     rcu_read_unlock();
> > >
> > > vm lookup helpers would be nice I guess, but perhaps something that
> > > vm_bind patches should do.
> >
> > I can add those.  I just don't know where to put it.  We don't have an
> > i915_gem_vm.h.  Suggestions?
>
> gt/intel_gtt.h seems to be the header for i915_address_space stuff. Also
> contains the i915_vma_ops but not i915_vma.
>
> It's a pretty good mess, but probably the best place for now for these :-/

The one for contexts is in i915_drv.h so I put the VM one there too.
Feel free to tell me to move it.  I don't care where it goes.

> >
> > >
> > > > +     if (!vm)
> > > > +             return -ENOENT;
> > > > +
> > > > +     i915_vm_put(pc->vm);
> > >
> > > Ah I guess I've found why you went with "pc->vm is always set". *shrug*
> > >
> > > > +     pc->vm = vm;
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +struct set_proto_ctx_engines {
> > > > +     struct drm_i915_private *i915;
> > > > +     unsigned num_engines;
> > > > +     struct i915_gem_proto_engine *engines;
> > > > +};
> > > > +
> > > > +static int
> > > > +set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
> > > > +                           void *data)
> > > > +{
> > > > +     struct i915_context_engines_load_balance __user *ext =
> > > > +             container_of_user(base, typeof(*ext), base);
> > > > +     const struct set_proto_ctx_engines *set = data;
> > > > +     struct drm_i915_private *i915 = set->i915;
> > > > +     struct intel_engine_cs **siblings;
> > > > +     u16 num_siblings, idx;
> > > > +     unsigned int n;
> > > > +     int err;
> > > > +
> > > > +     if (!HAS_EXECLISTS(i915))
> > > > +             return -ENODEV;
> > > > +
> > > > +     if (intel_uc_uses_guc_submission(&i915->gt.uc))
> > > > +             return -ENODEV; /* not implement yet */
> > > > +
> > > > +     if (get_user(idx, &ext->engine_index))
> > > > +             return -EFAULT;
> > > > +
> > > > +     if (idx >= set->num_engines) {
> > > > +             drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> > > > +                     idx, set->num_engines);
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     idx = array_index_nospec(idx, set->num_engines);
> > > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
> > > > +             drm_dbg(&i915->drm,
> > > > +                     "Invalid placement[%d], already occupied\n", idx);
> > > > +             return -EEXIST;
> > > > +     }
> > > > +
> > > > +     if (get_user(num_siblings, &ext->num_siblings))
> > > > +             return -EFAULT;
> > > > +
> > > > +     err = check_user_mbz(&ext->flags);
> > > > +     if (err)
> > > > +             return err;
> > > > +
> > > > +     err = check_user_mbz(&ext->mbz64);
> > > > +     if (err)
> > > > +             return err;
> > > > +
> > > > +     if (num_siblings == 0)
>
> > >
> > > You deleted the on-stack siblings micro-optimization.
> > >
> > > I'm shocked.
> >
> > Yup.  If balanced engine create overhead when balancing across a
> > single engine ever becomes a bottleneck in some UMD, I'm happy to deal
> > with it then.  And I intend to deal with it by banning whatever
> > developer decided balancing across single engine was a good idea.
>
> I should have annotated this with /s

I detected your sarcasm and returned it. :-P

> > > > +
> > > > +     siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);
> > >
> > > If you want to pay back your micro-opt budget: GFP_TEMPORARY.
> > >
> > > But then I realized much wiser heads than me removed this in 2017 from the
> > > kernel! That commit is a rather interesting story btw, if you're bored:
> > >
> > > commit 0ee931c4e31a5efb134c76440405e9219f896e33
> > > Author: Michal Hocko <mhocko@suse.com>
> > > Date:   Wed Sep 13 16:28:29 2017 -0700
> > >
> > >     mm: treewide: remove GFP_TEMPORARY allocation flag
> > >
> > > > +     if (!siblings)
> > > > +             return -ENOMEM;
> > > > +
> > > > +     for (n = 0; n < num_siblings; n++) {
> > > > +             struct i915_engine_class_instance ci;
> > > > +
> > > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> > > > +                     err = -EFAULT;
> > > > +                     goto err_siblings;
> > > > +             }
> > > > +
> > > > +             siblings[n] = intel_engine_lookup_user(i915,
> > > > +                                                    ci.engine_class,
> > > > +                                                    ci.engine_instance);
> > >
> > > intel_engine_user.c
> > >
> > > ...
> > >
> > > Maybe I should just stop looking.
> >
> > Don't think too hard.  It hurts.
> >
> > > > +             if (!siblings[n]) {
> > > > +                     drm_dbg(&i915->drm,
> > > > +                             "Invalid sibling[%d]: { class:%d, inst:%d }\n",
> > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > +                     err = -EINVAL;
> > > > +                     goto err_siblings;
> > > > +             }
> > > > +     }
> > > > +
> > > > +     if (num_siblings == 1) {
> > > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > > +             set->engines[idx].engine = siblings[0];
> > > > +             kfree(siblings);
> > > > +     } else {
> > > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
> > > > +             set->engines[idx].num_siblings = num_siblings;
> > > > +             set->engines[idx].siblings = siblings;
> > > > +     }
> > > > +
> > > > +     return 0;
> > > > +
> > > > +err_siblings:
> > > > +     kfree(siblings);
> > > > +
> > > > +     return err;
> > > > +}
> > > > +
> > > > +static int
> > > > +set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
> > > > +{
> > > > +     struct i915_context_engines_bond __user *ext =
> > > > +             container_of_user(base, typeof(*ext), base);
> > > > +     const struct set_proto_ctx_engines *set = data;
> > > > +     struct drm_i915_private *i915 = set->i915;
> > > > +     struct i915_engine_class_instance ci;
> > > > +     struct intel_engine_cs *master;
> > > > +     u16 idx, num_bonds;
> > > > +     int err, n;
> > > > +
> > > > +     if (get_user(idx, &ext->virtual_index))
> > > > +             return -EFAULT;
> > > > +
> > > > +     if (idx >= set->num_engines) {
> > > > +             drm_dbg(&i915->drm,
> > > > +                     "Invalid index for virtual engine: %d >= %d\n",
> > > > +                     idx, set->num_engines);
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     idx = array_index_nospec(idx, set->num_engines);
> > > > +     if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
> > > > +             drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
> > > > +             drm_dbg(&i915->drm,
> > > > +                     "Bonding with virtual engines not allowed\n");
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     err = check_user_mbz(&ext->flags);
> > > > +     if (err)
> > > > +             return err;
> > > > +
> > > > +     for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> > > > +             err = check_user_mbz(&ext->mbz64[n]);
> > > > +             if (err)
> > > > +                     return err;
> > > > +     }
> > > > +
> > > > +     if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> > > > +             return -EFAULT;
> > > > +
> > > > +     master = intel_engine_lookup_user(i915,
> > > > +                                       ci.engine_class,
> > > > +                                       ci.engine_instance);
> > > > +     if (!master) {
> > >
> > > It's 100% orthogonal annoyance, but maybe we can start the "what's a good
> > > name here" discussion.
> > >
> > > I'm thinking s/master/first/ and s/slave/subsequent/ that reflect how this
> > > is actually used on the execbuf side. But then this entire bonded
> > > extension is so disconnected from the actual use-case, maybe we should
> > > just sun-set it before we bother.
> >
> > primary/secondary come to mind.  But, also, I'd rather do that as a
> > separate patch since I was trying to make this mostly match.  Happy to
> > up my i915 patch count with a rename follow-on, if you want.
>
> Yeah I think we can repaint that shed as part of merging the new parallel
> submit support.
>
> > > Since we might need to keep the execlist backend implementation the
> > > renaming might still be needed.
> > >
> > > > +             drm_dbg(&i915->drm,
> > > > +                     "Unrecognised master engine: { class:%u, instance:%u }\n",
> > > > +                     ci.engine_class, ci.engine_instance);
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     if (get_user(num_bonds, &ext->num_bonds))
> > > > +             return -EFAULT;
> > > > +
> > > > +     for (n = 0; n < num_bonds; n++) {
> > > > +             struct intel_engine_cs *bond;
> > > > +
> > > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> > > > +                     return -EFAULT;
> > > > +
> > > > +             bond = intel_engine_lookup_user(i915,
> > > > +                                             ci.engine_class,
> > > > +                                             ci.engine_instance);
> > > > +             if (!bond) {
> > > > +                     drm_dbg(&i915->drm,
> > > > +                             "Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > +                     return -EINVAL;
> > > > +             }
> > > > +     }
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
> > > > +     [I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
> > > > +     [I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
> > > > +};
> > > > +
> > > > +static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
> > > > +                              struct i915_gem_proto_context *pc,
> > > > +                              const struct drm_i915_gem_context_param *args)
> > > > +{
> > > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > > +     struct set_proto_ctx_engines set = { .i915 = i915 };
> > > > +     struct i915_context_param_engines __user *user =
> > > > +             u64_to_user_ptr(args->value);
> > > > +     unsigned int n;
> > > > +     u64 extensions;
> > > > +     int err;
> > > > +
> > > > +     if (!args->size) {
> > > > +             kfree(pc->user_engines);
> > > > +             pc->num_user_engines = -1;
> > >
> > > Is this case actually used by actual userspace, or just more stuff igt
> > > loved to do?
> > >
> > > If so more uapi to ditch, and check in an igt that it's rejected.
> > >
> > > Plus standard !args->size handling here with appropriate drm_debug line
> > > and all that.
> > >
> > > > +             pc->user_engines = NULL;
> > > > +             memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
> > > > +             return 0;
> > > > +     }
> > > > +
> > > > +     BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
> > >
> > > I frankly don't know what this is checking, but it also looks harmless.
> >
> > Yeah..... All I can see is that it lets us avoid doing a subtraction
> > in the alignment check below.  Kind-of silly, IMO.
>
> I'm not seeing even that? Care to help the blind?

The array length is calculated as (args->size - sizeof(*user)) /
sizeof(*user->engines) which means that we really want (args->size -
sizeof(*user)) to be divisible by sizeof(*user->engines).  However,
instead of checking

IS_ALIGNED(args->size - sizeof(*user), sizeof(*user->engines))

we first check that sizeof(*user) is divisible by
sizeof(*user->engines) with a static check and then just check the
alignment of args->size.  I'm going to fix this mess.

> > > > +     if (args->size < sizeof(*user) ||
> > > > +         !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> > > > +             drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> > > > +                     args->size);
> > > > +             return -EINVAL;
> > > > +     }
> > > > +
> > > > +     set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> > > > +     /* RING_MASK has no shift so we can use it directly here */
> > > > +     if (set.num_engines > I915_EXEC_RING_MASK + 1)
> > > > +             return -EINVAL;
> > > > +
> > > > +     set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
> > > > +     if (!set.engines)
> > > > +             return -ENOMEM;
> > > > +
> > > > +     for (n = 0; n < set.num_engines; n++) {
> > > > +             struct i915_engine_class_instance ci;
> > > > +             struct intel_engine_cs *engine;
> > > > +
> > > > +             if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> > > > +                     kfree(set.engines);
> > > > +                     return -EFAULT;
> > > > +             }
> > > > +
> > > > +             memset(&set.engines[n], 0, sizeof(set.engines[n]));
> > > > +
> > > > +             if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> > > > +                 ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
> > > > +                     continue;
> > > > +
> > > > +             engine = intel_engine_lookup_user(i915,
> > > > +                                               ci.engine_class,
> > > > +                                               ci.engine_instance);
> > > > +             if (!engine) {
> > > > +                     drm_dbg(&i915->drm,
> > > > +                             "Invalid engine[%d]: { class:%d, instance:%d }\n",
> > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > +                     kfree(set.engines);
> > > > +                     return -ENOENT;
> > > > +             }
> > > > +
> > > > +             set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > > +             set.engines[n].engine = engine;
> > > > +     }
> > > > +
> > > > +     err = -EFAULT;
> > > > +     if (!get_user(extensions, &user->extensions))
> > > > +             err = i915_user_extensions(u64_to_user_ptr(extensions),
> > > > +                                        set_proto_ctx_engines_extensions,
> > > > +                                        ARRAY_SIZE(set_proto_ctx_engines_extensions),
> > > > +                                        &set);
> > > > +     if (err) {
> > > > +             kfree(set.engines);
> > > > +             return err;
> > > > +     }
> > > > +
> > > > +     kfree(pc->user_engines);
> > >
> > > Both of these kfree potentially leak engines[].siblings. I think you need
> > > to extract a proto_context_free_engines helper and use that 2x here and
> > > once at the very top in proto_context_close().
> >
> > Good catch. Done.
> >
> > > > +     pc->num_user_engines = set.num_engines;
> > > > +     pc->user_engines = set.engines;
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
> > > > +                           struct i915_gem_proto_context *pc,
> > > > +                           struct drm_i915_gem_context_param *args)
> > > > +{
> > > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > > +     struct drm_i915_gem_context_param_sseu user_sseu;
> > > > +     struct intel_sseu *sseu;
> > > > +     int ret;
> > > > +
> > > > +     if (args->size < sizeof(user_sseu))
> > > > +             return -EINVAL;
> > > > +
> > > > +     if (!IS_GEN(i915, 11))
> > > > +             return -ENODEV;
> > > > +
> > > > +     if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
> > > > +                        sizeof(user_sseu)))
> > > > +             return -EFAULT;
> > > > +
> > > > +     if (user_sseu.rsvd)
> > > > +             return -EINVAL;
> > > > +
> > > > +     if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
> > > > +             return -EINVAL;
> > > > +
> > > > +     if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
> > > > +             return -EINVAL;
> > > > +
> > > > +     if (pc->num_user_engines >= 0) {
> > > > +             int idx = user_sseu.engine.engine_instance;
> > > > +             struct i915_gem_proto_engine *pe;
> > > > +
> > > > +             if (idx >= pc->num_user_engines)
> > > > +                     return -EINVAL;
> > > > +
> > > > +             pe = &pc->user_engines[idx];
> > > > +
> > > > +             /* Only render engine supports RPCS configuration. */
> > > > +             if (pe->engine->class != RENDER_CLASS)
> > > > +                     return -EINVAL;
> > > > +
> > > > +             sseu = &pe->sseu;
> > > > +     } else {
> > > > +             /* Only render engine supports RPCS configuration. */
> > > > +             if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
> > > > +                     return -EINVAL;
> > > > +
> > > > +             /* There is only one render engine */
> > > > +             if (user_sseu.engine.engine_instance != 0)
> > > > +                     return -EINVAL;
> > > > +
> > > > +             sseu = &pc->legacy_rcs_sseu;
> > > > +     }
> > >
> > > I think this faithfully rebuilds the convoluted and I think largely
> > > accidental semantics of SSEU for all combinations of ordering against
> > > set_engines.
> > >
> > > Maybe add a commit message note about this particular kind of fun here. I
> > > don't think a code comment is warranted since I don't think I've seen a
> > > userspace rely on how sseu interacts with set_engines
> >
> > Done.
> >
> > > > +
> > > > +     ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
> > > > +     if (ret)
> > > > +             return ret;
> > > > +
> > > > +     args->size = sizeof(user_sseu);
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
> > > > +                            struct i915_gem_proto_context *pc,
> > > > +                            struct drm_i915_gem_context_param *args)
> > > > +{
> > > > +     int ret = 0;
> > > > +
> > > > +     switch (args->param) {
> > > > +     case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
> > > > +             if (args->size)
> > > > +                     ret = -EINVAL;
> > > > +             else if (args->value)
> > > > +                     __set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > > > +             else
> > > > +                     __clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > >
> > > Open code please and double check I caught them all ...
> >
> > As I commented the first time around, __set/clear_bit are static
> > inlines that unroll to "*field |= (1 << bit)" or "*field &= ~(1 <<
> > bit)" as appropriate.  The non-__ versions do atomics.  I could
> > hand-roll them but that seems error-prone and it gains us nothing.
>
> They do more, they treat this as a potential array of unsigned long as a
> bitfield of unlimted size. This comes from the cpuset support afaiu our
> history here, and years ago (decades by now?) linux started supporting
> more than 64 cpus cores. Our flags are definitely not unlimted and fit in
> an unsigned, so we're dropping some compiler checking here.
>
> Also it's not that bad really:
>
>         if (args->value)
>                 pc->user_flags |= BIT(UCONTEXT_NO_ERROR_CAPTURE);
>         else
>                 pc->user_flags &= ~BIT(UCONTEXT_NO_ERROR_CAPTURE);
>
> Fairly idiomatic construct. Final argument here is that __func() generally
> means "beware, check carefuly what's going on here", and nothing funny is
> going on here at all, so it's a bit a negative trap :-)
>
> Anyway git grep shows you're not the first (even outside of drm/i915).
> Some spot checking with grep shows that bitflag use of __set_bit is about
> a third of overall use:
>
> $ git grep '__set_bit.*)' | wc -l
> 1761
>
> $ git grep '__set_bit.*,\s*&.*)' | wc -l
> 479
>
> So whatever you feel like.

Your shed, your colors.  I just wanted a reason and to know you
weren't missing something.

> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_BANNABLE:
> > > > +             if (args->size)
> > > > +                     ret = -EINVAL;
> > > > +             else if (!capable(CAP_SYS_ADMIN) && !args->value)
> > > > +                     ret = -EPERM;
> > > > +             else if (args->value)
> > > > +                     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > > +             else
> > > > +                     __clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_RECOVERABLE:
> > > > +             if (args->size)
> > > > +                     ret = -EINVAL;
> > > > +             else if (args->value)
> > > > +                     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > > +             else
> > > > +                     __clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_PRIORITY:
> > > > +             ret = validate_priority(fpriv->dev_priv, args);
> > > > +             if (!ret)
> > > > +                     pc->sched.priority = args->value;
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_SSEU:
> > > > +             ret = set_proto_ctx_sseu(fpriv, pc, args);
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_VM:
> > > > +             ret = set_proto_ctx_vm(fpriv, pc, args);
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_ENGINES:
> > > > +             ret = set_proto_ctx_engines(fpriv, pc, args);
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_PERSISTENCE:
> > > > +             if (args->size)
> > > > +                     ret = -EINVAL;
> > > > +             else if (args->value)
> > > > +                     __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > > > +             else
> > > > +                     __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > >
> > > I think we have a nice mess here. You created this
> > > proto_context_set_persistence helper, but don't use it here. Oversight?
> >
> > Yeah, I should use it.  Done.
> >
> > > Aside from the validation fun around persistence, but that's better
> > > discussed in another patch I think.
> > >
> > > > +             break;
> > > > +
> > > > +     case I915_CONTEXT_PARAM_NO_ZEROMAP:
> > > > +     case I915_CONTEXT_PARAM_BAN_PERIOD:
> > > > +     case I915_CONTEXT_PARAM_RINGSIZE:
> > > > +     default:
> > > > +             ret = -EINVAL;
> > > > +             break;
> > > > +     }
> > > > +
> > > > +     return ret;
> > > > +}
> > > > +
> > > >  static struct i915_address_space *
> > > >  context_get_vm_rcu(struct i915_gem_context *ctx)
> > > >  {
> > > > @@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> > > >       return err;
> > > >  }
> > > >
> > > > +static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
> > > > +                                          unsigned int num_engines,
> > > > +                                          struct i915_gem_proto_engine *pe)
> > > > +{
> > > > +     struct i915_gem_engines *e, *err;
> > > > +     unsigned int n;
> > > > +
> > > > +     e = alloc_engines(num_engines);
> > > > +     for (n = 0; n < num_engines; n++) {
> > > > +             struct intel_context *ce;
> > > > +             int ret;
> > > > +
> > > > +             switch (pe[n].type) {
> > > > +             case I915_GEM_ENGINE_TYPE_PHYSICAL:
> > > > +                     ce = intel_context_create(pe[n].engine);
> > > > +                     break;
> > > > +
> > > > +             case I915_GEM_ENGINE_TYPE_BALANCED:
> > > > +                     ce = intel_execlists_create_virtual(pe[n].siblings,
> > > > +                                                         pe[n].num_siblings);
> > > > +                     break;
> > > > +
> > > > +             case I915_GEM_ENGINE_TYPE_INVALID:
> > > > +             default:
> > > > +                     GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
> > > > +                     continue;
> > > > +             }
> > > > +
> > > > +             if (IS_ERR(ce)) {
> > > > +                     err = ERR_CAST(ce);
> > > > +                     goto free_engines;
> > > > +             }
> > > > +
> > > > +             e->engines[n] = ce;
> > > > +
> > > > +             ret = intel_context_set_gem(ce, ctx, pe->sseu);
> > > > +             if (ret) {
> > > > +                     err = ERR_PTR(ret);
> > > > +                     goto free_engines;
> > > > +             }
> > > > +     }
> > > > +     e->num_engines = num_engines;
> > > > +
> > > > +     return e;
> > > > +
> > > > +free_engines:
> > > > +     free_engines(e);
> > > > +     return err;
> > > > +}
> > > > +
> > > >  void i915_gem_context_release(struct kref *ref)
> > > >  {
> > > >       struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
> > > > @@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
> > > >  {
> > > >       struct i915_gem_context *ctx;
> > > >       struct i915_gem_engines *e;
> > > > -     struct intel_sseu null_sseu = {};
> > > >       int err;
> > > >       int i;
> > > >
> > > > @@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
> > > >       INIT_LIST_HEAD(&ctx->stale.engines);
> > > >
> > > >       mutex_init(&ctx->engines_mutex);
> > > > -     e = default_engines(ctx, null_sseu);
> > > > +     e = default_engines(ctx, pc->legacy_rcs_sseu);
> > > >       if (IS_ERR(e)) {
> > > >               err = PTR_ERR(e);
> > > >               goto err_free;
> > > > @@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
> > > >               mutex_unlock(&ctx->mutex);
> > > >       }
> > > >
> > > > +     if (pc->num_user_engines >= 0) {
> > > > +             struct i915_gem_engines *engines;
> > > > +
> > > > +             engines = user_engines(ctx, pc->num_user_engines,
> > > > +                                    pc->user_engines);
> > > > +             if (IS_ERR(engines)) {
> > > > +                     context_close(ctx);
> > > > +                     return ERR_CAST(engines);
> > > > +             }
> > > > +
> > > > +             mutex_lock(&ctx->engines_mutex);
> > > > +             i915_gem_context_set_user_engines(ctx);
> > > > +             engines = rcu_replace_pointer(ctx->engines, engines, 1);
> > > > +             mutex_unlock(&ctx->engines_mutex);
> > >
> > > More locking code to ditch I guess.
> >
> > Sure.  Is it safe to just drop it?  I guess it is?  I'm really shaky
> > around all the RCU requirements and things.
>
> Well the 1 in here should be replace with
> lockdep_is_held(&ctx->engines_mutex), but the engines_mutex also should
> go, so really can ditch the entire thing. Also no one can access our
> context, so we can't fail.
>
> Now if you do this naively without dropping the __rcu classifier for
> ctx->engines then static checkers will complain. So until that's done an
> rcu_assign_pointer should do.

This is all nuked by the last patch.  If it's all the same to you, I'd
rather leave the re-typed stupid boiler-plate here and delete it and
do it properly there.  That patch sets up an engine set once and uses
RCU_INIT_POINTER.

--Jason

> >
> > > > +
> > > > +             free_engines(engines);
> > >
> > > Also I guess we shouldn't first create the legacy engines for this case?
> >
> > That's fixed in the last patch.
>
> Yeah I noticed later on.
>
> >
> > > > +     }
> > > > +
> > > >       if (pc->single_timeline) {
> > > >               ret = drm_syncobj_create(&ctx->syncobj,
> > > >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> > > > @@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
> > > >  }
> > > >
> > > >  struct create_ext {
> > > > -     struct i915_gem_context *ctx;
> > > > +     struct i915_gem_proto_context *pc;
> > > >       struct drm_i915_file_private *fpriv;
> > > >  };
> > > >
> > > > @@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
> > > >       if (local.param.ctx_id)
> > > >               return -EINVAL;
> > > >
> > > > -     return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> > > > +     return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
> > > >  }
> > > >
> > > >  static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> > > > @@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > >  {
> > > >       struct drm_i915_private *i915 = to_i915(dev);
> > > >       struct drm_i915_gem_context_create_ext *args = data;
> > > > -     struct i915_gem_proto_context *pc;
> > > > +     struct i915_gem_context *ctx;
> > > >       struct create_ext ext_data;
> > > >       int ret;
> > > >       u32 id;
> > > > @@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > >               return -EIO;
> > > >       }
> > > >
> > > > -     pc = proto_context_create(i915, args->flags);
> > > > -     if (IS_ERR(pc))
> > > > -             return PTR_ERR(pc);
> > > > -
> > > > -     ext_data.ctx = i915_gem_create_context(i915, pc);
> > > > -     proto_context_close(pc);
> > > > -     if (IS_ERR(ext_data.ctx))
> > > > -             return PTR_ERR(ext_data.ctx);
> > > > +     ext_data.pc = proto_context_create(i915, args->flags);
> > > > +     if (IS_ERR(ext_data.pc))
> > > > +             return PTR_ERR(ext_data.pc);
> > > >
> > > >       if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
> > > >               ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
> > > >                                          create_extensions,
> > > >                                          ARRAY_SIZE(create_extensions),
> > > >                                          &ext_data);
> > > > -             if (ret)
> > > > -                     goto err_ctx;
> > > > +             if (ret) {
> > > > +                     proto_context_close(ext_data.pc);
> > > > +                     return ret;
> > > > +             }
> > > >       }
> > > >
> > > > -     ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
> > > > +     ctx = i915_gem_create_context(i915, ext_data.pc);
> > > > +     proto_context_close(ext_data.pc);
> > > > +     if (IS_ERR(ctx))
> > > > +             return PTR_ERR(ctx);
> > > > +
> > > > +     ret = gem_context_register(ctx, ext_data.fpriv, &id);
> > > >       if (ret < 0)
> > > >               goto err_ctx;
> > > >
> > > > @@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > >       return 0;
> > > >
> > > >  err_ctx:
> > > > -     context_close(ext_data.ctx);
> > > > +     context_close(ctx);
> > > >       return ret;
> > > >  }
> > > >
> > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > index 0bf337b6d89ac..2ac341f805c8f 100644
> > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > @@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
> > > >       const struct i915_gem_engines *engines;
> > > >  };
> > > >
> > > > +/**
> > > > + * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
> > > > + */
> > > > +enum i915_gem_engine_type {
> > > > +     /** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
> > > > +     I915_GEM_ENGINE_TYPE_INVALID = 0,
> > > > +
> > > > +     /** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
> > > > +     I915_GEM_ENGINE_TYPE_PHYSICAL,
> > > > +
> > > > +     /** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
> > > > +     I915_GEM_ENGINE_TYPE_BALANCED,
> > > > +};
> > > > +
> > > > +/**
> > > > + * struct i915_gem_proto_engine - prototype engine
> > > > + *
> > > > + * This struct describes an engine that a context may contain.  Engines
> > > > + * have three types:
> > > > + *
> > > > + *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
> > > > + *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
> > > > + *    use them by the user results in -EINVAL.  They are also useful during
> > > > + *    proto-context construction because the client may create invalid
> > > > + *    engines and then set them up later as bonded engines.
> > > > + *
> > > > + *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
> > > > + *    i915_gem_proto_engine::engine.
> > > > + *
> > > > + *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
> > > > + *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
> > > > + */
> > > > +struct i915_gem_proto_engine {
> > > > +     /** @type: Type of this engine */
> > > > +     enum i915_gem_engine_type type;
> > > > +
> > > > +     /** @engine: Engine, for physical */
> > > > +     struct intel_engine_cs *engine;
> > > > +
> > > > +     /** @num_siblings: Number of balanced siblings */
> > > > +     unsigned int num_siblings;
> > > > +
> > > > +     /** @siblings: Balanced siblings */
> > > > +     struct intel_engine_cs **siblings;
> > > > +
> > > > +     /** @sseu: Client-set SSEU parameters */
> > > > +     struct intel_sseu sseu;
> > > > +};
> > > > +
> > > >  /**
> > > >   * struct i915_gem_proto_context - prototype context
> > > >   *
> > > > @@ -84,6 +133,15 @@ struct i915_gem_proto_context {
> > > >       /** @sched: See i915_gem_context::sched */
> > > >       struct i915_sched_attr sched;
> > > >
> > > > +     /** @num_user_engines: Number of user-specified engines or -1 */
> > > > +     int num_user_engines;
> > > > +
> > > > +     /** @user_engines: User-specified engines */
> > > > +     struct i915_gem_proto_engine *user_engines;
> > > > +
> > > > +     /** @sseu: Client-set SSEU parameters for the legacy RCS */
> > > > +     struct intel_sseu legacy_rcs_sseu;
> > > > +
> > > >       /** @single_timeline: See See i915_gem_context::syncobj */
> > > >       bool single_timeline;
> > > >  };
> > > > --
> > > > 2.31.1
> > >
> > > Man is this all nasty. Since I don't want to re-review the entire pile,
> > > assuming we figure out solutions to all the real issues I've raised (and
> > > not the snarky bikesheds) this is
> > >
> > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> >
> > Ok.  I'm leaving it off for now to remind myself to ensure that we
> > close on everything.  I'll add it once I've heard back from you on my
> > questions above.
>
> I think we're all good. Mostly :-/
> -Daniel
>
> >
> > --Jason
> >
> > > >
> > > > _______________________________________________
> > > > dri-devel mailing list
> > > > dri-devel@lists.freedesktop.org
> > > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> > >
> > > --
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > http://blog.ffwll.ch
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
  2021-05-17 17:04           ` [Intel-gfx] " Jason Ekstrand
@ 2021-05-17 18:44             ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-17 18:44 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: Intel GFX, Maling list - DRI developers

On Mon, May 17, 2021 at 7:05 PM Jason Ekstrand <jason@jlekstrand.net> wrote:
>
> On Mon, May 17, 2021 at 8:40 AM Daniel Vetter <daniel@ffwll.ch> wrote:
> >
> > On Fri, May 14, 2021 at 02:13:57PM -0500, Jason Ekstrand wrote:
> > > On Tue, May 4, 2021 at 3:33 PM Daniel Vetter <daniel@ffwll.ch> wrote:
> > > >
> > > > On Mon, May 03, 2021 at 10:57:40AM -0500, Jason Ekstrand wrote:
> > > > > This means that the proto-context needs to grow support for engine
> > > > > configuration information as well as setparam logic.  Fortunately, we'll
> > > > > be deleting a lot of setparam logic on the primary context shortly so it
> > > > > will hopefully balance out.
> > > > >
> > > > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > > > > ---
> > > > >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
> > > > >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
> > > > >  2 files changed, 587 insertions(+), 17 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > > index 6dd50d669c5b9..aa4edfbf7ed48 100644
> > > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > > @@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
> > > > >
> > > > >  static void proto_context_close(struct i915_gem_proto_context *pc)
> > > > >  {
> > > > > +     int i;
> > > > > +
> > > > >       if (pc->vm)
> > > > >               i915_vm_put(pc->vm);
> > > > > +     if (pc->user_engines) {
> > > > > +             for (i = 0; i < pc->num_user_engines; i++)
> > > > > +                     kfree(pc->user_engines[i].siblings);
> > > > > +             kfree(pc->user_engines);
> > > >
> > > >                 free_engines(&pc->user_engines);
> > > >
> > > > Maybe even stuff that if check into free_engines. Except I realized this
> > > > is proto engines here now :-(
> > > >
> > > > > +     }
> > > > >       kfree(pc);
> > > > >  }
> > > > >
> > > > > @@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > > > >       if (!pc)
> > > > >               return ERR_PTR(-ENOMEM);
> > > > >
> > > > > +     pc->num_user_engines = -1;
> > > > > +     pc->user_engines = NULL;
> > > > > +
> > > > >       if (HAS_FULL_PPGTT(i915)) {
> > > > >               struct i915_ppgtt *ppgtt;
> > > > >
> > > > > @@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > > > >       return err;
> > > > >  }
> > > > >
> > > > > +static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
> > > > > +                         struct i915_gem_proto_context *pc,
> > > > > +                         const struct drm_i915_gem_context_param *args)
> > > > > +{
> > > > > +     struct i915_address_space *vm;
> > > > > +
> > > > > +     if (args->size)
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     if (!pc->vm)
> > > > > +             return -ENODEV;
> > > > > +
> > > > > +     if (upper_32_bits(args->value))
> > > > > +             return -ENOENT;
> > > > > +
> > > > > +     rcu_read_lock();
> > > > > +     vm = xa_load(&fpriv->vm_xa, args->value);
> > > > > +     if (vm && !kref_get_unless_zero(&vm->ref))
> > > > > +             vm = NULL;
> > > > > +     rcu_read_unlock();
> > > >
> > > > vm lookup helpers would be nice I guess, but perhaps something that
> > > > vm_bind patches should do.
> > >
> > > I can add those.  I just don't know where to put it.  We don't have an
> > > i915_gem_vm.h.  Suggestions?
> >
> > gt/intel_gtt.h seems to be the header for i915_address_space stuff. Also
> > contains the i915_vma_ops but not i915_vma.
> >
> > It's a pretty good mess, but probably the best place for now for these :-/
>
> The one for contexts is in i915_drv.h so I put the VM one there too.
> Feel free to tell me to move it.  I don't care where it goes.

i915_drv.h is the og dumping ground and needs to die. Everything in
there needs to be moved out/split/whatever for better code
organization. If we have a place already that fits better (even if
maybe misnamed) it's better to put it there.

But also, the mess here is much larger unfortuantely :-/

> > >
> > > >
> > > > > +     if (!vm)
> > > > > +             return -ENOENT;
> > > > > +
> > > > > +     i915_vm_put(pc->vm);
> > > >
> > > > Ah I guess I've found why you went with "pc->vm is always set". *shrug*
> > > >
> > > > > +     pc->vm = vm;
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +struct set_proto_ctx_engines {
> > > > > +     struct drm_i915_private *i915;
> > > > > +     unsigned num_engines;
> > > > > +     struct i915_gem_proto_engine *engines;
> > > > > +};
> > > > > +
> > > > > +static int
> > > > > +set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
> > > > > +                           void *data)
> > > > > +{
> > > > > +     struct i915_context_engines_load_balance __user *ext =
> > > > > +             container_of_user(base, typeof(*ext), base);
> > > > > +     const struct set_proto_ctx_engines *set = data;
> > > > > +     struct drm_i915_private *i915 = set->i915;
> > > > > +     struct intel_engine_cs **siblings;
> > > > > +     u16 num_siblings, idx;
> > > > > +     unsigned int n;
> > > > > +     int err;
> > > > > +
> > > > > +     if (!HAS_EXECLISTS(i915))
> > > > > +             return -ENODEV;
> > > > > +
> > > > > +     if (intel_uc_uses_guc_submission(&i915->gt.uc))
> > > > > +             return -ENODEV; /* not implement yet */
> > > > > +
> > > > > +     if (get_user(idx, &ext->engine_index))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     if (idx >= set->num_engines) {
> > > > > +             drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> > > > > +                     idx, set->num_engines);
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     idx = array_index_nospec(idx, set->num_engines);
> > > > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
> > > > > +             drm_dbg(&i915->drm,
> > > > > +                     "Invalid placement[%d], already occupied\n", idx);
> > > > > +             return -EEXIST;
> > > > > +     }
> > > > > +
> > > > > +     if (get_user(num_siblings, &ext->num_siblings))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     err = check_user_mbz(&ext->flags);
> > > > > +     if (err)
> > > > > +             return err;
> > > > > +
> > > > > +     err = check_user_mbz(&ext->mbz64);
> > > > > +     if (err)
> > > > > +             return err;
> > > > > +
> > > > > +     if (num_siblings == 0)
> >
> > > >
> > > > You deleted the on-stack siblings micro-optimization.
> > > >
> > > > I'm shocked.
> > >
> > > Yup.  If balanced engine create overhead when balancing across a
> > > single engine ever becomes a bottleneck in some UMD, I'm happy to deal
> > > with it then.  And I intend to deal with it by banning whatever
> > > developer decided balancing across single engine was a good idea.
> >
> > I should have annotated this with /s
>
> I detected your sarcasm and returned it. :-P
>
> > > > > +
> > > > > +     siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);
> > > >
> > > > If you want to pay back your micro-opt budget: GFP_TEMPORARY.
> > > >
> > > > But then I realized much wiser heads than me removed this in 2017 from the
> > > > kernel! That commit is a rather interesting story btw, if you're bored:
> > > >
> > > > commit 0ee931c4e31a5efb134c76440405e9219f896e33
> > > > Author: Michal Hocko <mhocko@suse.com>
> > > > Date:   Wed Sep 13 16:28:29 2017 -0700
> > > >
> > > >     mm: treewide: remove GFP_TEMPORARY allocation flag
> > > >
> > > > > +     if (!siblings)
> > > > > +             return -ENOMEM;
> > > > > +
> > > > > +     for (n = 0; n < num_siblings; n++) {
> > > > > +             struct i915_engine_class_instance ci;
> > > > > +
> > > > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> > > > > +                     err = -EFAULT;
> > > > > +                     goto err_siblings;
> > > > > +             }
> > > > > +
> > > > > +             siblings[n] = intel_engine_lookup_user(i915,
> > > > > +                                                    ci.engine_class,
> > > > > +                                                    ci.engine_instance);
> > > >
> > > > intel_engine_user.c
> > > >
> > > > ...
> > > >
> > > > Maybe I should just stop looking.
> > >
> > > Don't think too hard.  It hurts.
> > >
> > > > > +             if (!siblings[n]) {
> > > > > +                     drm_dbg(&i915->drm,
> > > > > +                             "Invalid sibling[%d]: { class:%d, inst:%d }\n",
> > > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > > +                     err = -EINVAL;
> > > > > +                     goto err_siblings;
> > > > > +             }
> > > > > +     }
> > > > > +
> > > > > +     if (num_siblings == 1) {
> > > > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > > > +             set->engines[idx].engine = siblings[0];
> > > > > +             kfree(siblings);
> > > > > +     } else {
> > > > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
> > > > > +             set->engines[idx].num_siblings = num_siblings;
> > > > > +             set->engines[idx].siblings = siblings;
> > > > > +     }
> > > > > +
> > > > > +     return 0;
> > > > > +
> > > > > +err_siblings:
> > > > > +     kfree(siblings);
> > > > > +
> > > > > +     return err;
> > > > > +}
> > > > > +
> > > > > +static int
> > > > > +set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
> > > > > +{
> > > > > +     struct i915_context_engines_bond __user *ext =
> > > > > +             container_of_user(base, typeof(*ext), base);
> > > > > +     const struct set_proto_ctx_engines *set = data;
> > > > > +     struct drm_i915_private *i915 = set->i915;
> > > > > +     struct i915_engine_class_instance ci;
> > > > > +     struct intel_engine_cs *master;
> > > > > +     u16 idx, num_bonds;
> > > > > +     int err, n;
> > > > > +
> > > > > +     if (get_user(idx, &ext->virtual_index))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     if (idx >= set->num_engines) {
> > > > > +             drm_dbg(&i915->drm,
> > > > > +                     "Invalid index for virtual engine: %d >= %d\n",
> > > > > +                     idx, set->num_engines);
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     idx = array_index_nospec(idx, set->num_engines);
> > > > > +     if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
> > > > > +             drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
> > > > > +             drm_dbg(&i915->drm,
> > > > > +                     "Bonding with virtual engines not allowed\n");
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     err = check_user_mbz(&ext->flags);
> > > > > +     if (err)
> > > > > +             return err;
> > > > > +
> > > > > +     for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> > > > > +             err = check_user_mbz(&ext->mbz64[n]);
> > > > > +             if (err)
> > > > > +                     return err;
> > > > > +     }
> > > > > +
> > > > > +     if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     master = intel_engine_lookup_user(i915,
> > > > > +                                       ci.engine_class,
> > > > > +                                       ci.engine_instance);
> > > > > +     if (!master) {
> > > >
> > > > It's 100% orthogonal annoyance, but maybe we can start the "what's a good
> > > > name here" discussion.
> > > >
> > > > I'm thinking s/master/first/ and s/slave/subsequent/ that reflect how this
> > > > is actually used on the execbuf side. But then this entire bonded
> > > > extension is so disconnected from the actual use-case, maybe we should
> > > > just sun-set it before we bother.
> > >
> > > primary/secondary come to mind.  But, also, I'd rather do that as a
> > > separate patch since I was trying to make this mostly match.  Happy to
> > > up my i915 patch count with a rename follow-on, if you want.
> >
> > Yeah I think we can repaint that shed as part of merging the new parallel
> > submit support.
> >
> > > > Since we might need to keep the execlist backend implementation the
> > > > renaming might still be needed.
> > > >
> > > > > +             drm_dbg(&i915->drm,
> > > > > +                     "Unrecognised master engine: { class:%u, instance:%u }\n",
> > > > > +                     ci.engine_class, ci.engine_instance);
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     if (get_user(num_bonds, &ext->num_bonds))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     for (n = 0; n < num_bonds; n++) {
> > > > > +             struct intel_engine_cs *bond;
> > > > > +
> > > > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> > > > > +                     return -EFAULT;
> > > > > +
> > > > > +             bond = intel_engine_lookup_user(i915,
> > > > > +                                             ci.engine_class,
> > > > > +                                             ci.engine_instance);
> > > > > +             if (!bond) {
> > > > > +                     drm_dbg(&i915->drm,
> > > > > +                             "Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> > > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > > +                     return -EINVAL;
> > > > > +             }
> > > > > +     }
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
> > > > > +     [I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
> > > > > +     [I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
> > > > > +};
> > > > > +
> > > > > +static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
> > > > > +                              struct i915_gem_proto_context *pc,
> > > > > +                              const struct drm_i915_gem_context_param *args)
> > > > > +{
> > > > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > > > +     struct set_proto_ctx_engines set = { .i915 = i915 };
> > > > > +     struct i915_context_param_engines __user *user =
> > > > > +             u64_to_user_ptr(args->value);
> > > > > +     unsigned int n;
> > > > > +     u64 extensions;
> > > > > +     int err;
> > > > > +
> > > > > +     if (!args->size) {
> > > > > +             kfree(pc->user_engines);
> > > > > +             pc->num_user_engines = -1;
> > > >
> > > > Is this case actually used by actual userspace, or just more stuff igt
> > > > loved to do?
> > > >
> > > > If so more uapi to ditch, and check in an igt that it's rejected.
> > > >
> > > > Plus standard !args->size handling here with appropriate drm_debug line
> > > > and all that.
> > > >
> > > > > +             pc->user_engines = NULL;
> > > > > +             memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
> > > > > +             return 0;
> > > > > +     }
> > > > > +
> > > > > +     BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
> > > >
> > > > I frankly don't know what this is checking, but it also looks harmless.
> > >
> > > Yeah..... All I can see is that it lets us avoid doing a subtraction
> > > in the alignment check below.  Kind-of silly, IMO.
> >
> > I'm not seeing even that? Care to help the blind?
>
> The array length is calculated as (args->size - sizeof(*user)) /
> sizeof(*user->engines) which means that we really want (args->size -
> sizeof(*user)) to be divisible by sizeof(*user->engines).  However,
> instead of checking
>
> IS_ALIGNED(args->size - sizeof(*user), sizeof(*user->engines))
>
> we first check that sizeof(*user) is divisible by
> sizeof(*user->engines) with a static check and then just check the
> alignment of args->size.  I'm going to fix this mess.

Uh. Motion that I'm guilty of not having understood this magic at all,
and also yes pls, burn this down with fire. gcc will optimize out the
subtraction as long as everything is aligned, and since it's uapi we
know it's never going to change.

Also.

Why.



...

Just why.

> > > > > +     if (args->size < sizeof(*user) ||
> > > > > +         !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> > > > > +             drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> > > > > +                     args->size);
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> > > > > +     /* RING_MASK has no shift so we can use it directly here */
> > > > > +     if (set.num_engines > I915_EXEC_RING_MASK + 1)
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
> > > > > +     if (!set.engines)
> > > > > +             return -ENOMEM;
> > > > > +
> > > > > +     for (n = 0; n < set.num_engines; n++) {
> > > > > +             struct i915_engine_class_instance ci;
> > > > > +             struct intel_engine_cs *engine;
> > > > > +
> > > > > +             if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> > > > > +                     kfree(set.engines);
> > > > > +                     return -EFAULT;
> > > > > +             }
> > > > > +
> > > > > +             memset(&set.engines[n], 0, sizeof(set.engines[n]));
> > > > > +
> > > > > +             if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> > > > > +                 ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
> > > > > +                     continue;
> > > > > +
> > > > > +             engine = intel_engine_lookup_user(i915,
> > > > > +                                               ci.engine_class,
> > > > > +                                               ci.engine_instance);
> > > > > +             if (!engine) {
> > > > > +                     drm_dbg(&i915->drm,
> > > > > +                             "Invalid engine[%d]: { class:%d, instance:%d }\n",
> > > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > > +                     kfree(set.engines);
> > > > > +                     return -ENOENT;
> > > > > +             }
> > > > > +
> > > > > +             set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > > > +             set.engines[n].engine = engine;
> > > > > +     }
> > > > > +
> > > > > +     err = -EFAULT;
> > > > > +     if (!get_user(extensions, &user->extensions))
> > > > > +             err = i915_user_extensions(u64_to_user_ptr(extensions),
> > > > > +                                        set_proto_ctx_engines_extensions,
> > > > > +                                        ARRAY_SIZE(set_proto_ctx_engines_extensions),
> > > > > +                                        &set);
> > > > > +     if (err) {
> > > > > +             kfree(set.engines);
> > > > > +             return err;
> > > > > +     }
> > > > > +
> > > > > +     kfree(pc->user_engines);
> > > >
> > > > Both of these kfree potentially leak engines[].siblings. I think you need
> > > > to extract a proto_context_free_engines helper and use that 2x here and
> > > > once at the very top in proto_context_close().
> > >
> > > Good catch. Done.
> > >
> > > > > +     pc->num_user_engines = set.num_engines;
> > > > > +     pc->user_engines = set.engines;
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
> > > > > +                           struct i915_gem_proto_context *pc,
> > > > > +                           struct drm_i915_gem_context_param *args)
> > > > > +{
> > > > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > > > +     struct drm_i915_gem_context_param_sseu user_sseu;
> > > > > +     struct intel_sseu *sseu;
> > > > > +     int ret;
> > > > > +
> > > > > +     if (args->size < sizeof(user_sseu))
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     if (!IS_GEN(i915, 11))
> > > > > +             return -ENODEV;
> > > > > +
> > > > > +     if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
> > > > > +                        sizeof(user_sseu)))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     if (user_sseu.rsvd)
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     if (pc->num_user_engines >= 0) {
> > > > > +             int idx = user_sseu.engine.engine_instance;
> > > > > +             struct i915_gem_proto_engine *pe;
> > > > > +
> > > > > +             if (idx >= pc->num_user_engines)
> > > > > +                     return -EINVAL;
> > > > > +
> > > > > +             pe = &pc->user_engines[idx];
> > > > > +
> > > > > +             /* Only render engine supports RPCS configuration. */
> > > > > +             if (pe->engine->class != RENDER_CLASS)
> > > > > +                     return -EINVAL;
> > > > > +
> > > > > +             sseu = &pe->sseu;
> > > > > +     } else {
> > > > > +             /* Only render engine supports RPCS configuration. */
> > > > > +             if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
> > > > > +                     return -EINVAL;
> > > > > +
> > > > > +             /* There is only one render engine */
> > > > > +             if (user_sseu.engine.engine_instance != 0)
> > > > > +                     return -EINVAL;
> > > > > +
> > > > > +             sseu = &pc->legacy_rcs_sseu;
> > > > > +     }
> > > >
> > > > I think this faithfully rebuilds the convoluted and I think largely
> > > > accidental semantics of SSEU for all combinations of ordering against
> > > > set_engines.
> > > >
> > > > Maybe add a commit message note about this particular kind of fun here. I
> > > > don't think a code comment is warranted since I don't think I've seen a
> > > > userspace rely on how sseu interacts with set_engines
> > >
> > > Done.
> > >
> > > > > +
> > > > > +     ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
> > > > > +     if (ret)
> > > > > +             return ret;
> > > > > +
> > > > > +     args->size = sizeof(user_sseu);
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
> > > > > +                            struct i915_gem_proto_context *pc,
> > > > > +                            struct drm_i915_gem_context_param *args)
> > > > > +{
> > > > > +     int ret = 0;
> > > > > +
> > > > > +     switch (args->param) {
> > > > > +     case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
> > > > > +             if (args->size)
> > > > > +                     ret = -EINVAL;
> > > > > +             else if (args->value)
> > > > > +                     __set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > > > > +             else
> > > > > +                     __clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > > >
> > > > Open code please and double check I caught them all ...
> > >
> > > As I commented the first time around, __set/clear_bit are static
> > > inlines that unroll to "*field |= (1 << bit)" or "*field &= ~(1 <<
> > > bit)" as appropriate.  The non-__ versions do atomics.  I could
> > > hand-roll them but that seems error-prone and it gains us nothing.
> >
> > They do more, they treat this as a potential array of unsigned long as a
> > bitfield of unlimted size. This comes from the cpuset support afaiu our
> > history here, and years ago (decades by now?) linux started supporting
> > more than 64 cpus cores. Our flags are definitely not unlimted and fit in
> > an unsigned, so we're dropping some compiler checking here.
> >
> > Also it's not that bad really:
> >
> >         if (args->value)
> >                 pc->user_flags |= BIT(UCONTEXT_NO_ERROR_CAPTURE);
> >         else
> >                 pc->user_flags &= ~BIT(UCONTEXT_NO_ERROR_CAPTURE);
> >
> > Fairly idiomatic construct. Final argument here is that __func() generally
> > means "beware, check carefuly what's going on here", and nothing funny is
> > going on here at all, so it's a bit a negative trap :-)
> >
> > Anyway git grep shows you're not the first (even outside of drm/i915).
> > Some spot checking with grep shows that bitflag use of __set_bit is about
> > a third of overall use:
> >
> > $ git grep '__set_bit.*)' | wc -l
> > 1761
> >
> > $ git grep '__set_bit.*,\s*&.*)' | wc -l
> > 479
> >
> > So whatever you feel like.
>
> Your shed, your colors.  I just wanted a reason and to know you
> weren't missing something.

Well it's a 30% shed or so, I think it really doesn't matter that much.

> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_BANNABLE:
> > > > > +             if (args->size)
> > > > > +                     ret = -EINVAL;
> > > > > +             else if (!capable(CAP_SYS_ADMIN) && !args->value)
> > > > > +                     ret = -EPERM;
> > > > > +             else if (args->value)
> > > > > +                     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > > > +             else
> > > > > +                     __clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_RECOVERABLE:
> > > > > +             if (args->size)
> > > > > +                     ret = -EINVAL;
> > > > > +             else if (args->value)
> > > > > +                     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > > > +             else
> > > > > +                     __clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_PRIORITY:
> > > > > +             ret = validate_priority(fpriv->dev_priv, args);
> > > > > +             if (!ret)
> > > > > +                     pc->sched.priority = args->value;
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_SSEU:
> > > > > +             ret = set_proto_ctx_sseu(fpriv, pc, args);
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_VM:
> > > > > +             ret = set_proto_ctx_vm(fpriv, pc, args);
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_ENGINES:
> > > > > +             ret = set_proto_ctx_engines(fpriv, pc, args);
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_PERSISTENCE:
> > > > > +             if (args->size)
> > > > > +                     ret = -EINVAL;
> > > > > +             else if (args->value)
> > > > > +                     __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > > > > +             else
> > > > > +                     __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > > >
> > > > I think we have a nice mess here. You created this
> > > > proto_context_set_persistence helper, but don't use it here. Oversight?
> > >
> > > Yeah, I should use it.  Done.
> > >
> > > > Aside from the validation fun around persistence, but that's better
> > > > discussed in another patch I think.
> > > >
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_NO_ZEROMAP:
> > > > > +     case I915_CONTEXT_PARAM_BAN_PERIOD:
> > > > > +     case I915_CONTEXT_PARAM_RINGSIZE:
> > > > > +     default:
> > > > > +             ret = -EINVAL;
> > > > > +             break;
> > > > > +     }
> > > > > +
> > > > > +     return ret;
> > > > > +}
> > > > > +
> > > > >  static struct i915_address_space *
> > > > >  context_get_vm_rcu(struct i915_gem_context *ctx)
> > > > >  {
> > > > > @@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> > > > >       return err;
> > > > >  }
> > > > >
> > > > > +static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
> > > > > +                                          unsigned int num_engines,
> > > > > +                                          struct i915_gem_proto_engine *pe)
> > > > > +{
> > > > > +     struct i915_gem_engines *e, *err;
> > > > > +     unsigned int n;
> > > > > +
> > > > > +     e = alloc_engines(num_engines);
> > > > > +     for (n = 0; n < num_engines; n++) {
> > > > > +             struct intel_context *ce;
> > > > > +             int ret;
> > > > > +
> > > > > +             switch (pe[n].type) {
> > > > > +             case I915_GEM_ENGINE_TYPE_PHYSICAL:
> > > > > +                     ce = intel_context_create(pe[n].engine);
> > > > > +                     break;
> > > > > +
> > > > > +             case I915_GEM_ENGINE_TYPE_BALANCED:
> > > > > +                     ce = intel_execlists_create_virtual(pe[n].siblings,
> > > > > +                                                         pe[n].num_siblings);
> > > > > +                     break;
> > > > > +
> > > > > +             case I915_GEM_ENGINE_TYPE_INVALID:
> > > > > +             default:
> > > > > +                     GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
> > > > > +                     continue;
> > > > > +             }
> > > > > +
> > > > > +             if (IS_ERR(ce)) {
> > > > > +                     err = ERR_CAST(ce);
> > > > > +                     goto free_engines;
> > > > > +             }
> > > > > +
> > > > > +             e->engines[n] = ce;
> > > > > +
> > > > > +             ret = intel_context_set_gem(ce, ctx, pe->sseu);
> > > > > +             if (ret) {
> > > > > +                     err = ERR_PTR(ret);
> > > > > +                     goto free_engines;
> > > > > +             }
> > > > > +     }
> > > > > +     e->num_engines = num_engines;
> > > > > +
> > > > > +     return e;
> > > > > +
> > > > > +free_engines:
> > > > > +     free_engines(e);
> > > > > +     return err;
> > > > > +}
> > > > > +
> > > > >  void i915_gem_context_release(struct kref *ref)
> > > > >  {
> > > > >       struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
> > > > > @@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
> > > > >  {
> > > > >       struct i915_gem_context *ctx;
> > > > >       struct i915_gem_engines *e;
> > > > > -     struct intel_sseu null_sseu = {};
> > > > >       int err;
> > > > >       int i;
> > > > >
> > > > > @@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
> > > > >       INIT_LIST_HEAD(&ctx->stale.engines);
> > > > >
> > > > >       mutex_init(&ctx->engines_mutex);
> > > > > -     e = default_engines(ctx, null_sseu);
> > > > > +     e = default_engines(ctx, pc->legacy_rcs_sseu);
> > > > >       if (IS_ERR(e)) {
> > > > >               err = PTR_ERR(e);
> > > > >               goto err_free;
> > > > > @@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
> > > > >               mutex_unlock(&ctx->mutex);
> > > > >       }
> > > > >
> > > > > +     if (pc->num_user_engines >= 0) {
> > > > > +             struct i915_gem_engines *engines;
> > > > > +
> > > > > +             engines = user_engines(ctx, pc->num_user_engines,
> > > > > +                                    pc->user_engines);
> > > > > +             if (IS_ERR(engines)) {
> > > > > +                     context_close(ctx);
> > > > > +                     return ERR_CAST(engines);
> > > > > +             }
> > > > > +
> > > > > +             mutex_lock(&ctx->engines_mutex);
> > > > > +             i915_gem_context_set_user_engines(ctx);
> > > > > +             engines = rcu_replace_pointer(ctx->engines, engines, 1);
> > > > > +             mutex_unlock(&ctx->engines_mutex);
> > > >
> > > > More locking code to ditch I guess.
> > >
> > > Sure.  Is it safe to just drop it?  I guess it is?  I'm really shaky
> > > around all the RCU requirements and things.
> >
> > Well the 1 in here should be replace with
> > lockdep_is_held(&ctx->engines_mutex), but the engines_mutex also should
> > go, so really can ditch the entire thing. Also no one can access our
> > context, so we can't fail.
> >
> > Now if you do this naively without dropping the __rcu classifier for
> > ctx->engines then static checkers will complain. So until that's done an
> > rcu_assign_pointer should do.
>
> This is all nuked by the last patch.  If it's all the same to you, I'd
> rather leave the re-typed stupid boiler-plate here and delete it and
> do it properly there.  That patch sets up an engine set once and uses
> RCU_INIT_POINTER.

Yeah I think it's all fine if it's clean in the end. I think we
already maxed out out how to transition in reasonable patches to where
we want to be, and there's definitely no optimal path.

I think a git branch for me to pull for next round would be great, so
I can give the final result a good once-over for checking. Without
having to fiddle with .mbox tooling :-)

Cheers, Daniel

> --Jason
>
> > >
> > > > > +
> > > > > +             free_engines(engines);
> > > >
> > > > Also I guess we shouldn't first create the legacy engines for this case?
> > >
> > > That's fixed in the last patch.
> >
> > Yeah I noticed later on.
> >
> > >
> > > > > +     }
> > > > > +
> > > > >       if (pc->single_timeline) {
> > > > >               ret = drm_syncobj_create(&ctx->syncobj,
> > > > >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> > > > > @@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
> > > > >  }
> > > > >
> > > > >  struct create_ext {
> > > > > -     struct i915_gem_context *ctx;
> > > > > +     struct i915_gem_proto_context *pc;
> > > > >       struct drm_i915_file_private *fpriv;
> > > > >  };
> > > > >
> > > > > @@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
> > > > >       if (local.param.ctx_id)
> > > > >               return -EINVAL;
> > > > >
> > > > > -     return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> > > > > +     return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
> > > > >  }
> > > > >
> > > > >  static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> > > > > @@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > > >  {
> > > > >       struct drm_i915_private *i915 = to_i915(dev);
> > > > >       struct drm_i915_gem_context_create_ext *args = data;
> > > > > -     struct i915_gem_proto_context *pc;
> > > > > +     struct i915_gem_context *ctx;
> > > > >       struct create_ext ext_data;
> > > > >       int ret;
> > > > >       u32 id;
> > > > > @@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > > >               return -EIO;
> > > > >       }
> > > > >
> > > > > -     pc = proto_context_create(i915, args->flags);
> > > > > -     if (IS_ERR(pc))
> > > > > -             return PTR_ERR(pc);
> > > > > -
> > > > > -     ext_data.ctx = i915_gem_create_context(i915, pc);
> > > > > -     proto_context_close(pc);
> > > > > -     if (IS_ERR(ext_data.ctx))
> > > > > -             return PTR_ERR(ext_data.ctx);
> > > > > +     ext_data.pc = proto_context_create(i915, args->flags);
> > > > > +     if (IS_ERR(ext_data.pc))
> > > > > +             return PTR_ERR(ext_data.pc);
> > > > >
> > > > >       if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
> > > > >               ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
> > > > >                                          create_extensions,
> > > > >                                          ARRAY_SIZE(create_extensions),
> > > > >                                          &ext_data);
> > > > > -             if (ret)
> > > > > -                     goto err_ctx;
> > > > > +             if (ret) {
> > > > > +                     proto_context_close(ext_data.pc);
> > > > > +                     return ret;
> > > > > +             }
> > > > >       }
> > > > >
> > > > > -     ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
> > > > > +     ctx = i915_gem_create_context(i915, ext_data.pc);
> > > > > +     proto_context_close(ext_data.pc);
> > > > > +     if (IS_ERR(ctx))
> > > > > +             return PTR_ERR(ctx);
> > > > > +
> > > > > +     ret = gem_context_register(ctx, ext_data.fpriv, &id);
> > > > >       if (ret < 0)
> > > > >               goto err_ctx;
> > > > >
> > > > > @@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > > >       return 0;
> > > > >
> > > > >  err_ctx:
> > > > > -     context_close(ext_data.ctx);
> > > > > +     context_close(ctx);
> > > > >       return ret;
> > > > >  }
> > > > >
> > > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > > index 0bf337b6d89ac..2ac341f805c8f 100644
> > > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > > @@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
> > > > >       const struct i915_gem_engines *engines;
> > > > >  };
> > > > >
> > > > > +/**
> > > > > + * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
> > > > > + */
> > > > > +enum i915_gem_engine_type {
> > > > > +     /** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
> > > > > +     I915_GEM_ENGINE_TYPE_INVALID = 0,
> > > > > +
> > > > > +     /** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
> > > > > +     I915_GEM_ENGINE_TYPE_PHYSICAL,
> > > > > +
> > > > > +     /** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
> > > > > +     I915_GEM_ENGINE_TYPE_BALANCED,
> > > > > +};
> > > > > +
> > > > > +/**
> > > > > + * struct i915_gem_proto_engine - prototype engine
> > > > > + *
> > > > > + * This struct describes an engine that a context may contain.  Engines
> > > > > + * have three types:
> > > > > + *
> > > > > + *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
> > > > > + *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
> > > > > + *    use them by the user results in -EINVAL.  They are also useful during
> > > > > + *    proto-context construction because the client may create invalid
> > > > > + *    engines and then set them up later as bonded engines.
> > > > > + *
> > > > > + *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
> > > > > + *    i915_gem_proto_engine::engine.
> > > > > + *
> > > > > + *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
> > > > > + *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
> > > > > + */
> > > > > +struct i915_gem_proto_engine {
> > > > > +     /** @type: Type of this engine */
> > > > > +     enum i915_gem_engine_type type;
> > > > > +
> > > > > +     /** @engine: Engine, for physical */
> > > > > +     struct intel_engine_cs *engine;
> > > > > +
> > > > > +     /** @num_siblings: Number of balanced siblings */
> > > > > +     unsigned int num_siblings;
> > > > > +
> > > > > +     /** @siblings: Balanced siblings */
> > > > > +     struct intel_engine_cs **siblings;
> > > > > +
> > > > > +     /** @sseu: Client-set SSEU parameters */
> > > > > +     struct intel_sseu sseu;
> > > > > +};
> > > > > +
> > > > >  /**
> > > > >   * struct i915_gem_proto_context - prototype context
> > > > >   *
> > > > > @@ -84,6 +133,15 @@ struct i915_gem_proto_context {
> > > > >       /** @sched: See i915_gem_context::sched */
> > > > >       struct i915_sched_attr sched;
> > > > >
> > > > > +     /** @num_user_engines: Number of user-specified engines or -1 */
> > > > > +     int num_user_engines;
> > > > > +
> > > > > +     /** @user_engines: User-specified engines */
> > > > > +     struct i915_gem_proto_engine *user_engines;
> > > > > +
> > > > > +     /** @sseu: Client-set SSEU parameters for the legacy RCS */
> > > > > +     struct intel_sseu legacy_rcs_sseu;
> > > > > +
> > > > >       /** @single_timeline: See See i915_gem_context::syncobj */
> > > > >       bool single_timeline;
> > > > >  };
> > > > > --
> > > > > 2.31.1
> > > >
> > > > Man is this all nasty. Since I don't want to re-review the entire pile,
> > > > assuming we figure out solutions to all the real issues I've raised (and
> > > > not the snarky bikesheds) this is
> > > >
> > > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > >
> > > Ok.  I'm leaving it off for now to remind myself to ensure that we
> > > close on everything.  I'll add it once I've heard back from you on my
> > > questions above.
> >
> > I think we're all good. Mostly :-/
> > -Daniel
> >
> > >
> > > --Jason
> > >
> > > > >
> > > > > _______________________________________________
> > > > > dri-devel mailing list
> > > > > dri-devel@lists.freedesktop.org
> > > > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> > > >
> > > > --
> > > > Daniel Vetter
> > > > Software Engineer, Intel Corporation
> > > > http://blog.ffwll.ch
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
@ 2021-05-17 18:44             ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-05-17 18:44 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: Intel GFX, Maling list - DRI developers

On Mon, May 17, 2021 at 7:05 PM Jason Ekstrand <jason@jlekstrand.net> wrote:
>
> On Mon, May 17, 2021 at 8:40 AM Daniel Vetter <daniel@ffwll.ch> wrote:
> >
> > On Fri, May 14, 2021 at 02:13:57PM -0500, Jason Ekstrand wrote:
> > > On Tue, May 4, 2021 at 3:33 PM Daniel Vetter <daniel@ffwll.ch> wrote:
> > > >
> > > > On Mon, May 03, 2021 at 10:57:40AM -0500, Jason Ekstrand wrote:
> > > > > This means that the proto-context needs to grow support for engine
> > > > > configuration information as well as setparam logic.  Fortunately, we'll
> > > > > be deleting a lot of setparam logic on the primary context shortly so it
> > > > > will hopefully balance out.
> > > > >
> > > > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> > > > > ---
> > > > >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 546 +++++++++++++++++-
> > > > >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  58 ++
> > > > >  2 files changed, 587 insertions(+), 17 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > > index 6dd50d669c5b9..aa4edfbf7ed48 100644
> > > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > > > @@ -193,8 +193,15 @@ static int validate_priority(struct drm_i915_private *i915,
> > > > >
> > > > >  static void proto_context_close(struct i915_gem_proto_context *pc)
> > > > >  {
> > > > > +     int i;
> > > > > +
> > > > >       if (pc->vm)
> > > > >               i915_vm_put(pc->vm);
> > > > > +     if (pc->user_engines) {
> > > > > +             for (i = 0; i < pc->num_user_engines; i++)
> > > > > +                     kfree(pc->user_engines[i].siblings);
> > > > > +             kfree(pc->user_engines);
> > > >
> > > >                 free_engines(&pc->user_engines);
> > > >
> > > > Maybe even stuff that if check into free_engines. Except I realized this
> > > > is proto engines here now :-(
> > > >
> > > > > +     }
> > > > >       kfree(pc);
> > > > >  }
> > > > >
> > > > > @@ -248,6 +255,9 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > > > >       if (!pc)
> > > > >               return ERR_PTR(-ENOMEM);
> > > > >
> > > > > +     pc->num_user_engines = -1;
> > > > > +     pc->user_engines = NULL;
> > > > > +
> > > > >       if (HAS_FULL_PPGTT(i915)) {
> > > > >               struct i915_ppgtt *ppgtt;
> > > > >
> > > > > @@ -282,6 +292,439 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > > > >       return err;
> > > > >  }
> > > > >
> > > > > +static int set_proto_ctx_vm(struct drm_i915_file_private *fpriv,
> > > > > +                         struct i915_gem_proto_context *pc,
> > > > > +                         const struct drm_i915_gem_context_param *args)
> > > > > +{
> > > > > +     struct i915_address_space *vm;
> > > > > +
> > > > > +     if (args->size)
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     if (!pc->vm)
> > > > > +             return -ENODEV;
> > > > > +
> > > > > +     if (upper_32_bits(args->value))
> > > > > +             return -ENOENT;
> > > > > +
> > > > > +     rcu_read_lock();
> > > > > +     vm = xa_load(&fpriv->vm_xa, args->value);
> > > > > +     if (vm && !kref_get_unless_zero(&vm->ref))
> > > > > +             vm = NULL;
> > > > > +     rcu_read_unlock();
> > > >
> > > > vm lookup helpers would be nice I guess, but perhaps something that
> > > > vm_bind patches should do.
> > >
> > > I can add those.  I just don't know where to put it.  We don't have an
> > > i915_gem_vm.h.  Suggestions?
> >
> > gt/intel_gtt.h seems to be the header for i915_address_space stuff. Also
> > contains the i915_vma_ops but not i915_vma.
> >
> > It's a pretty good mess, but probably the best place for now for these :-/
>
> The one for contexts is in i915_drv.h so I put the VM one there too.
> Feel free to tell me to move it.  I don't care where it goes.

i915_drv.h is the og dumping ground and needs to die. Everything in
there needs to be moved out/split/whatever for better code
organization. If we have a place already that fits better (even if
maybe misnamed) it's better to put it there.

But also, the mess here is much larger unfortuantely :-/

> > >
> > > >
> > > > > +     if (!vm)
> > > > > +             return -ENOENT;
> > > > > +
> > > > > +     i915_vm_put(pc->vm);
> > > >
> > > > Ah I guess I've found why you went with "pc->vm is always set". *shrug*
> > > >
> > > > > +     pc->vm = vm;
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +struct set_proto_ctx_engines {
> > > > > +     struct drm_i915_private *i915;
> > > > > +     unsigned num_engines;
> > > > > +     struct i915_gem_proto_engine *engines;
> > > > > +};
> > > > > +
> > > > > +static int
> > > > > +set_proto_ctx_engines_balance(struct i915_user_extension __user *base,
> > > > > +                           void *data)
> > > > > +{
> > > > > +     struct i915_context_engines_load_balance __user *ext =
> > > > > +             container_of_user(base, typeof(*ext), base);
> > > > > +     const struct set_proto_ctx_engines *set = data;
> > > > > +     struct drm_i915_private *i915 = set->i915;
> > > > > +     struct intel_engine_cs **siblings;
> > > > > +     u16 num_siblings, idx;
> > > > > +     unsigned int n;
> > > > > +     int err;
> > > > > +
> > > > > +     if (!HAS_EXECLISTS(i915))
> > > > > +             return -ENODEV;
> > > > > +
> > > > > +     if (intel_uc_uses_guc_submission(&i915->gt.uc))
> > > > > +             return -ENODEV; /* not implement yet */
> > > > > +
> > > > > +     if (get_user(idx, &ext->engine_index))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     if (idx >= set->num_engines) {
> > > > > +             drm_dbg(&i915->drm, "Invalid placement value, %d >= %d\n",
> > > > > +                     idx, set->num_engines);
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     idx = array_index_nospec(idx, set->num_engines);
> > > > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_INVALID) {
> > > > > +             drm_dbg(&i915->drm,
> > > > > +                     "Invalid placement[%d], already occupied\n", idx);
> > > > > +             return -EEXIST;
> > > > > +     }
> > > > > +
> > > > > +     if (get_user(num_siblings, &ext->num_siblings))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     err = check_user_mbz(&ext->flags);
> > > > > +     if (err)
> > > > > +             return err;
> > > > > +
> > > > > +     err = check_user_mbz(&ext->mbz64);
> > > > > +     if (err)
> > > > > +             return err;
> > > > > +
> > > > > +     if (num_siblings == 0)
> >
> > > >
> > > > You deleted the on-stack siblings micro-optimization.
> > > >
> > > > I'm shocked.
> > >
> > > Yup.  If balanced engine create overhead when balancing across a
> > > single engine ever becomes a bottleneck in some UMD, I'm happy to deal
> > > with it then.  And I intend to deal with it by banning whatever
> > > developer decided balancing across single engine was a good idea.
> >
> > I should have annotated this with /s
>
> I detected your sarcasm and returned it. :-P
>
> > > > > +
> > > > > +     siblings = kmalloc_array(num_siblings, sizeof(*siblings), GFP_KERNEL);
> > > >
> > > > If you want to pay back your micro-opt budget: GFP_TEMPORARY.
> > > >
> > > > But then I realized much wiser heads than me removed this in 2017 from the
> > > > kernel! That commit is a rather interesting story btw, if you're bored:
> > > >
> > > > commit 0ee931c4e31a5efb134c76440405e9219f896e33
> > > > Author: Michal Hocko <mhocko@suse.com>
> > > > Date:   Wed Sep 13 16:28:29 2017 -0700
> > > >
> > > >     mm: treewide: remove GFP_TEMPORARY allocation flag
> > > >
> > > > > +     if (!siblings)
> > > > > +             return -ENOMEM;
> > > > > +
> > > > > +     for (n = 0; n < num_siblings; n++) {
> > > > > +             struct i915_engine_class_instance ci;
> > > > > +
> > > > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci))) {
> > > > > +                     err = -EFAULT;
> > > > > +                     goto err_siblings;
> > > > > +             }
> > > > > +
> > > > > +             siblings[n] = intel_engine_lookup_user(i915,
> > > > > +                                                    ci.engine_class,
> > > > > +                                                    ci.engine_instance);
> > > >
> > > > intel_engine_user.c
> > > >
> > > > ...
> > > >
> > > > Maybe I should just stop looking.
> > >
> > > Don't think too hard.  It hurts.
> > >
> > > > > +             if (!siblings[n]) {
> > > > > +                     drm_dbg(&i915->drm,
> > > > > +                             "Invalid sibling[%d]: { class:%d, inst:%d }\n",
> > > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > > +                     err = -EINVAL;
> > > > > +                     goto err_siblings;
> > > > > +             }
> > > > > +     }
> > > > > +
> > > > > +     if (num_siblings == 1) {
> > > > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > > > +             set->engines[idx].engine = siblings[0];
> > > > > +             kfree(siblings);
> > > > > +     } else {
> > > > > +             set->engines[idx].type = I915_GEM_ENGINE_TYPE_BALANCED;
> > > > > +             set->engines[idx].num_siblings = num_siblings;
> > > > > +             set->engines[idx].siblings = siblings;
> > > > > +     }
> > > > > +
> > > > > +     return 0;
> > > > > +
> > > > > +err_siblings:
> > > > > +     kfree(siblings);
> > > > > +
> > > > > +     return err;
> > > > > +}
> > > > > +
> > > > > +static int
> > > > > +set_proto_ctx_engines_bond(struct i915_user_extension __user *base, void *data)
> > > > > +{
> > > > > +     struct i915_context_engines_bond __user *ext =
> > > > > +             container_of_user(base, typeof(*ext), base);
> > > > > +     const struct set_proto_ctx_engines *set = data;
> > > > > +     struct drm_i915_private *i915 = set->i915;
> > > > > +     struct i915_engine_class_instance ci;
> > > > > +     struct intel_engine_cs *master;
> > > > > +     u16 idx, num_bonds;
> > > > > +     int err, n;
> > > > > +
> > > > > +     if (get_user(idx, &ext->virtual_index))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     if (idx >= set->num_engines) {
> > > > > +             drm_dbg(&i915->drm,
> > > > > +                     "Invalid index for virtual engine: %d >= %d\n",
> > > > > +                     idx, set->num_engines);
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     idx = array_index_nospec(idx, set->num_engines);
> > > > > +     if (set->engines[idx].type == I915_GEM_ENGINE_TYPE_INVALID) {
> > > > > +             drm_dbg(&i915->drm, "Invalid engine at %d\n", idx);
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     if (set->engines[idx].type != I915_GEM_ENGINE_TYPE_PHYSICAL) {
> > > > > +             drm_dbg(&i915->drm,
> > > > > +                     "Bonding with virtual engines not allowed\n");
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     err = check_user_mbz(&ext->flags);
> > > > > +     if (err)
> > > > > +             return err;
> > > > > +
> > > > > +     for (n = 0; n < ARRAY_SIZE(ext->mbz64); n++) {
> > > > > +             err = check_user_mbz(&ext->mbz64[n]);
> > > > > +             if (err)
> > > > > +                     return err;
> > > > > +     }
> > > > > +
> > > > > +     if (copy_from_user(&ci, &ext->master, sizeof(ci)))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     master = intel_engine_lookup_user(i915,
> > > > > +                                       ci.engine_class,
> > > > > +                                       ci.engine_instance);
> > > > > +     if (!master) {
> > > >
> > > > It's 100% orthogonal annoyance, but maybe we can start the "what's a good
> > > > name here" discussion.
> > > >
> > > > I'm thinking s/master/first/ and s/slave/subsequent/ that reflect how this
> > > > is actually used on the execbuf side. But then this entire bonded
> > > > extension is so disconnected from the actual use-case, maybe we should
> > > > just sun-set it before we bother.
> > >
> > > primary/secondary come to mind.  But, also, I'd rather do that as a
> > > separate patch since I was trying to make this mostly match.  Happy to
> > > up my i915 patch count with a rename follow-on, if you want.
> >
> > Yeah I think we can repaint that shed as part of merging the new parallel
> > submit support.
> >
> > > > Since we might need to keep the execlist backend implementation the
> > > > renaming might still be needed.
> > > >
> > > > > +             drm_dbg(&i915->drm,
> > > > > +                     "Unrecognised master engine: { class:%u, instance:%u }\n",
> > > > > +                     ci.engine_class, ci.engine_instance);
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     if (get_user(num_bonds, &ext->num_bonds))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     for (n = 0; n < num_bonds; n++) {
> > > > > +             struct intel_engine_cs *bond;
> > > > > +
> > > > > +             if (copy_from_user(&ci, &ext->engines[n], sizeof(ci)))
> > > > > +                     return -EFAULT;
> > > > > +
> > > > > +             bond = intel_engine_lookup_user(i915,
> > > > > +                                             ci.engine_class,
> > > > > +                                             ci.engine_instance);
> > > > > +             if (!bond) {
> > > > > +                     drm_dbg(&i915->drm,
> > > > > +                             "Unrecognised engine[%d] for bonding: { class:%d, instance: %d }\n",
> > > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > > +                     return -EINVAL;
> > > > > +             }
> > > > > +     }
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +static const i915_user_extension_fn set_proto_ctx_engines_extensions[] = {
> > > > > +     [I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE] = set_proto_ctx_engines_balance,
> > > > > +     [I915_CONTEXT_ENGINES_EXT_BOND] = set_proto_ctx_engines_bond,
> > > > > +};
> > > > > +
> > > > > +static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
> > > > > +                              struct i915_gem_proto_context *pc,
> > > > > +                              const struct drm_i915_gem_context_param *args)
> > > > > +{
> > > > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > > > +     struct set_proto_ctx_engines set = { .i915 = i915 };
> > > > > +     struct i915_context_param_engines __user *user =
> > > > > +             u64_to_user_ptr(args->value);
> > > > > +     unsigned int n;
> > > > > +     u64 extensions;
> > > > > +     int err;
> > > > > +
> > > > > +     if (!args->size) {
> > > > > +             kfree(pc->user_engines);
> > > > > +             pc->num_user_engines = -1;
> > > >
> > > > Is this case actually used by actual userspace, or just more stuff igt
> > > > loved to do?
> > > >
> > > > If so more uapi to ditch, and check in an igt that it's rejected.
> > > >
> > > > Plus standard !args->size handling here with appropriate drm_debug line
> > > > and all that.
> > > >
> > > > > +             pc->user_engines = NULL;
> > > > > +             memset(&pc->legacy_rcs_sseu, 0, sizeof(pc->legacy_rcs_sseu));
> > > > > +             return 0;
> > > > > +     }
> > > > > +
> > > > > +     BUILD_BUG_ON(!IS_ALIGNED(sizeof(*user), sizeof(*user->engines)));
> > > >
> > > > I frankly don't know what this is checking, but it also looks harmless.
> > >
> > > Yeah..... All I can see is that it lets us avoid doing a subtraction
> > > in the alignment check below.  Kind-of silly, IMO.
> >
> > I'm not seeing even that? Care to help the blind?
>
> The array length is calculated as (args->size - sizeof(*user)) /
> sizeof(*user->engines) which means that we really want (args->size -
> sizeof(*user)) to be divisible by sizeof(*user->engines).  However,
> instead of checking
>
> IS_ALIGNED(args->size - sizeof(*user), sizeof(*user->engines))
>
> we first check that sizeof(*user) is divisible by
> sizeof(*user->engines) with a static check and then just check the
> alignment of args->size.  I'm going to fix this mess.

Uh. Motion that I'm guilty of not having understood this magic at all,
and also yes pls, burn this down with fire. gcc will optimize out the
subtraction as long as everything is aligned, and since it's uapi we
know it's never going to change.

Also.

Why.



...

Just why.

> > > > > +     if (args->size < sizeof(*user) ||
> > > > > +         !IS_ALIGNED(args->size, sizeof(*user->engines))) {
> > > > > +             drm_dbg(&i915->drm, "Invalid size for engine array: %d\n",
> > > > > +                     args->size);
> > > > > +             return -EINVAL;
> > > > > +     }
> > > > > +
> > > > > +     set.num_engines = (args->size - sizeof(*user)) / sizeof(*user->engines);
> > > > > +     /* RING_MASK has no shift so we can use it directly here */
> > > > > +     if (set.num_engines > I915_EXEC_RING_MASK + 1)
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     set.engines = kmalloc_array(set.num_engines, sizeof(*set.engines), GFP_KERNEL);
> > > > > +     if (!set.engines)
> > > > > +             return -ENOMEM;
> > > > > +
> > > > > +     for (n = 0; n < set.num_engines; n++) {
> > > > > +             struct i915_engine_class_instance ci;
> > > > > +             struct intel_engine_cs *engine;
> > > > > +
> > > > > +             if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
> > > > > +                     kfree(set.engines);
> > > > > +                     return -EFAULT;
> > > > > +             }
> > > > > +
> > > > > +             memset(&set.engines[n], 0, sizeof(set.engines[n]));
> > > > > +
> > > > > +             if (ci.engine_class == (u16)I915_ENGINE_CLASS_INVALID &&
> > > > > +                 ci.engine_instance == (u16)I915_ENGINE_CLASS_INVALID_NONE)
> > > > > +                     continue;
> > > > > +
> > > > > +             engine = intel_engine_lookup_user(i915,
> > > > > +                                               ci.engine_class,
> > > > > +                                               ci.engine_instance);
> > > > > +             if (!engine) {
> > > > > +                     drm_dbg(&i915->drm,
> > > > > +                             "Invalid engine[%d]: { class:%d, instance:%d }\n",
> > > > > +                             n, ci.engine_class, ci.engine_instance);
> > > > > +                     kfree(set.engines);
> > > > > +                     return -ENOENT;
> > > > > +             }
> > > > > +
> > > > > +             set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
> > > > > +             set.engines[n].engine = engine;
> > > > > +     }
> > > > > +
> > > > > +     err = -EFAULT;
> > > > > +     if (!get_user(extensions, &user->extensions))
> > > > > +             err = i915_user_extensions(u64_to_user_ptr(extensions),
> > > > > +                                        set_proto_ctx_engines_extensions,
> > > > > +                                        ARRAY_SIZE(set_proto_ctx_engines_extensions),
> > > > > +                                        &set);
> > > > > +     if (err) {
> > > > > +             kfree(set.engines);
> > > > > +             return err;
> > > > > +     }
> > > > > +
> > > > > +     kfree(pc->user_engines);
> > > >
> > > > Both of these kfree potentially leak engines[].siblings. I think you need
> > > > to extract a proto_context_free_engines helper and use that 2x here and
> > > > once at the very top in proto_context_close().
> > >
> > > Good catch. Done.
> > >
> > > > > +     pc->num_user_engines = set.num_engines;
> > > > > +     pc->user_engines = set.engines;
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
> > > > > +                           struct i915_gem_proto_context *pc,
> > > > > +                           struct drm_i915_gem_context_param *args)
> > > > > +{
> > > > > +     struct drm_i915_private *i915 = fpriv->dev_priv;
> > > > > +     struct drm_i915_gem_context_param_sseu user_sseu;
> > > > > +     struct intel_sseu *sseu;
> > > > > +     int ret;
> > > > > +
> > > > > +     if (args->size < sizeof(user_sseu))
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     if (!IS_GEN(i915, 11))
> > > > > +             return -ENODEV;
> > > > > +
> > > > > +     if (copy_from_user(&user_sseu, u64_to_user_ptr(args->value),
> > > > > +                        sizeof(user_sseu)))
> > > > > +             return -EFAULT;
> > > > > +
> > > > > +     if (user_sseu.rsvd)
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     if (user_sseu.flags & ~(I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX))
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     if (!!(user_sseu.flags & I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX) != (pc->num_user_engines >= 0))
> > > > > +             return -EINVAL;
> > > > > +
> > > > > +     if (pc->num_user_engines >= 0) {
> > > > > +             int idx = user_sseu.engine.engine_instance;
> > > > > +             struct i915_gem_proto_engine *pe;
> > > > > +
> > > > > +             if (idx >= pc->num_user_engines)
> > > > > +                     return -EINVAL;
> > > > > +
> > > > > +             pe = &pc->user_engines[idx];
> > > > > +
> > > > > +             /* Only render engine supports RPCS configuration. */
> > > > > +             if (pe->engine->class != RENDER_CLASS)
> > > > > +                     return -EINVAL;
> > > > > +
> > > > > +             sseu = &pe->sseu;
> > > > > +     } else {
> > > > > +             /* Only render engine supports RPCS configuration. */
> > > > > +             if (user_sseu.engine.engine_class != I915_ENGINE_CLASS_RENDER)
> > > > > +                     return -EINVAL;
> > > > > +
> > > > > +             /* There is only one render engine */
> > > > > +             if (user_sseu.engine.engine_instance != 0)
> > > > > +                     return -EINVAL;
> > > > > +
> > > > > +             sseu = &pc->legacy_rcs_sseu;
> > > > > +     }
> > > >
> > > > I think this faithfully rebuilds the convoluted and I think largely
> > > > accidental semantics of SSEU for all combinations of ordering against
> > > > set_engines.
> > > >
> > > > Maybe add a commit message note about this particular kind of fun here. I
> > > > don't think a code comment is warranted since I don't think I've seen a
> > > > userspace rely on how sseu interacts with set_engines
> > >
> > > Done.
> > >
> > > > > +
> > > > > +     ret = i915_gem_user_to_context_sseu(&i915->gt, &user_sseu, sseu);
> > > > > +     if (ret)
> > > > > +             return ret;
> > > > > +
> > > > > +     args->size = sizeof(user_sseu);
> > > > > +
> > > > > +     return 0;
> > > > > +}
> > > > > +
> > > > > +static int set_proto_ctx_param(struct drm_i915_file_private *fpriv,
> > > > > +                            struct i915_gem_proto_context *pc,
> > > > > +                            struct drm_i915_gem_context_param *args)
> > > > > +{
> > > > > +     int ret = 0;
> > > > > +
> > > > > +     switch (args->param) {
> > > > > +     case I915_CONTEXT_PARAM_NO_ERROR_CAPTURE:
> > > > > +             if (args->size)
> > > > > +                     ret = -EINVAL;
> > > > > +             else if (args->value)
> > > > > +                     __set_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > > > > +             else
> > > > > +                     __clear_bit(UCONTEXT_NO_ERROR_CAPTURE, &pc->user_flags);
> > > >
> > > > Open code please and double check I caught them all ...
> > >
> > > As I commented the first time around, __set/clear_bit are static
> > > inlines that unroll to "*field |= (1 << bit)" or "*field &= ~(1 <<
> > > bit)" as appropriate.  The non-__ versions do atomics.  I could
> > > hand-roll them but that seems error-prone and it gains us nothing.
> >
> > They do more, they treat this as a potential array of unsigned long as a
> > bitfield of unlimted size. This comes from the cpuset support afaiu our
> > history here, and years ago (decades by now?) linux started supporting
> > more than 64 cpus cores. Our flags are definitely not unlimted and fit in
> > an unsigned, so we're dropping some compiler checking here.
> >
> > Also it's not that bad really:
> >
> >         if (args->value)
> >                 pc->user_flags |= BIT(UCONTEXT_NO_ERROR_CAPTURE);
> >         else
> >                 pc->user_flags &= ~BIT(UCONTEXT_NO_ERROR_CAPTURE);
> >
> > Fairly idiomatic construct. Final argument here is that __func() generally
> > means "beware, check carefuly what's going on here", and nothing funny is
> > going on here at all, so it's a bit a negative trap :-)
> >
> > Anyway git grep shows you're not the first (even outside of drm/i915).
> > Some spot checking with grep shows that bitflag use of __set_bit is about
> > a third of overall use:
> >
> > $ git grep '__set_bit.*)' | wc -l
> > 1761
> >
> > $ git grep '__set_bit.*,\s*&.*)' | wc -l
> > 479
> >
> > So whatever you feel like.
>
> Your shed, your colors.  I just wanted a reason and to know you
> weren't missing something.

Well it's a 30% shed or so, I think it really doesn't matter that much.

> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_BANNABLE:
> > > > > +             if (args->size)
> > > > > +                     ret = -EINVAL;
> > > > > +             else if (!capable(CAP_SYS_ADMIN) && !args->value)
> > > > > +                     ret = -EPERM;
> > > > > +             else if (args->value)
> > > > > +                     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > > > +             else
> > > > > +                     __clear_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_RECOVERABLE:
> > > > > +             if (args->size)
> > > > > +                     ret = -EINVAL;
> > > > > +             else if (args->value)
> > > > > +                     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > > > +             else
> > > > > +                     __clear_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_PRIORITY:
> > > > > +             ret = validate_priority(fpriv->dev_priv, args);
> > > > > +             if (!ret)
> > > > > +                     pc->sched.priority = args->value;
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_SSEU:
> > > > > +             ret = set_proto_ctx_sseu(fpriv, pc, args);
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_VM:
> > > > > +             ret = set_proto_ctx_vm(fpriv, pc, args);
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_ENGINES:
> > > > > +             ret = set_proto_ctx_engines(fpriv, pc, args);
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_PERSISTENCE:
> > > > > +             if (args->size)
> > > > > +                     ret = -EINVAL;
> > > > > +             else if (args->value)
> > > > > +                     __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > > > > +             else
> > > > > +                     __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> > > >
> > > > I think we have a nice mess here. You created this
> > > > proto_context_set_persistence helper, but don't use it here. Oversight?
> > >
> > > Yeah, I should use it.  Done.
> > >
> > > > Aside from the validation fun around persistence, but that's better
> > > > discussed in another patch I think.
> > > >
> > > > > +             break;
> > > > > +
> > > > > +     case I915_CONTEXT_PARAM_NO_ZEROMAP:
> > > > > +     case I915_CONTEXT_PARAM_BAN_PERIOD:
> > > > > +     case I915_CONTEXT_PARAM_RINGSIZE:
> > > > > +     default:
> > > > > +             ret = -EINVAL;
> > > > > +             break;
> > > > > +     }
> > > > > +
> > > > > +     return ret;
> > > > > +}
> > > > > +
> > > > >  static struct i915_address_space *
> > > > >  context_get_vm_rcu(struct i915_gem_context *ctx)
> > > > >  {
> > > > > @@ -475,6 +918,56 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx,
> > > > >       return err;
> > > > >  }
> > > > >
> > > > > +static struct i915_gem_engines *user_engines(struct i915_gem_context *ctx,
> > > > > +                                          unsigned int num_engines,
> > > > > +                                          struct i915_gem_proto_engine *pe)
> > > > > +{
> > > > > +     struct i915_gem_engines *e, *err;
> > > > > +     unsigned int n;
> > > > > +
> > > > > +     e = alloc_engines(num_engines);
> > > > > +     for (n = 0; n < num_engines; n++) {
> > > > > +             struct intel_context *ce;
> > > > > +             int ret;
> > > > > +
> > > > > +             switch (pe[n].type) {
> > > > > +             case I915_GEM_ENGINE_TYPE_PHYSICAL:
> > > > > +                     ce = intel_context_create(pe[n].engine);
> > > > > +                     break;
> > > > > +
> > > > > +             case I915_GEM_ENGINE_TYPE_BALANCED:
> > > > > +                     ce = intel_execlists_create_virtual(pe[n].siblings,
> > > > > +                                                         pe[n].num_siblings);
> > > > > +                     break;
> > > > > +
> > > > > +             case I915_GEM_ENGINE_TYPE_INVALID:
> > > > > +             default:
> > > > > +                     GEM_WARN_ON(pe[n].type != I915_GEM_ENGINE_TYPE_INVALID);
> > > > > +                     continue;
> > > > > +             }
> > > > > +
> > > > > +             if (IS_ERR(ce)) {
> > > > > +                     err = ERR_CAST(ce);
> > > > > +                     goto free_engines;
> > > > > +             }
> > > > > +
> > > > > +             e->engines[n] = ce;
> > > > > +
> > > > > +             ret = intel_context_set_gem(ce, ctx, pe->sseu);
> > > > > +             if (ret) {
> > > > > +                     err = ERR_PTR(ret);
> > > > > +                     goto free_engines;
> > > > > +             }
> > > > > +     }
> > > > > +     e->num_engines = num_engines;
> > > > > +
> > > > > +     return e;
> > > > > +
> > > > > +free_engines:
> > > > > +     free_engines(e);
> > > > > +     return err;
> > > > > +}
> > > > > +
> > > > >  void i915_gem_context_release(struct kref *ref)
> > > > >  {
> > > > >       struct i915_gem_context *ctx = container_of(ref, typeof(*ctx), ref);
> > > > > @@ -779,7 +1272,6 @@ __create_context(struct drm_i915_private *i915,
> > > > >  {
> > > > >       struct i915_gem_context *ctx;
> > > > >       struct i915_gem_engines *e;
> > > > > -     struct intel_sseu null_sseu = {};
> > > > >       int err;
> > > > >       int i;
> > > > >
> > > > > @@ -797,7 +1289,7 @@ __create_context(struct drm_i915_private *i915,
> > > > >       INIT_LIST_HEAD(&ctx->stale.engines);
> > > > >
> > > > >       mutex_init(&ctx->engines_mutex);
> > > > > -     e = default_engines(ctx, null_sseu);
> > > > > +     e = default_engines(ctx, pc->legacy_rcs_sseu);
> > > > >       if (IS_ERR(e)) {
> > > > >               err = PTR_ERR(e);
> > > > >               goto err_free;
> > > > > @@ -916,6 +1408,24 @@ i915_gem_create_context(struct drm_i915_private *i915,
> > > > >               mutex_unlock(&ctx->mutex);
> > > > >       }
> > > > >
> > > > > +     if (pc->num_user_engines >= 0) {
> > > > > +             struct i915_gem_engines *engines;
> > > > > +
> > > > > +             engines = user_engines(ctx, pc->num_user_engines,
> > > > > +                                    pc->user_engines);
> > > > > +             if (IS_ERR(engines)) {
> > > > > +                     context_close(ctx);
> > > > > +                     return ERR_CAST(engines);
> > > > > +             }
> > > > > +
> > > > > +             mutex_lock(&ctx->engines_mutex);
> > > > > +             i915_gem_context_set_user_engines(ctx);
> > > > > +             engines = rcu_replace_pointer(ctx->engines, engines, 1);
> > > > > +             mutex_unlock(&ctx->engines_mutex);
> > > >
> > > > More locking code to ditch I guess.
> > >
> > > Sure.  Is it safe to just drop it?  I guess it is?  I'm really shaky
> > > around all the RCU requirements and things.
> >
> > Well the 1 in here should be replace with
> > lockdep_is_held(&ctx->engines_mutex), but the engines_mutex also should
> > go, so really can ditch the entire thing. Also no one can access our
> > context, so we can't fail.
> >
> > Now if you do this naively without dropping the __rcu classifier for
> > ctx->engines then static checkers will complain. So until that's done an
> > rcu_assign_pointer should do.
>
> This is all nuked by the last patch.  If it's all the same to you, I'd
> rather leave the re-typed stupid boiler-plate here and delete it and
> do it properly there.  That patch sets up an engine set once and uses
> RCU_INIT_POINTER.

Yeah I think it's all fine if it's clean in the end. I think we
already maxed out out how to transition in reasonable patches to where
we want to be, and there's definitely no optimal path.

I think a git branch for me to pull for next round would be great, so
I can give the final result a good once-over for checking. Without
having to fiddle with .mbox tooling :-)

Cheers, Daniel

> --Jason
>
> > >
> > > > > +
> > > > > +             free_engines(engines);
> > > >
> > > > Also I guess we shouldn't first create the legacy engines for this case?
> > >
> > > That's fixed in the last patch.
> >
> > Yeah I noticed later on.
> >
> > >
> > > > > +     }
> > > > > +
> > > > >       if (pc->single_timeline) {
> > > > >               ret = drm_syncobj_create(&ctx->syncobj,
> > > > >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> > > > > @@ -1956,7 +2466,7 @@ static int ctx_setparam(struct drm_i915_file_private *fpriv,
> > > > >  }
> > > > >
> > > > >  struct create_ext {
> > > > > -     struct i915_gem_context *ctx;
> > > > > +     struct i915_gem_proto_context *pc;
> > > > >       struct drm_i915_file_private *fpriv;
> > > > >  };
> > > > >
> > > > > @@ -1971,7 +2481,7 @@ static int create_setparam(struct i915_user_extension __user *ext, void *data)
> > > > >       if (local.param.ctx_id)
> > > > >               return -EINVAL;
> > > > >
> > > > > -     return ctx_setparam(arg->fpriv, arg->ctx, &local.param);
> > > > > +     return set_proto_ctx_param(arg->fpriv, arg->pc, &local.param);
> > > > >  }
> > > > >
> > > > >  static int invalid_ext(struct i915_user_extension __user *ext, void *data)
> > > > > @@ -1994,7 +2504,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > > >  {
> > > > >       struct drm_i915_private *i915 = to_i915(dev);
> > > > >       struct drm_i915_gem_context_create_ext *args = data;
> > > > > -     struct i915_gem_proto_context *pc;
> > > > > +     struct i915_gem_context *ctx;
> > > > >       struct create_ext ext_data;
> > > > >       int ret;
> > > > >       u32 id;
> > > > > @@ -2017,25 +2527,27 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > > >               return -EIO;
> > > > >       }
> > > > >
> > > > > -     pc = proto_context_create(i915, args->flags);
> > > > > -     if (IS_ERR(pc))
> > > > > -             return PTR_ERR(pc);
> > > > > -
> > > > > -     ext_data.ctx = i915_gem_create_context(i915, pc);
> > > > > -     proto_context_close(pc);
> > > > > -     if (IS_ERR(ext_data.ctx))
> > > > > -             return PTR_ERR(ext_data.ctx);
> > > > > +     ext_data.pc = proto_context_create(i915, args->flags);
> > > > > +     if (IS_ERR(ext_data.pc))
> > > > > +             return PTR_ERR(ext_data.pc);
> > > > >
> > > > >       if (args->flags & I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS) {
> > > > >               ret = i915_user_extensions(u64_to_user_ptr(args->extensions),
> > > > >                                          create_extensions,
> > > > >                                          ARRAY_SIZE(create_extensions),
> > > > >                                          &ext_data);
> > > > > -             if (ret)
> > > > > -                     goto err_ctx;
> > > > > +             if (ret) {
> > > > > +                     proto_context_close(ext_data.pc);
> > > > > +                     return ret;
> > > > > +             }
> > > > >       }
> > > > >
> > > > > -     ret = gem_context_register(ext_data.ctx, ext_data.fpriv, &id);
> > > > > +     ctx = i915_gem_create_context(i915, ext_data.pc);
> > > > > +     proto_context_close(ext_data.pc);
> > > > > +     if (IS_ERR(ctx))
> > > > > +             return PTR_ERR(ctx);
> > > > > +
> > > > > +     ret = gem_context_register(ctx, ext_data.fpriv, &id);
> > > > >       if (ret < 0)
> > > > >               goto err_ctx;
> > > > >
> > > > > @@ -2045,7 +2557,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > > > >       return 0;
> > > > >
> > > > >  err_ctx:
> > > > > -     context_close(ext_data.ctx);
> > > > > +     context_close(ctx);
> > > > >       return ret;
> > > > >  }
> > > > >
> > > > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > > index 0bf337b6d89ac..2ac341f805c8f 100644
> > > > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > > > @@ -66,6 +66,55 @@ struct i915_gem_engines_iter {
> > > > >       const struct i915_gem_engines *engines;
> > > > >  };
> > > > >
> > > > > +/**
> > > > > + * enum i915_gem_engine_type - Describes the type of an i915_gem_proto_engine
> > > > > + */
> > > > > +enum i915_gem_engine_type {
> > > > > +     /** @I915_GEM_ENGINE_TYPE_INVALID: An invalid engine */
> > > > > +     I915_GEM_ENGINE_TYPE_INVALID = 0,
> > > > > +
> > > > > +     /** @I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine */
> > > > > +     I915_GEM_ENGINE_TYPE_PHYSICAL,
> > > > > +
> > > > > +     /** @I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set */
> > > > > +     I915_GEM_ENGINE_TYPE_BALANCED,
> > > > > +};
> > > > > +
> > > > > +/**
> > > > > + * struct i915_gem_proto_engine - prototype engine
> > > > > + *
> > > > > + * This struct describes an engine that a context may contain.  Engines
> > > > > + * have three types:
> > > > > + *
> > > > > + *  - I915_GEM_ENGINE_TYPE_INVALID: Invalid engines can be created but they
> > > > > + *    show up as a NULL in i915_gem_engines::engines[i] and any attempt to
> > > > > + *    use them by the user results in -EINVAL.  They are also useful during
> > > > > + *    proto-context construction because the client may create invalid
> > > > > + *    engines and then set them up later as bonded engines.
> > > > > + *
> > > > > + *  - I915_GEM_ENGINE_TYPE_PHYSICAL: A single physical engine, described by
> > > > > + *    i915_gem_proto_engine::engine.
> > > > > + *
> > > > > + *  - I915_GEM_ENGINE_TYPE_BALANCED: A load-balanced engine set, described
> > > > > + *    i915_gem_proto_engine::num_siblings and i915_gem_proto_engine::siblings.
> > > > > + */
> > > > > +struct i915_gem_proto_engine {
> > > > > +     /** @type: Type of this engine */
> > > > > +     enum i915_gem_engine_type type;
> > > > > +
> > > > > +     /** @engine: Engine, for physical */
> > > > > +     struct intel_engine_cs *engine;
> > > > > +
> > > > > +     /** @num_siblings: Number of balanced siblings */
> > > > > +     unsigned int num_siblings;
> > > > > +
> > > > > +     /** @siblings: Balanced siblings */
> > > > > +     struct intel_engine_cs **siblings;
> > > > > +
> > > > > +     /** @sseu: Client-set SSEU parameters */
> > > > > +     struct intel_sseu sseu;
> > > > > +};
> > > > > +
> > > > >  /**
> > > > >   * struct i915_gem_proto_context - prototype context
> > > > >   *
> > > > > @@ -84,6 +133,15 @@ struct i915_gem_proto_context {
> > > > >       /** @sched: See i915_gem_context::sched */
> > > > >       struct i915_sched_attr sched;
> > > > >
> > > > > +     /** @num_user_engines: Number of user-specified engines or -1 */
> > > > > +     int num_user_engines;
> > > > > +
> > > > > +     /** @user_engines: User-specified engines */
> > > > > +     struct i915_gem_proto_engine *user_engines;
> > > > > +
> > > > > +     /** @sseu: Client-set SSEU parameters for the legacy RCS */
> > > > > +     struct intel_sseu legacy_rcs_sseu;
> > > > > +
> > > > >       /** @single_timeline: See See i915_gem_context::syncobj */
> > > > >       bool single_timeline;
> > > > >  };
> > > > > --
> > > > > 2.31.1
> > > >
> > > > Man is this all nasty. Since I don't want to re-review the entire pile,
> > > > assuming we figure out solutions to all the real issues I've raised (and
> > > > not the snarky bikesheds) this is
> > > >
> > > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > >
> > > Ok.  I'm leaving it off for now to remind myself to ensure that we
> > > close on everything.  I'll add it once I've heard back from you on my
> > > questions above.
> >
> > I think we're all good. Mostly :-/
> > -Daniel
> >
> > >
> > > --Jason
> > >
> > > > >
> > > > > _______________________________________________
> > > > > dri-devel mailing list
> > > > > dri-devel@lists.freedesktop.org
> > > > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> > > >
> > > > --
> > > > Daniel Vetter
> > > > Software Engineer, Intel Corporation
> > > > http://blog.ffwll.ch
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
  2021-05-17 18:44             ` [Intel-gfx] " Daniel Vetter
@ 2021-05-18 10:51               ` Jani Nikula
  -1 siblings, 0 replies; 135+ messages in thread
From: Jani Nikula @ 2021-05-18 10:51 UTC (permalink / raw)
  To: Daniel Vetter, Jason Ekstrand; +Cc: Intel GFX, Maling list - DRI developers

On Mon, 17 May 2021, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Mon, May 17, 2021 at 7:05 PM Jason Ekstrand <jason@jlekstrand.net> wrote:
>>
>> On Mon, May 17, 2021 at 8:40 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>> >
>> > On Fri, May 14, 2021 at 02:13:57PM -0500, Jason Ekstrand wrote:
>> > > I can add those.  I just don't know where to put it.  We don't have an
>> > > i915_gem_vm.h.  Suggestions?
>> >
>> > gt/intel_gtt.h seems to be the header for i915_address_space stuff. Also
>> > contains the i915_vma_ops but not i915_vma.
>> >
>> > It's a pretty good mess, but probably the best place for now for these :-/
>>
>> The one for contexts is in i915_drv.h so I put the VM one there too.
>> Feel free to tell me to move it.  I don't care where it goes.
>
> i915_drv.h is the og dumping ground and needs to die. Everything in
> there needs to be moved out/split/whatever for better code
> organization. If we have a place already that fits better (even if
> maybe misnamed) it's better to put it there.

I haven't really codified this anywhere, but this is what I've been
trying to drive:

* All functions in a .c file are declared in the corresponding .h
  file. 1:1 relationship.

* Have _types.h headers separately for defining types that lead to deep
  include chains. (We have this in part because we have absolutely
  everything in struct drm_i915_private, and everything needs everything
  else to look inside i915.)

* Minimize includes from headers. Prefer forward declarations where
  possible. Prefer specific includes over generic includes.

* Each header is self-contained (this is build-tested with
  CONFIG_DRM_I915_WERROR=y).

* Avoid static inlines unless you have a performance need.

* Don't have any externs. Interfaces over data; data is not an
  interface.

* Prefix functions in a file according to the filename. intel_foo.[ch]
  would have functions intel_foo_*(). Ditto i915_bar.[ch] and
  i915_bar_*(). (Avoid non-static platform specific functions, but if
  you have them, you'd name them e.g. skl_foo_*().)

Basically the rationale is to have more order in the chaos that we've
had for a long time. It's not so much about being pedantic about the
naming, but rather the secondary effect of making people think about
where they put stuff and how it's all grouped together.

IMO it's also easier to add file.[ch] and nuke it later than add stuff
to some of our huge files and then clean it up later.


BR,
Jani.

-- 
Jani Nikula, Intel Open Source Graphics Center

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters
@ 2021-05-18 10:51               ` Jani Nikula
  0 siblings, 0 replies; 135+ messages in thread
From: Jani Nikula @ 2021-05-18 10:51 UTC (permalink / raw)
  To: Daniel Vetter, Jason Ekstrand; +Cc: Intel GFX, Maling list - DRI developers

On Mon, 17 May 2021, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Mon, May 17, 2021 at 7:05 PM Jason Ekstrand <jason@jlekstrand.net> wrote:
>>
>> On Mon, May 17, 2021 at 8:40 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>> >
>> > On Fri, May 14, 2021 at 02:13:57PM -0500, Jason Ekstrand wrote:
>> > > I can add those.  I just don't know where to put it.  We don't have an
>> > > i915_gem_vm.h.  Suggestions?
>> >
>> > gt/intel_gtt.h seems to be the header for i915_address_space stuff. Also
>> > contains the i915_vma_ops but not i915_vma.
>> >
>> > It's a pretty good mess, but probably the best place for now for these :-/
>>
>> The one for contexts is in i915_drv.h so I put the VM one there too.
>> Feel free to tell me to move it.  I don't care where it goes.
>
> i915_drv.h is the og dumping ground and needs to die. Everything in
> there needs to be moved out/split/whatever for better code
> organization. If we have a place already that fits better (even if
> maybe misnamed) it's better to put it there.

I haven't really codified this anywhere, but this is what I've been
trying to drive:

* All functions in a .c file are declared in the corresponding .h
  file. 1:1 relationship.

* Have _types.h headers separately for defining types that lead to deep
  include chains. (We have this in part because we have absolutely
  everything in struct drm_i915_private, and everything needs everything
  else to look inside i915.)

* Minimize includes from headers. Prefer forward declarations where
  possible. Prefer specific includes over generic includes.

* Each header is self-contained (this is build-tested with
  CONFIG_DRM_I915_WERROR=y).

* Avoid static inlines unless you have a performance need.

* Don't have any externs. Interfaces over data; data is not an
  interface.

* Prefix functions in a file according to the filename. intel_foo.[ch]
  would have functions intel_foo_*(). Ditto i915_bar.[ch] and
  i915_bar_*(). (Avoid non-static platform specific functions, but if
  you have them, you'd name them e.g. skl_foo_*().)

Basically the rationale is to have more order in the chaos that we've
had for a long time. It's not so much about being pedantic about the
naming, but rather the secondary effect of making people think about
where they put stuff and how it's all grouped together.

IMO it's also easier to add file.[ch] and nuke it later than add stuff
to some of our huge files and then clean it up later.


BR,
Jani.

-- 
Jani Nikula, Intel Open Source Graphics Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct
  2021-05-04 16:13     ` [Intel-gfx] " Daniel Vetter
@ 2021-06-02 21:53       ` Jason Ekstrand
  -1 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-06-02 21:53 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 11:13 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:37AM -0500, Jason Ekstrand wrote:
> > The current context uAPI allows for two methods of setting context
> > parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
> > former is allowed to be called at any time while the later happens as
> > part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
> > settable via the other.  While some params are fairly simple and setting
> > them on a live context is harmless such the context priority, others are
> > far trickier such as the VM or the set of engines.  In order to swap out
> > the VM, for instance, we have to delay until all current in-flight work
> > is complete, swap in the new VM, and then continue.  This leads to a
> > plethora of potential race conditions we'd really rather avoid.
> >
> > Unfortunately, both methods of setting the VM and engine set are in
> > active use today so we can't simply disallow setting the VM or engine
> > set vial SET_CONTEXT_PARAM.  In order to work around this wart, this
> > commit adds a proto-context struct which contains all the context create
> > parameters.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
>
> Per-patch changelog pls.

Done.

> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 145 ++++++++++++++----
> >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  22 +++
> >  .../gpu/drm/i915/gem/selftests/mock_context.c |  16 +-
> >  3 files changed, 153 insertions(+), 30 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index 4835991898ac9..10bd1b6dd1774 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -191,6 +191,97 @@ static int validate_priority(struct drm_i915_private *i915,
> >       return 0;
> >  }
> >
> > +static void proto_context_close(struct i915_gem_proto_context *pc)
> > +{
> > +     if (pc->vm)
> > +             i915_vm_put(pc->vm);
> > +     kfree(pc);
> > +}
> > +
> > +static int proto_context_set_persistence(struct drm_i915_private *i915,
> > +                                      struct i915_gem_proto_context *pc,
> > +                                      bool persist)
> > +{
> > +     if (persist) {
> > +             /*
> > +              * Only contexts that are short-lived [that will expire or be
> > +              * reset] are allowed to survive past termination. We require
> > +              * hangcheck to ensure that the persistent requests are healthy.
> > +              */
> > +             if (!i915->params.enable_hangcheck)
> > +                     return -EINVAL;
> > +
> > +             __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
>
> Ok so I looked, and the reason __set_bit and friends is for endless
> bitfields, i.e. where user_flags is an actually dynamically sized array.
>
> Given that this is complete overkill I think fully open-coding the bitops
> is the right bikeshed color choice. So

I've fixed it now.  I had fixed it in the last version but it ended up
squashed into the wrong patch. :-(

>                 user_flags &= UCONTEXT_PERSISTENCE;
>
> > +     } else {
> > +             /* To cancel a context we use "preempt-to-idle" */
> > +             if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
> > +                     return -ENODEV;
> > +
> > +             /*
> > +              * If the cancel fails, we then need to reset, cleanly!
> > +              *
> > +              * If the per-engine reset fails, all hope is lost! We resort
> > +              * to a full GPU reset in that unlikely case, but realistically
> > +              * if the engine could not reset, the full reset does not fare
> > +              * much better. The damage has been done.
> > +              *
> > +              * However, if we cannot reset an engine by itself, we cannot
> > +              * cleanup a hanging persistent context without causing
> > +              * colateral damage, and we should not pretend we can by
> > +              * exposing the interface.
> > +              */
> > +             if (!intel_has_reset_engine(&i915->gt))
> > +                     return -ENODEV;
> > +
> > +             __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
>
>                 user_flags &= ~UCONTEXT_PERSISTENCE;
>
> Similar for all the others.
>
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static struct i915_gem_proto_context *
> > +proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > +{
> > +     struct i915_gem_proto_context *pc, *err;
> > +
> > +     pc = kzalloc(sizeof(*pc), GFP_KERNEL);
> > +     if (!pc)
> > +             return ERR_PTR(-ENOMEM);
> > +
> > +     if (HAS_FULL_PPGTT(i915)) {
> > +             struct i915_ppgtt *ppgtt;
> > +
> > +             ppgtt = i915_ppgtt_create(&i915->gt);
> > +             if (IS_ERR(ppgtt)) {
> > +                     drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> > +                             PTR_ERR(ppgtt));
> > +                     err = ERR_CAST(ppgtt);
> > +                     goto proto_close;
> > +             }
> > +             pc->vm = &ppgtt->vm;
>
> I'm not understanding why we're creating the default vm as part of the
> proto context? If we end up setting one this is kinda just wasted
> conditionals, and we're not really gaining in code simplicity. It's just
> whether we create the default vm here (and might need to delete it) or
> when we finalize the context in i915_gem_create_context().
>
> Or am I missing something?
>
> If it's cleaner overall I'm ok with this, just feels a bit silly.

Hrm... I guess there's no particularly good reason.  I think I did it
this way because it seemed like a closer match to the code we had
before.  Also, we need to do it this way if we want GET_CONTEXT_PARAM
with CONTEXT_PARAM_VM to work on a proto-context without finalizing
it.  However, in the end, I'm always finalizing contexts on
GET_CONTEXT_PARAM so that's a non-reason.  I'll see what it looks like
to move it.

> > +     }
> > +
> > +     pc->user_flags = 0;
> > +     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > +     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > +     proto_context_set_persistence(i915, pc, true);
>
> So this I think is another case of trying too hard to share code, because
> what this essentially does is pick the default through a _very_ contrived
> way:
> - we start out with false since we kzalloc, so everything is cleared
> - we try to enable persistence, but we fail silently, so if the module
>   options don't allow persistence we silently keep it at false

Yeah, it's pretty horrible.  It's a copy+paste of what was there
before but that was terrible too.

> I think open-coding this condition would be a lot better. Also disabling
> hangcheck isn't a thing anymore, but we still have code in it.
>
> I think the right thing here is a patch which removes all occurences of
> params.enable_hangcheck and replaces it with the default (which is true).
>
> And then just set this default here directly, because not doing so would
> randomly break some mesa depending how a modparam is set which otherwise
> has 0 impact. Also I think the other code which checks this could end up
> with a refcount underrun on !execlist platforms.

Yeah, I think this would make things clearer.  Before I go off and do
that, it looks to me like the param still exists.  Maybe we just
ignore it?  Should I delete the whole param?  Just trying to confirm
before I go off and type the wrong code.

--Jason

> > +     pc->sched.priority = I915_PRIORITY_NORMAL;
> > +
> > +     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> > +             if (!HAS_EXECLISTS(i915)) {
> > +                     err = ERR_PTR(-EINVAL);
> > +                     goto proto_close;
> > +             }
> > +             pc->single_timeline = true;
> > +     }
> > +
> > +     return pc;
> > +
> > +proto_close:
> > +     proto_context_close(pc);
> > +     return err;
> > +}
> > +
> >  static struct i915_address_space *
> >  context_get_vm_rcu(struct i915_gem_context *ctx)
> >  {
> > @@ -660,7 +751,8 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
> >  }
> >
> >  static struct i915_gem_context *
> > -__create_context(struct drm_i915_private *i915)
> > +__create_context(struct drm_i915_private *i915,
> > +              const struct i915_gem_proto_context *pc)
> >  {
> >       struct i915_gem_context *ctx;
> >       struct i915_gem_engines *e;
> > @@ -673,7 +765,7 @@ __create_context(struct drm_i915_private *i915)
> >
> >       kref_init(&ctx->ref);
> >       ctx->i915 = i915;
> > -     ctx->sched.priority = I915_PRIORITY_NORMAL;
> > +     ctx->sched = pc->sched;
> >       mutex_init(&ctx->mutex);
> >       INIT_LIST_HEAD(&ctx->link);
> >
> > @@ -696,9 +788,7 @@ __create_context(struct drm_i915_private *i915)
> >        * is no remap info, it will be a NOP. */
> >       ctx->remap_slice = ALL_L3_SLICES(i915);
> >
> > -     i915_gem_context_set_bannable(ctx);
> > -     i915_gem_context_set_recoverable(ctx);
> > -     __context_set_persistence(ctx, true /* cgroup hook? */);
> > +     ctx->user_flags = pc->user_flags;
> >
> >       for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
> >               ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
> > @@ -786,38 +876,23 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
> >  }
> >
> >  static struct i915_gem_context *
> > -i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
> > +i915_gem_create_context(struct drm_i915_private *i915,
> > +                     const struct i915_gem_proto_context *pc)
> >  {
> >       struct i915_gem_context *ctx;
> >       int ret;
> >
> > -     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
> > -         !HAS_EXECLISTS(i915))
> > -             return ERR_PTR(-EINVAL);
> > -
> > -     ctx = __create_context(i915);
> > +     ctx = __create_context(i915, pc);
> >       if (IS_ERR(ctx))
> >               return ctx;
> >
> > -     if (HAS_FULL_PPGTT(i915)) {
> > -             struct i915_ppgtt *ppgtt;
> > -
> > -             ppgtt = i915_ppgtt_create(&i915->gt);
> > -             if (IS_ERR(ppgtt)) {
> > -                     drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> > -                             PTR_ERR(ppgtt));
> > -                     context_close(ctx);
> > -                     return ERR_CAST(ppgtt);
> > -             }
> > -
> > +     if (pc->vm) {
> >               mutex_lock(&ctx->mutex);
> > -             __assign_ppgtt(ctx, &ppgtt->vm);
> > +             __assign_ppgtt(ctx, pc->vm);
> >               mutex_unlock(&ctx->mutex);
> > -
> > -             i915_vm_put(&ppgtt->vm);
> >       }
> >
> > -     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> > +     if (pc->single_timeline) {
> >               ret = drm_syncobj_create(&ctx->syncobj,
> >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> >                                        NULL);
> > @@ -883,6 +958,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
> >                         struct drm_file *file)
> >  {
> >       struct drm_i915_file_private *file_priv = file->driver_priv;
> > +     struct i915_gem_proto_context *pc;
> >       struct i915_gem_context *ctx;
> >       int err;
> >       u32 id;
> > @@ -892,7 +968,14 @@ int i915_gem_context_open(struct drm_i915_private *i915,
> >       /* 0 reserved for invalid/unassigned ppgtt */
> >       xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
> >
> > -     ctx = i915_gem_create_context(i915, 0);
> > +     pc = proto_context_create(i915, 0);
> > +     if (IS_ERR(pc)) {
> > +             err = PTR_ERR(pc);
> > +             goto err;
> > +     }
> > +
> > +     ctx = i915_gem_create_context(i915, pc);
> > +     proto_context_close(pc);
> >       if (IS_ERR(ctx)) {
> >               err = PTR_ERR(ctx);
> >               goto err;
> > @@ -1885,6 +1968,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> >  {
> >       struct drm_i915_private *i915 = to_i915(dev);
> >       struct drm_i915_gem_context_create_ext *args = data;
> > +     struct i915_gem_proto_context *pc;
> >       struct create_ext ext_data;
> >       int ret;
> >       u32 id;
> > @@ -1907,7 +1991,12 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> >               return -EIO;
> >       }
> >
> > -     ext_data.ctx = i915_gem_create_context(i915, args->flags);
> > +     pc = proto_context_create(i915, args->flags);
> > +     if (IS_ERR(pc))
> > +             return PTR_ERR(pc);
> > +
> > +     ext_data.ctx = i915_gem_create_context(i915, pc);
> > +     proto_context_close(pc);
> >       if (IS_ERR(ext_data.ctx))
> >               return PTR_ERR(ext_data.ctx);
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > index 5f0673a2129f9..0bf337b6d89ac 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > @@ -66,6 +66,28 @@ struct i915_gem_engines_iter {
> >       const struct i915_gem_engines *engines;
> >  };
> >
> > +/**
> > + * struct i915_gem_proto_context - prototype context
> > + *
> > + * The struct i915_gem_proto_context represents the creation parameters for
> > + * an i915_gem_context.  This is used to gather parameters provided either
> > + * through creation flags or via SET_CONTEXT_PARAM so that, when we create
> > + * the final i915_gem_context, those parameters can be immutable.
> > + */
> > +struct i915_gem_proto_context {
> > +     /** @vm: See i915_gem_context::vm */
> > +     struct i915_address_space *vm;
> > +
> > +     /** @user_flags: See i915_gem_context::user_flags */
> > +     unsigned long user_flags;
> > +
> > +     /** @sched: See i915_gem_context::sched */
> > +     struct i915_sched_attr sched;
> > +
> > +     /** @single_timeline: See See i915_gem_context::syncobj */
> > +     bool single_timeline;
> > +};
> > +
> >  /**
> >   * struct i915_gem_context - client state
> >   *
> > diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > index 51b5a3421b400..e0f512ef7f3c6 100644
> > --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > @@ -80,11 +80,17 @@ void mock_init_contexts(struct drm_i915_private *i915)
> >  struct i915_gem_context *
> >  live_context(struct drm_i915_private *i915, struct file *file)
> >  {
> > +     struct i915_gem_proto_context *pc;
> >       struct i915_gem_context *ctx;
> >       int err;
> >       u32 id;
> >
> > -     ctx = i915_gem_create_context(i915, 0);
> > +     pc = proto_context_create(i915, 0);
> > +     if (IS_ERR(pc))
> > +             return ERR_CAST(pc);
> > +
> > +     ctx = i915_gem_create_context(i915, pc);
> > +     proto_context_close(pc);
> >       if (IS_ERR(ctx))
> >               return ctx;
> >
> > @@ -142,8 +148,14 @@ struct i915_gem_context *
> >  kernel_context(struct drm_i915_private *i915)
> >  {
> >       struct i915_gem_context *ctx;
> > +     struct i915_gem_proto_context *pc;
> > +
> > +     pc = proto_context_create(i915, 0);
> > +     if (IS_ERR(pc))
> > +             return ERR_CAST(pc);
> >
> > -     ctx = i915_gem_create_context(i915, 0);
> > +     ctx = i915_gem_create_context(i915, pc);
> > +     proto_context_close(pc);
>
> I think at large still looks pretty good, but some polish needed.
> -Daniel
>
> >       if (IS_ERR(ctx))
> >               return ctx;
> >
> > --
> > 2.31.1
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct
@ 2021-06-02 21:53       ` Jason Ekstrand
  0 siblings, 0 replies; 135+ messages in thread
From: Jason Ekstrand @ 2021-06-02 21:53 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Intel GFX, Maling list - DRI developers

On Tue, May 4, 2021 at 11:13 AM Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Mon, May 03, 2021 at 10:57:37AM -0500, Jason Ekstrand wrote:
> > The current context uAPI allows for two methods of setting context
> > parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
> > former is allowed to be called at any time while the later happens as
> > part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
> > settable via the other.  While some params are fairly simple and setting
> > them on a live context is harmless such the context priority, others are
> > far trickier such as the VM or the set of engines.  In order to swap out
> > the VM, for instance, we have to delay until all current in-flight work
> > is complete, swap in the new VM, and then continue.  This leads to a
> > plethora of potential race conditions we'd really rather avoid.
> >
> > Unfortunately, both methods of setting the VM and engine set are in
> > active use today so we can't simply disallow setting the VM or engine
> > set vial SET_CONTEXT_PARAM.  In order to work around this wart, this
> > commit adds a proto-context struct which contains all the context create
> > parameters.
> >
> > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
>
> Per-patch changelog pls.

Done.

> > ---
> >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 145 ++++++++++++++----
> >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  22 +++
> >  .../gpu/drm/i915/gem/selftests/mock_context.c |  16 +-
> >  3 files changed, 153 insertions(+), 30 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > index 4835991898ac9..10bd1b6dd1774 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > @@ -191,6 +191,97 @@ static int validate_priority(struct drm_i915_private *i915,
> >       return 0;
> >  }
> >
> > +static void proto_context_close(struct i915_gem_proto_context *pc)
> > +{
> > +     if (pc->vm)
> > +             i915_vm_put(pc->vm);
> > +     kfree(pc);
> > +}
> > +
> > +static int proto_context_set_persistence(struct drm_i915_private *i915,
> > +                                      struct i915_gem_proto_context *pc,
> > +                                      bool persist)
> > +{
> > +     if (persist) {
> > +             /*
> > +              * Only contexts that are short-lived [that will expire or be
> > +              * reset] are allowed to survive past termination. We require
> > +              * hangcheck to ensure that the persistent requests are healthy.
> > +              */
> > +             if (!i915->params.enable_hangcheck)
> > +                     return -EINVAL;
> > +
> > +             __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
>
> Ok so I looked, and the reason __set_bit and friends is for endless
> bitfields, i.e. where user_flags is an actually dynamically sized array.
>
> Given that this is complete overkill I think fully open-coding the bitops
> is the right bikeshed color choice. So

I've fixed it now.  I had fixed it in the last version but it ended up
squashed into the wrong patch. :-(

>                 user_flags &= UCONTEXT_PERSISTENCE;
>
> > +     } else {
> > +             /* To cancel a context we use "preempt-to-idle" */
> > +             if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
> > +                     return -ENODEV;
> > +
> > +             /*
> > +              * If the cancel fails, we then need to reset, cleanly!
> > +              *
> > +              * If the per-engine reset fails, all hope is lost! We resort
> > +              * to a full GPU reset in that unlikely case, but realistically
> > +              * if the engine could not reset, the full reset does not fare
> > +              * much better. The damage has been done.
> > +              *
> > +              * However, if we cannot reset an engine by itself, we cannot
> > +              * cleanup a hanging persistent context without causing
> > +              * colateral damage, and we should not pretend we can by
> > +              * exposing the interface.
> > +              */
> > +             if (!intel_has_reset_engine(&i915->gt))
> > +                     return -ENODEV;
> > +
> > +             __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
>
>                 user_flags &= ~UCONTEXT_PERSISTENCE;
>
> Similar for all the others.
>
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static struct i915_gem_proto_context *
> > +proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > +{
> > +     struct i915_gem_proto_context *pc, *err;
> > +
> > +     pc = kzalloc(sizeof(*pc), GFP_KERNEL);
> > +     if (!pc)
> > +             return ERR_PTR(-ENOMEM);
> > +
> > +     if (HAS_FULL_PPGTT(i915)) {
> > +             struct i915_ppgtt *ppgtt;
> > +
> > +             ppgtt = i915_ppgtt_create(&i915->gt);
> > +             if (IS_ERR(ppgtt)) {
> > +                     drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> > +                             PTR_ERR(ppgtt));
> > +                     err = ERR_CAST(ppgtt);
> > +                     goto proto_close;
> > +             }
> > +             pc->vm = &ppgtt->vm;
>
> I'm not understanding why we're creating the default vm as part of the
> proto context? If we end up setting one this is kinda just wasted
> conditionals, and we're not really gaining in code simplicity. It's just
> whether we create the default vm here (and might need to delete it) or
> when we finalize the context in i915_gem_create_context().
>
> Or am I missing something?
>
> If it's cleaner overall I'm ok with this, just feels a bit silly.

Hrm... I guess there's no particularly good reason.  I think I did it
this way because it seemed like a closer match to the code we had
before.  Also, we need to do it this way if we want GET_CONTEXT_PARAM
with CONTEXT_PARAM_VM to work on a proto-context without finalizing
it.  However, in the end, I'm always finalizing contexts on
GET_CONTEXT_PARAM so that's a non-reason.  I'll see what it looks like
to move it.

> > +     }
> > +
> > +     pc->user_flags = 0;
> > +     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > +     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > +     proto_context_set_persistence(i915, pc, true);
>
> So this I think is another case of trying too hard to share code, because
> what this essentially does is pick the default through a _very_ contrived
> way:
> - we start out with false since we kzalloc, so everything is cleared
> - we try to enable persistence, but we fail silently, so if the module
>   options don't allow persistence we silently keep it at false

Yeah, it's pretty horrible.  It's a copy+paste of what was there
before but that was terrible too.

> I think open-coding this condition would be a lot better. Also disabling
> hangcheck isn't a thing anymore, but we still have code in it.
>
> I think the right thing here is a patch which removes all occurences of
> params.enable_hangcheck and replaces it with the default (which is true).
>
> And then just set this default here directly, because not doing so would
> randomly break some mesa depending how a modparam is set which otherwise
> has 0 impact. Also I think the other code which checks this could end up
> with a refcount underrun on !execlist platforms.

Yeah, I think this would make things clearer.  Before I go off and do
that, it looks to me like the param still exists.  Maybe we just
ignore it?  Should I delete the whole param?  Just trying to confirm
before I go off and type the wrong code.

--Jason

> > +     pc->sched.priority = I915_PRIORITY_NORMAL;
> > +
> > +     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> > +             if (!HAS_EXECLISTS(i915)) {
> > +                     err = ERR_PTR(-EINVAL);
> > +                     goto proto_close;
> > +             }
> > +             pc->single_timeline = true;
> > +     }
> > +
> > +     return pc;
> > +
> > +proto_close:
> > +     proto_context_close(pc);
> > +     return err;
> > +}
> > +
> >  static struct i915_address_space *
> >  context_get_vm_rcu(struct i915_gem_context *ctx)
> >  {
> > @@ -660,7 +751,8 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
> >  }
> >
> >  static struct i915_gem_context *
> > -__create_context(struct drm_i915_private *i915)
> > +__create_context(struct drm_i915_private *i915,
> > +              const struct i915_gem_proto_context *pc)
> >  {
> >       struct i915_gem_context *ctx;
> >       struct i915_gem_engines *e;
> > @@ -673,7 +765,7 @@ __create_context(struct drm_i915_private *i915)
> >
> >       kref_init(&ctx->ref);
> >       ctx->i915 = i915;
> > -     ctx->sched.priority = I915_PRIORITY_NORMAL;
> > +     ctx->sched = pc->sched;
> >       mutex_init(&ctx->mutex);
> >       INIT_LIST_HEAD(&ctx->link);
> >
> > @@ -696,9 +788,7 @@ __create_context(struct drm_i915_private *i915)
> >        * is no remap info, it will be a NOP. */
> >       ctx->remap_slice = ALL_L3_SLICES(i915);
> >
> > -     i915_gem_context_set_bannable(ctx);
> > -     i915_gem_context_set_recoverable(ctx);
> > -     __context_set_persistence(ctx, true /* cgroup hook? */);
> > +     ctx->user_flags = pc->user_flags;
> >
> >       for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
> >               ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
> > @@ -786,38 +876,23 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
> >  }
> >
> >  static struct i915_gem_context *
> > -i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
> > +i915_gem_create_context(struct drm_i915_private *i915,
> > +                     const struct i915_gem_proto_context *pc)
> >  {
> >       struct i915_gem_context *ctx;
> >       int ret;
> >
> > -     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
> > -         !HAS_EXECLISTS(i915))
> > -             return ERR_PTR(-EINVAL);
> > -
> > -     ctx = __create_context(i915);
> > +     ctx = __create_context(i915, pc);
> >       if (IS_ERR(ctx))
> >               return ctx;
> >
> > -     if (HAS_FULL_PPGTT(i915)) {
> > -             struct i915_ppgtt *ppgtt;
> > -
> > -             ppgtt = i915_ppgtt_create(&i915->gt);
> > -             if (IS_ERR(ppgtt)) {
> > -                     drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> > -                             PTR_ERR(ppgtt));
> > -                     context_close(ctx);
> > -                     return ERR_CAST(ppgtt);
> > -             }
> > -
> > +     if (pc->vm) {
> >               mutex_lock(&ctx->mutex);
> > -             __assign_ppgtt(ctx, &ppgtt->vm);
> > +             __assign_ppgtt(ctx, pc->vm);
> >               mutex_unlock(&ctx->mutex);
> > -
> > -             i915_vm_put(&ppgtt->vm);
> >       }
> >
> > -     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> > +     if (pc->single_timeline) {
> >               ret = drm_syncobj_create(&ctx->syncobj,
> >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> >                                        NULL);
> > @@ -883,6 +958,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
> >                         struct drm_file *file)
> >  {
> >       struct drm_i915_file_private *file_priv = file->driver_priv;
> > +     struct i915_gem_proto_context *pc;
> >       struct i915_gem_context *ctx;
> >       int err;
> >       u32 id;
> > @@ -892,7 +968,14 @@ int i915_gem_context_open(struct drm_i915_private *i915,
> >       /* 0 reserved for invalid/unassigned ppgtt */
> >       xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
> >
> > -     ctx = i915_gem_create_context(i915, 0);
> > +     pc = proto_context_create(i915, 0);
> > +     if (IS_ERR(pc)) {
> > +             err = PTR_ERR(pc);
> > +             goto err;
> > +     }
> > +
> > +     ctx = i915_gem_create_context(i915, pc);
> > +     proto_context_close(pc);
> >       if (IS_ERR(ctx)) {
> >               err = PTR_ERR(ctx);
> >               goto err;
> > @@ -1885,6 +1968,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> >  {
> >       struct drm_i915_private *i915 = to_i915(dev);
> >       struct drm_i915_gem_context_create_ext *args = data;
> > +     struct i915_gem_proto_context *pc;
> >       struct create_ext ext_data;
> >       int ret;
> >       u32 id;
> > @@ -1907,7 +1991,12 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> >               return -EIO;
> >       }
> >
> > -     ext_data.ctx = i915_gem_create_context(i915, args->flags);
> > +     pc = proto_context_create(i915, args->flags);
> > +     if (IS_ERR(pc))
> > +             return PTR_ERR(pc);
> > +
> > +     ext_data.ctx = i915_gem_create_context(i915, pc);
> > +     proto_context_close(pc);
> >       if (IS_ERR(ext_data.ctx))
> >               return PTR_ERR(ext_data.ctx);
> >
> > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > index 5f0673a2129f9..0bf337b6d89ac 100644
> > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > @@ -66,6 +66,28 @@ struct i915_gem_engines_iter {
> >       const struct i915_gem_engines *engines;
> >  };
> >
> > +/**
> > + * struct i915_gem_proto_context - prototype context
> > + *
> > + * The struct i915_gem_proto_context represents the creation parameters for
> > + * an i915_gem_context.  This is used to gather parameters provided either
> > + * through creation flags or via SET_CONTEXT_PARAM so that, when we create
> > + * the final i915_gem_context, those parameters can be immutable.
> > + */
> > +struct i915_gem_proto_context {
> > +     /** @vm: See i915_gem_context::vm */
> > +     struct i915_address_space *vm;
> > +
> > +     /** @user_flags: See i915_gem_context::user_flags */
> > +     unsigned long user_flags;
> > +
> > +     /** @sched: See i915_gem_context::sched */
> > +     struct i915_sched_attr sched;
> > +
> > +     /** @single_timeline: See See i915_gem_context::syncobj */
> > +     bool single_timeline;
> > +};
> > +
> >  /**
> >   * struct i915_gem_context - client state
> >   *
> > diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > index 51b5a3421b400..e0f512ef7f3c6 100644
> > --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > @@ -80,11 +80,17 @@ void mock_init_contexts(struct drm_i915_private *i915)
> >  struct i915_gem_context *
> >  live_context(struct drm_i915_private *i915, struct file *file)
> >  {
> > +     struct i915_gem_proto_context *pc;
> >       struct i915_gem_context *ctx;
> >       int err;
> >       u32 id;
> >
> > -     ctx = i915_gem_create_context(i915, 0);
> > +     pc = proto_context_create(i915, 0);
> > +     if (IS_ERR(pc))
> > +             return ERR_CAST(pc);
> > +
> > +     ctx = i915_gem_create_context(i915, pc);
> > +     proto_context_close(pc);
> >       if (IS_ERR(ctx))
> >               return ctx;
> >
> > @@ -142,8 +148,14 @@ struct i915_gem_context *
> >  kernel_context(struct drm_i915_private *i915)
> >  {
> >       struct i915_gem_context *ctx;
> > +     struct i915_gem_proto_context *pc;
> > +
> > +     pc = proto_context_create(i915, 0);
> > +     if (IS_ERR(pc))
> > +             return ERR_CAST(pc);
> >
> > -     ctx = i915_gem_create_context(i915, 0);
> > +     ctx = i915_gem_create_context(i915, pc);
> > +     proto_context_close(pc);
>
> I think at large still looks pretty good, but some polish needed.
> -Daniel
>
> >       if (IS_ERR(ctx))
> >               return ctx;
> >
> > --
> > 2.31.1
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct
  2021-06-02 21:53       ` [Intel-gfx] " Jason Ekstrand
@ 2021-06-03  7:07         ` Daniel Vetter
  -1 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-06-03  7:07 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: Intel GFX, Maling list - DRI developers

On Wed, Jun 2, 2021 at 11:53 PM Jason Ekstrand <jason@jlekstrand.net> wrote:
>
> On Tue, May 4, 2021 at 11:13 AM Daniel Vetter <daniel@ffwll.ch> wrote:
> >
> > On Mon, May 03, 2021 at 10:57:37AM -0500, Jason Ekstrand wrote:
> > > The current context uAPI allows for two methods of setting context
> > > parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
> > > former is allowed to be called at any time while the later happens as
> > > part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
> > > settable via the other.  While some params are fairly simple and setting
> > > them on a live context is harmless such the context priority, others are
> > > far trickier such as the VM or the set of engines.  In order to swap out
> > > the VM, for instance, we have to delay until all current in-flight work
> > > is complete, swap in the new VM, and then continue.  This leads to a
> > > plethora of potential race conditions we'd really rather avoid.
> > >
> > > Unfortunately, both methods of setting the VM and engine set are in
> > > active use today so we can't simply disallow setting the VM or engine
> > > set vial SET_CONTEXT_PARAM.  In order to work around this wart, this
> > > commit adds a proto-context struct which contains all the context create
> > > parameters.
> > >
> > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> >
> > Per-patch changelog pls.
>
> Done.
>
> > > ---
> > >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 145 ++++++++++++++----
> > >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  22 +++
> > >  .../gpu/drm/i915/gem/selftests/mock_context.c |  16 +-
> > >  3 files changed, 153 insertions(+), 30 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > index 4835991898ac9..10bd1b6dd1774 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > @@ -191,6 +191,97 @@ static int validate_priority(struct drm_i915_private *i915,
> > >       return 0;
> > >  }
> > >
> > > +static void proto_context_close(struct i915_gem_proto_context *pc)
> > > +{
> > > +     if (pc->vm)
> > > +             i915_vm_put(pc->vm);
> > > +     kfree(pc);
> > > +}
> > > +
> > > +static int proto_context_set_persistence(struct drm_i915_private *i915,
> > > +                                      struct i915_gem_proto_context *pc,
> > > +                                      bool persist)
> > > +{
> > > +     if (persist) {
> > > +             /*
> > > +              * Only contexts that are short-lived [that will expire or be
> > > +              * reset] are allowed to survive past termination. We require
> > > +              * hangcheck to ensure that the persistent requests are healthy.
> > > +              */
> > > +             if (!i915->params.enable_hangcheck)
> > > +                     return -EINVAL;
> > > +
> > > +             __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> >
> > Ok so I looked, and the reason __set_bit and friends is for endless
> > bitfields, i.e. where user_flags is an actually dynamically sized array.
> >
> > Given that this is complete overkill I think fully open-coding the bitops
> > is the right bikeshed color choice. So
>
> I've fixed it now.  I had fixed it in the last version but it ended up
> squashed into the wrong patch. :-(
>
> >                 user_flags &= UCONTEXT_PERSISTENCE;
> >
> > > +     } else {
> > > +             /* To cancel a context we use "preempt-to-idle" */
> > > +             if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
> > > +                     return -ENODEV;
> > > +
> > > +             /*
> > > +              * If the cancel fails, we then need to reset, cleanly!
> > > +              *
> > > +              * If the per-engine reset fails, all hope is lost! We resort
> > > +              * to a full GPU reset in that unlikely case, but realistically
> > > +              * if the engine could not reset, the full reset does not fare
> > > +              * much better. The damage has been done.
> > > +              *
> > > +              * However, if we cannot reset an engine by itself, we cannot
> > > +              * cleanup a hanging persistent context without causing
> > > +              * colateral damage, and we should not pretend we can by
> > > +              * exposing the interface.
> > > +              */
> > > +             if (!intel_has_reset_engine(&i915->gt))
> > > +                     return -ENODEV;
> > > +
> > > +             __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> >
> >                 user_flags &= ~UCONTEXT_PERSISTENCE;
> >
> > Similar for all the others.
> >
> > > +     }
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static struct i915_gem_proto_context *
> > > +proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > > +{
> > > +     struct i915_gem_proto_context *pc, *err;
> > > +
> > > +     pc = kzalloc(sizeof(*pc), GFP_KERNEL);
> > > +     if (!pc)
> > > +             return ERR_PTR(-ENOMEM);
> > > +
> > > +     if (HAS_FULL_PPGTT(i915)) {
> > > +             struct i915_ppgtt *ppgtt;
> > > +
> > > +             ppgtt = i915_ppgtt_create(&i915->gt);
> > > +             if (IS_ERR(ppgtt)) {
> > > +                     drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> > > +                             PTR_ERR(ppgtt));
> > > +                     err = ERR_CAST(ppgtt);
> > > +                     goto proto_close;
> > > +             }
> > > +             pc->vm = &ppgtt->vm;
> >
> > I'm not understanding why we're creating the default vm as part of the
> > proto context? If we end up setting one this is kinda just wasted
> > conditionals, and we're not really gaining in code simplicity. It's just
> > whether we create the default vm here (and might need to delete it) or
> > when we finalize the context in i915_gem_create_context().
> >
> > Or am I missing something?
> >
> > If it's cleaner overall I'm ok with this, just feels a bit silly.
>
> Hrm... I guess there's no particularly good reason.  I think I did it
> this way because it seemed like a closer match to the code we had
> before.  Also, we need to do it this way if we want GET_CONTEXT_PARAM
> with CONTEXT_PARAM_VM to work on a proto-context without finalizing
> it.  However, in the end, I'm always finalizing contexts on
> GET_CONTEXT_PARAM so that's a non-reason.  I'll see what it looks like
> to move it.
>
> > > +     }
> > > +
> > > +     pc->user_flags = 0;
> > > +     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > +     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > +     proto_context_set_persistence(i915, pc, true);
> >
> > So this I think is another case of trying too hard to share code, because
> > what this essentially does is pick the default through a _very_ contrived
> > way:
> > - we start out with false since we kzalloc, so everything is cleared
> > - we try to enable persistence, but we fail silently, so if the module
> >   options don't allow persistence we silently keep it at false
>
> Yeah, it's pretty horrible.  It's a copy+paste of what was there
> before but that was terrible too.
>
> > I think open-coding this condition would be a lot better. Also disabling
> > hangcheck isn't a thing anymore, but we still have code in it.
> >
> > I think the right thing here is a patch which removes all occurences of
> > params.enable_hangcheck and replaces it with the default (which is true).
> >
> > And then just set this default here directly, because not doing so would
> > randomly break some mesa depending how a modparam is set which otherwise
> > has 0 impact. Also I think the other code which checks this could end up
> > with a refcount underrun on !execlist platforms.
>
> Yeah, I think this would make things clearer.  Before I go off and do
> that, it looks to me like the param still exists.  Maybe we just
> ignore it?  Should I delete the whole param?  Just trying to confirm
> before I go off and type the wrong code.

After more reading and talking with Tvrtko I realized that the
hangcheck modparam does actually do something still. So no ripping out
that modparam. I'm also wondering whether we should do an upfront
patch first, but then the bisect history for this proto-context is
nasty anyway, just highlighting the change in the commit message here
should be enough.
-Daniel

> --Jason
>
> > > +     pc->sched.priority = I915_PRIORITY_NORMAL;
> > > +
> > > +     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> > > +             if (!HAS_EXECLISTS(i915)) {
> > > +                     err = ERR_PTR(-EINVAL);
> > > +                     goto proto_close;
> > > +             }
> > > +             pc->single_timeline = true;
> > > +     }
> > > +
> > > +     return pc;
> > > +
> > > +proto_close:
> > > +     proto_context_close(pc);
> > > +     return err;
> > > +}
> > > +
> > >  static struct i915_address_space *
> > >  context_get_vm_rcu(struct i915_gem_context *ctx)
> > >  {
> > > @@ -660,7 +751,8 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
> > >  }
> > >
> > >  static struct i915_gem_context *
> > > -__create_context(struct drm_i915_private *i915)
> > > +__create_context(struct drm_i915_private *i915,
> > > +              const struct i915_gem_proto_context *pc)
> > >  {
> > >       struct i915_gem_context *ctx;
> > >       struct i915_gem_engines *e;
> > > @@ -673,7 +765,7 @@ __create_context(struct drm_i915_private *i915)
> > >
> > >       kref_init(&ctx->ref);
> > >       ctx->i915 = i915;
> > > -     ctx->sched.priority = I915_PRIORITY_NORMAL;
> > > +     ctx->sched = pc->sched;
> > >       mutex_init(&ctx->mutex);
> > >       INIT_LIST_HEAD(&ctx->link);
> > >
> > > @@ -696,9 +788,7 @@ __create_context(struct drm_i915_private *i915)
> > >        * is no remap info, it will be a NOP. */
> > >       ctx->remap_slice = ALL_L3_SLICES(i915);
> > >
> > > -     i915_gem_context_set_bannable(ctx);
> > > -     i915_gem_context_set_recoverable(ctx);
> > > -     __context_set_persistence(ctx, true /* cgroup hook? */);
> > > +     ctx->user_flags = pc->user_flags;
> > >
> > >       for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
> > >               ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
> > > @@ -786,38 +876,23 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
> > >  }
> > >
> > >  static struct i915_gem_context *
> > > -i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
> > > +i915_gem_create_context(struct drm_i915_private *i915,
> > > +                     const struct i915_gem_proto_context *pc)
> > >  {
> > >       struct i915_gem_context *ctx;
> > >       int ret;
> > >
> > > -     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
> > > -         !HAS_EXECLISTS(i915))
> > > -             return ERR_PTR(-EINVAL);
> > > -
> > > -     ctx = __create_context(i915);
> > > +     ctx = __create_context(i915, pc);
> > >       if (IS_ERR(ctx))
> > >               return ctx;
> > >
> > > -     if (HAS_FULL_PPGTT(i915)) {
> > > -             struct i915_ppgtt *ppgtt;
> > > -
> > > -             ppgtt = i915_ppgtt_create(&i915->gt);
> > > -             if (IS_ERR(ppgtt)) {
> > > -                     drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> > > -                             PTR_ERR(ppgtt));
> > > -                     context_close(ctx);
> > > -                     return ERR_CAST(ppgtt);
> > > -             }
> > > -
> > > +     if (pc->vm) {
> > >               mutex_lock(&ctx->mutex);
> > > -             __assign_ppgtt(ctx, &ppgtt->vm);
> > > +             __assign_ppgtt(ctx, pc->vm);
> > >               mutex_unlock(&ctx->mutex);
> > > -
> > > -             i915_vm_put(&ppgtt->vm);
> > >       }
> > >
> > > -     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> > > +     if (pc->single_timeline) {
> > >               ret = drm_syncobj_create(&ctx->syncobj,
> > >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> > >                                        NULL);
> > > @@ -883,6 +958,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
> > >                         struct drm_file *file)
> > >  {
> > >       struct drm_i915_file_private *file_priv = file->driver_priv;
> > > +     struct i915_gem_proto_context *pc;
> > >       struct i915_gem_context *ctx;
> > >       int err;
> > >       u32 id;
> > > @@ -892,7 +968,14 @@ int i915_gem_context_open(struct drm_i915_private *i915,
> > >       /* 0 reserved for invalid/unassigned ppgtt */
> > >       xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
> > >
> > > -     ctx = i915_gem_create_context(i915, 0);
> > > +     pc = proto_context_create(i915, 0);
> > > +     if (IS_ERR(pc)) {
> > > +             err = PTR_ERR(pc);
> > > +             goto err;
> > > +     }
> > > +
> > > +     ctx = i915_gem_create_context(i915, pc);
> > > +     proto_context_close(pc);
> > >       if (IS_ERR(ctx)) {
> > >               err = PTR_ERR(ctx);
> > >               goto err;
> > > @@ -1885,6 +1968,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > >  {
> > >       struct drm_i915_private *i915 = to_i915(dev);
> > >       struct drm_i915_gem_context_create_ext *args = data;
> > > +     struct i915_gem_proto_context *pc;
> > >       struct create_ext ext_data;
> > >       int ret;
> > >       u32 id;
> > > @@ -1907,7 +1991,12 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > >               return -EIO;
> > >       }
> > >
> > > -     ext_data.ctx = i915_gem_create_context(i915, args->flags);
> > > +     pc = proto_context_create(i915, args->flags);
> > > +     if (IS_ERR(pc))
> > > +             return PTR_ERR(pc);
> > > +
> > > +     ext_data.ctx = i915_gem_create_context(i915, pc);
> > > +     proto_context_close(pc);
> > >       if (IS_ERR(ext_data.ctx))
> > >               return PTR_ERR(ext_data.ctx);
> > >
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > index 5f0673a2129f9..0bf337b6d89ac 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > @@ -66,6 +66,28 @@ struct i915_gem_engines_iter {
> > >       const struct i915_gem_engines *engines;
> > >  };
> > >
> > > +/**
> > > + * struct i915_gem_proto_context - prototype context
> > > + *
> > > + * The struct i915_gem_proto_context represents the creation parameters for
> > > + * an i915_gem_context.  This is used to gather parameters provided either
> > > + * through creation flags or via SET_CONTEXT_PARAM so that, when we create
> > > + * the final i915_gem_context, those parameters can be immutable.
> > > + */
> > > +struct i915_gem_proto_context {
> > > +     /** @vm: See i915_gem_context::vm */
> > > +     struct i915_address_space *vm;
> > > +
> > > +     /** @user_flags: See i915_gem_context::user_flags */
> > > +     unsigned long user_flags;
> > > +
> > > +     /** @sched: See i915_gem_context::sched */
> > > +     struct i915_sched_attr sched;
> > > +
> > > +     /** @single_timeline: See See i915_gem_context::syncobj */
> > > +     bool single_timeline;
> > > +};
> > > +
> > >  /**
> > >   * struct i915_gem_context - client state
> > >   *
> > > diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > index 51b5a3421b400..e0f512ef7f3c6 100644
> > > --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > @@ -80,11 +80,17 @@ void mock_init_contexts(struct drm_i915_private *i915)
> > >  struct i915_gem_context *
> > >  live_context(struct drm_i915_private *i915, struct file *file)
> > >  {
> > > +     struct i915_gem_proto_context *pc;
> > >       struct i915_gem_context *ctx;
> > >       int err;
> > >       u32 id;
> > >
> > > -     ctx = i915_gem_create_context(i915, 0);
> > > +     pc = proto_context_create(i915, 0);
> > > +     if (IS_ERR(pc))
> > > +             return ERR_CAST(pc);
> > > +
> > > +     ctx = i915_gem_create_context(i915, pc);
> > > +     proto_context_close(pc);
> > >       if (IS_ERR(ctx))
> > >               return ctx;
> > >
> > > @@ -142,8 +148,14 @@ struct i915_gem_context *
> > >  kernel_context(struct drm_i915_private *i915)
> > >  {
> > >       struct i915_gem_context *ctx;
> > > +     struct i915_gem_proto_context *pc;
> > > +
> > > +     pc = proto_context_create(i915, 0);
> > > +     if (IS_ERR(pc))
> > > +             return ERR_CAST(pc);
> > >
> > > -     ctx = i915_gem_create_context(i915, 0);
> > > +     ctx = i915_gem_create_context(i915, pc);
> > > +     proto_context_close(pc);
> >
> > I think at large still looks pretty good, but some polish needed.
> > -Daniel
> >
> > >       if (IS_ERR(ctx))
> > >               return ctx;
> > >
> > > --
> > > 2.31.1
> > >
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 135+ messages in thread

* Re: [Intel-gfx] [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct
@ 2021-06-03  7:07         ` Daniel Vetter
  0 siblings, 0 replies; 135+ messages in thread
From: Daniel Vetter @ 2021-06-03  7:07 UTC (permalink / raw)
  To: Jason Ekstrand; +Cc: Intel GFX, Maling list - DRI developers

On Wed, Jun 2, 2021 at 11:53 PM Jason Ekstrand <jason@jlekstrand.net> wrote:
>
> On Tue, May 4, 2021 at 11:13 AM Daniel Vetter <daniel@ffwll.ch> wrote:
> >
> > On Mon, May 03, 2021 at 10:57:37AM -0500, Jason Ekstrand wrote:
> > > The current context uAPI allows for two methods of setting context
> > > parameters: SET_CONTEXT_PARAM and CONTEXT_CREATE_EXT_SETPARAM.  The
> > > former is allowed to be called at any time while the later happens as
> > > part of GEM_CONTEXT_CREATE.  Currently, everything settable via one is
> > > settable via the other.  While some params are fairly simple and setting
> > > them on a live context is harmless such the context priority, others are
> > > far trickier such as the VM or the set of engines.  In order to swap out
> > > the VM, for instance, we have to delay until all current in-flight work
> > > is complete, swap in the new VM, and then continue.  This leads to a
> > > plethora of potential race conditions we'd really rather avoid.
> > >
> > > Unfortunately, both methods of setting the VM and engine set are in
> > > active use today so we can't simply disallow setting the VM or engine
> > > set vial SET_CONTEXT_PARAM.  In order to work around this wart, this
> > > commit adds a proto-context struct which contains all the context create
> > > parameters.
> > >
> > > Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
> >
> > Per-patch changelog pls.
>
> Done.
>
> > > ---
> > >  drivers/gpu/drm/i915/gem/i915_gem_context.c   | 145 ++++++++++++++----
> > >  .../gpu/drm/i915/gem/i915_gem_context_types.h |  22 +++
> > >  .../gpu/drm/i915/gem/selftests/mock_context.c |  16 +-
> > >  3 files changed, 153 insertions(+), 30 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > index 4835991898ac9..10bd1b6dd1774 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
> > > @@ -191,6 +191,97 @@ static int validate_priority(struct drm_i915_private *i915,
> > >       return 0;
> > >  }
> > >
> > > +static void proto_context_close(struct i915_gem_proto_context *pc)
> > > +{
> > > +     if (pc->vm)
> > > +             i915_vm_put(pc->vm);
> > > +     kfree(pc);
> > > +}
> > > +
> > > +static int proto_context_set_persistence(struct drm_i915_private *i915,
> > > +                                      struct i915_gem_proto_context *pc,
> > > +                                      bool persist)
> > > +{
> > > +     if (persist) {
> > > +             /*
> > > +              * Only contexts that are short-lived [that will expire or be
> > > +              * reset] are allowed to survive past termination. We require
> > > +              * hangcheck to ensure that the persistent requests are healthy.
> > > +              */
> > > +             if (!i915->params.enable_hangcheck)
> > > +                     return -EINVAL;
> > > +
> > > +             __set_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> >
> > Ok so I looked, and the reason __set_bit and friends is for endless
> > bitfields, i.e. where user_flags is an actually dynamically sized array.
> >
> > Given that this is complete overkill I think fully open-coding the bitops
> > is the right bikeshed color choice. So
>
> I've fixed it now.  I had fixed it in the last version but it ended up
> squashed into the wrong patch. :-(
>
> >                 user_flags &= UCONTEXT_PERSISTENCE;
> >
> > > +     } else {
> > > +             /* To cancel a context we use "preempt-to-idle" */
> > > +             if (!(i915->caps.scheduler & I915_SCHEDULER_CAP_PREEMPTION))
> > > +                     return -ENODEV;
> > > +
> > > +             /*
> > > +              * If the cancel fails, we then need to reset, cleanly!
> > > +              *
> > > +              * If the per-engine reset fails, all hope is lost! We resort
> > > +              * to a full GPU reset in that unlikely case, but realistically
> > > +              * if the engine could not reset, the full reset does not fare
> > > +              * much better. The damage has been done.
> > > +              *
> > > +              * However, if we cannot reset an engine by itself, we cannot
> > > +              * cleanup a hanging persistent context without causing
> > > +              * colateral damage, and we should not pretend we can by
> > > +              * exposing the interface.
> > > +              */
> > > +             if (!intel_has_reset_engine(&i915->gt))
> > > +                     return -ENODEV;
> > > +
> > > +             __clear_bit(UCONTEXT_PERSISTENCE, &pc->user_flags);
> >
> >                 user_flags &= ~UCONTEXT_PERSISTENCE;
> >
> > Similar for all the others.
> >
> > > +     }
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static struct i915_gem_proto_context *
> > > +proto_context_create(struct drm_i915_private *i915, unsigned int flags)
> > > +{
> > > +     struct i915_gem_proto_context *pc, *err;
> > > +
> > > +     pc = kzalloc(sizeof(*pc), GFP_KERNEL);
> > > +     if (!pc)
> > > +             return ERR_PTR(-ENOMEM);
> > > +
> > > +     if (HAS_FULL_PPGTT(i915)) {
> > > +             struct i915_ppgtt *ppgtt;
> > > +
> > > +             ppgtt = i915_ppgtt_create(&i915->gt);
> > > +             if (IS_ERR(ppgtt)) {
> > > +                     drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> > > +                             PTR_ERR(ppgtt));
> > > +                     err = ERR_CAST(ppgtt);
> > > +                     goto proto_close;
> > > +             }
> > > +             pc->vm = &ppgtt->vm;
> >
> > I'm not understanding why we're creating the default vm as part of the
> > proto context? If we end up setting one this is kinda just wasted
> > conditionals, and we're not really gaining in code simplicity. It's just
> > whether we create the default vm here (and might need to delete it) or
> > when we finalize the context in i915_gem_create_context().
> >
> > Or am I missing something?
> >
> > If it's cleaner overall I'm ok with this, just feels a bit silly.
>
> Hrm... I guess there's no particularly good reason.  I think I did it
> this way because it seemed like a closer match to the code we had
> before.  Also, we need to do it this way if we want GET_CONTEXT_PARAM
> with CONTEXT_PARAM_VM to work on a proto-context without finalizing
> it.  However, in the end, I'm always finalizing contexts on
> GET_CONTEXT_PARAM so that's a non-reason.  I'll see what it looks like
> to move it.
>
> > > +     }
> > > +
> > > +     pc->user_flags = 0;
> > > +     __set_bit(UCONTEXT_BANNABLE, &pc->user_flags);
> > > +     __set_bit(UCONTEXT_RECOVERABLE, &pc->user_flags);
> > > +     proto_context_set_persistence(i915, pc, true);
> >
> > So this I think is another case of trying too hard to share code, because
> > what this essentially does is pick the default through a _very_ contrived
> > way:
> > - we start out with false since we kzalloc, so everything is cleared
> > - we try to enable persistence, but we fail silently, so if the module
> >   options don't allow persistence we silently keep it at false
>
> Yeah, it's pretty horrible.  It's a copy+paste of what was there
> before but that was terrible too.
>
> > I think open-coding this condition would be a lot better. Also disabling
> > hangcheck isn't a thing anymore, but we still have code in it.
> >
> > I think the right thing here is a patch which removes all occurences of
> > params.enable_hangcheck and replaces it with the default (which is true).
> >
> > And then just set this default here directly, because not doing so would
> > randomly break some mesa depending how a modparam is set which otherwise
> > has 0 impact. Also I think the other code which checks this could end up
> > with a refcount underrun on !execlist platforms.
>
> Yeah, I think this would make things clearer.  Before I go off and do
> that, it looks to me like the param still exists.  Maybe we just
> ignore it?  Should I delete the whole param?  Just trying to confirm
> before I go off and type the wrong code.

After more reading and talking with Tvrtko I realized that the
hangcheck modparam does actually do something still. So no ripping out
that modparam. I'm also wondering whether we should do an upfront
patch first, but then the bisect history for this proto-context is
nasty anyway, just highlighting the change in the commit message here
should be enough.
-Daniel

> --Jason
>
> > > +     pc->sched.priority = I915_PRIORITY_NORMAL;
> > > +
> > > +     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> > > +             if (!HAS_EXECLISTS(i915)) {
> > > +                     err = ERR_PTR(-EINVAL);
> > > +                     goto proto_close;
> > > +             }
> > > +             pc->single_timeline = true;
> > > +     }
> > > +
> > > +     return pc;
> > > +
> > > +proto_close:
> > > +     proto_context_close(pc);
> > > +     return err;
> > > +}
> > > +
> > >  static struct i915_address_space *
> > >  context_get_vm_rcu(struct i915_gem_context *ctx)
> > >  {
> > > @@ -660,7 +751,8 @@ static int __context_set_persistence(struct i915_gem_context *ctx, bool state)
> > >  }
> > >
> > >  static struct i915_gem_context *
> > > -__create_context(struct drm_i915_private *i915)
> > > +__create_context(struct drm_i915_private *i915,
> > > +              const struct i915_gem_proto_context *pc)
> > >  {
> > >       struct i915_gem_context *ctx;
> > >       struct i915_gem_engines *e;
> > > @@ -673,7 +765,7 @@ __create_context(struct drm_i915_private *i915)
> > >
> > >       kref_init(&ctx->ref);
> > >       ctx->i915 = i915;
> > > -     ctx->sched.priority = I915_PRIORITY_NORMAL;
> > > +     ctx->sched = pc->sched;
> > >       mutex_init(&ctx->mutex);
> > >       INIT_LIST_HEAD(&ctx->link);
> > >
> > > @@ -696,9 +788,7 @@ __create_context(struct drm_i915_private *i915)
> > >        * is no remap info, it will be a NOP. */
> > >       ctx->remap_slice = ALL_L3_SLICES(i915);
> > >
> > > -     i915_gem_context_set_bannable(ctx);
> > > -     i915_gem_context_set_recoverable(ctx);
> > > -     __context_set_persistence(ctx, true /* cgroup hook? */);
> > > +     ctx->user_flags = pc->user_flags;
> > >
> > >       for (i = 0; i < ARRAY_SIZE(ctx->hang_timestamp); i++)
> > >               ctx->hang_timestamp[i] = jiffies - CONTEXT_FAST_HANG_JIFFIES;
> > > @@ -786,38 +876,23 @@ static void __assign_ppgtt(struct i915_gem_context *ctx,
> > >  }
> > >
> > >  static struct i915_gem_context *
> > > -i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags)
> > > +i915_gem_create_context(struct drm_i915_private *i915,
> > > +                     const struct i915_gem_proto_context *pc)
> > >  {
> > >       struct i915_gem_context *ctx;
> > >       int ret;
> > >
> > > -     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE &&
> > > -         !HAS_EXECLISTS(i915))
> > > -             return ERR_PTR(-EINVAL);
> > > -
> > > -     ctx = __create_context(i915);
> > > +     ctx = __create_context(i915, pc);
> > >       if (IS_ERR(ctx))
> > >               return ctx;
> > >
> > > -     if (HAS_FULL_PPGTT(i915)) {
> > > -             struct i915_ppgtt *ppgtt;
> > > -
> > > -             ppgtt = i915_ppgtt_create(&i915->gt);
> > > -             if (IS_ERR(ppgtt)) {
> > > -                     drm_dbg(&i915->drm, "PPGTT setup failed (%ld)\n",
> > > -                             PTR_ERR(ppgtt));
> > > -                     context_close(ctx);
> > > -                     return ERR_CAST(ppgtt);
> > > -             }
> > > -
> > > +     if (pc->vm) {
> > >               mutex_lock(&ctx->mutex);
> > > -             __assign_ppgtt(ctx, &ppgtt->vm);
> > > +             __assign_ppgtt(ctx, pc->vm);
> > >               mutex_unlock(&ctx->mutex);
> > > -
> > > -             i915_vm_put(&ppgtt->vm);
> > >       }
> > >
> > > -     if (flags & I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE) {
> > > +     if (pc->single_timeline) {
> > >               ret = drm_syncobj_create(&ctx->syncobj,
> > >                                        DRM_SYNCOBJ_CREATE_SIGNALED,
> > >                                        NULL);
> > > @@ -883,6 +958,7 @@ int i915_gem_context_open(struct drm_i915_private *i915,
> > >                         struct drm_file *file)
> > >  {
> > >       struct drm_i915_file_private *file_priv = file->driver_priv;
> > > +     struct i915_gem_proto_context *pc;
> > >       struct i915_gem_context *ctx;
> > >       int err;
> > >       u32 id;
> > > @@ -892,7 +968,14 @@ int i915_gem_context_open(struct drm_i915_private *i915,
> > >       /* 0 reserved for invalid/unassigned ppgtt */
> > >       xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1);
> > >
> > > -     ctx = i915_gem_create_context(i915, 0);
> > > +     pc = proto_context_create(i915, 0);
> > > +     if (IS_ERR(pc)) {
> > > +             err = PTR_ERR(pc);
> > > +             goto err;
> > > +     }
> > > +
> > > +     ctx = i915_gem_create_context(i915, pc);
> > > +     proto_context_close(pc);
> > >       if (IS_ERR(ctx)) {
> > >               err = PTR_ERR(ctx);
> > >               goto err;
> > > @@ -1885,6 +1968,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > >  {
> > >       struct drm_i915_private *i915 = to_i915(dev);
> > >       struct drm_i915_gem_context_create_ext *args = data;
> > > +     struct i915_gem_proto_context *pc;
> > >       struct create_ext ext_data;
> > >       int ret;
> > >       u32 id;
> > > @@ -1907,7 +1991,12 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
> > >               return -EIO;
> > >       }
> > >
> > > -     ext_data.ctx = i915_gem_create_context(i915, args->flags);
> > > +     pc = proto_context_create(i915, args->flags);
> > > +     if (IS_ERR(pc))
> > > +             return PTR_ERR(pc);
> > > +
> > > +     ext_data.ctx = i915_gem_create_context(i915, pc);
> > > +     proto_context_close(pc);
> > >       if (IS_ERR(ext_data.ctx))
> > >               return PTR_ERR(ext_data.ctx);
> > >
> > > diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > index 5f0673a2129f9..0bf337b6d89ac 100644
> > > --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h
> > > @@ -66,6 +66,28 @@ struct i915_gem_engines_iter {
> > >       const struct i915_gem_engines *engines;
> > >  };
> > >
> > > +/**
> > > + * struct i915_gem_proto_context - prototype context
> > > + *
> > > + * The struct i915_gem_proto_context represents the creation parameters for
> > > + * an i915_gem_context.  This is used to gather parameters provided either
> > > + * through creation flags or via SET_CONTEXT_PARAM so that, when we create
> > > + * the final i915_gem_context, those parameters can be immutable.
> > > + */
> > > +struct i915_gem_proto_context {
> > > +     /** @vm: See i915_gem_context::vm */
> > > +     struct i915_address_space *vm;
> > > +
> > > +     /** @user_flags: See i915_gem_context::user_flags */
> > > +     unsigned long user_flags;
> > > +
> > > +     /** @sched: See i915_gem_context::sched */
> > > +     struct i915_sched_attr sched;
> > > +
> > > +     /** @single_timeline: See See i915_gem_context::syncobj */
> > > +     bool single_timeline;
> > > +};
> > > +
> > >  /**
> > >   * struct i915_gem_context - client state
> > >   *
> > > diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > index 51b5a3421b400..e0f512ef7f3c6 100644
> > > --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c
> > > @@ -80,11 +80,17 @@ void mock_init_contexts(struct drm_i915_private *i915)
> > >  struct i915_gem_context *
> > >  live_context(struct drm_i915_private *i915, struct file *file)
> > >  {
> > > +     struct i915_gem_proto_context *pc;
> > >       struct i915_gem_context *ctx;
> > >       int err;
> > >       u32 id;
> > >
> > > -     ctx = i915_gem_create_context(i915, 0);
> > > +     pc = proto_context_create(i915, 0);
> > > +     if (IS_ERR(pc))
> > > +             return ERR_CAST(pc);
> > > +
> > > +     ctx = i915_gem_create_context(i915, pc);
> > > +     proto_context_close(pc);
> > >       if (IS_ERR(ctx))
> > >               return ctx;
> > >
> > > @@ -142,8 +148,14 @@ struct i915_gem_context *
> > >  kernel_context(struct drm_i915_private *i915)
> > >  {
> > >       struct i915_gem_context *ctx;
> > > +     struct i915_gem_proto_context *pc;
> > > +
> > > +     pc = proto_context_create(i915, 0);
> > > +     if (IS_ERR(pc))
> > > +             return ERR_CAST(pc);
> > >
> > > -     ctx = i915_gem_create_context(i915, 0);
> > > +     ctx = i915_gem_create_context(i915, pc);
> > > +     proto_context_close(pc);
> >
> > I think at large still looks pretty good, but some polish needed.
> > -Daniel
> >
> > >       if (IS_ERR(ctx))
> > >               return ctx;
> > >
> > > --
> > > 2.31.1
> > >
> > > _______________________________________________
> > > dri-devel mailing list
> > > dri-devel@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 135+ messages in thread

end of thread, other threads:[~2021-06-03  7:07 UTC | newest]

Thread overview: 135+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-03 15:57 [PATCH 00/27] drm/i915/gem: ioctl clean-ups (v5) Jason Ekstrand
2021-05-03 15:57 ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 01/27] drm/i915: Drop I915_CONTEXT_PARAM_RINGSIZE Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 02/27] drm/i915: Stop storing the ring size in the ring pointer Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-04  8:47   ` Daniel Vetter
2021-05-04  8:47     ` [Intel-gfx] " Daniel Vetter
2021-05-14 18:06     ` Jason Ekstrand
2021-05-14 18:06       ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 03/27] drm/i915: Drop I915_CONTEXT_PARAM_NO_ZEROMAP Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-04  8:48   ` Daniel Vetter
2021-05-04  8:48     ` Daniel Vetter
2021-05-03 15:57 ` [PATCH 04/27] drm/i915/gem: Set the watchdog timeout directly in intel_context_set_gem (v2) Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 05/27] drm/i915/gem: Return void from context_apply_all Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 06/27] drm/i915: Drop the CONTEXT_CLONE API Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-04  8:50   ` Daniel Vetter
2021-05-04  8:50     ` Daniel Vetter
2021-05-14 18:07     ` Jason Ekstrand
2021-05-14 18:07       ` Jason Ekstrand
2021-05-03 15:57 ` [PATCH 07/27] drm/i915: Implement SINGLE_TIMELINE with a syncobj (v4) Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 08/27] drm/i915: Drop getparam support for I915_CONTEXT_PARAM_ENGINES Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 09/27] drm/i915/gem: Disallow bonding of virtual engines (v3) Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 10/27] drm/i915/gem: Remove engine auto-magic with FENCE_SUBMIT Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-04  8:56   ` Daniel Vetter
2021-05-04  8:56     ` [Intel-gfx] " Daniel Vetter
2021-05-14 18:19     ` Jason Ekstrand
2021-05-14 18:19       ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 11/27] drm/i915/request: Remove the hook from await_execution Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-04  8:55   ` Daniel Vetter
2021-05-04  8:55     ` [Intel-gfx] " Daniel Vetter
2021-05-03 15:57 ` [PATCH 12/27] drm/i915/gem: Disallow creating contexts with too many engines Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-05  9:56   ` Tvrtko Ursulin
2021-05-05  9:56     ` Tvrtko Ursulin
2021-05-03 15:57 ` [PATCH 13/27] drm/i915: Stop manually RCU banging in reset_stats_ioctl (v2) Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 14/27] drm/i915/gem: Add a separate validate_priority helper Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 15/27] drm/i915: Add gem/i915_gem_context.h to the docs Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-04  9:11   ` Daniel Vetter
2021-05-04  9:11     ` [Intel-gfx] " Daniel Vetter
2021-05-03 15:57 ` [PATCH 16/27] drm/i915/gem: Add an intermediate proto_context struct Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-04 16:13   ` Daniel Vetter
2021-05-04 16:13     ` [Intel-gfx] " Daniel Vetter
2021-06-02 21:53     ` Jason Ekstrand
2021-06-02 21:53       ` [Intel-gfx] " Jason Ekstrand
2021-06-03  7:07       ` Daniel Vetter
2021-06-03  7:07         ` [Intel-gfx] " Daniel Vetter
2021-05-05 10:09   ` Tvrtko Ursulin
2021-05-05 10:09     ` Tvrtko Ursulin
2021-05-03 15:57 ` [PATCH 17/27] drm/i915/gem: Rework error handling in default_engines Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-04 16:17   ` Daniel Vetter
2021-05-04 16:17     ` Daniel Vetter
2021-05-14 18:21     ` Jason Ekstrand
2021-05-14 18:21       ` Jason Ekstrand
2021-05-03 15:57 ` [PATCH 18/27] drm/i915/gem: Optionally set SSEU in intel_context_set_gem Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-04 19:00   ` Daniel Vetter
2021-05-04 19:00     ` Daniel Vetter
2021-05-05  9:28     ` Tvrtko Ursulin
2021-05-05  9:28       ` Tvrtko Ursulin
2021-05-05  9:47       ` Daniel Vetter
2021-05-05  9:47         ` Daniel Vetter
2021-05-05  9:52         ` Tvrtko Ursulin
2021-05-05  9:52           ` Tvrtko Ursulin
2021-05-03 15:57 ` [PATCH 19/27] drm/i915/gem: Use the proto-context to handle create parameters Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-04 20:33   ` Daniel Vetter
2021-05-04 20:33     ` [Intel-gfx] " Daniel Vetter
2021-05-14 19:13     ` Jason Ekstrand
2021-05-14 19:13       ` [Intel-gfx] " Jason Ekstrand
2021-05-17 13:40       ` Daniel Vetter
2021-05-17 13:40         ` [Intel-gfx] " Daniel Vetter
2021-05-17 17:04         ` Jason Ekstrand
2021-05-17 17:04           ` [Intel-gfx] " Jason Ekstrand
2021-05-17 18:44           ` Daniel Vetter
2021-05-17 18:44             ` [Intel-gfx] " Daniel Vetter
2021-05-18 10:51             ` Jani Nikula
2021-05-18 10:51               ` [Intel-gfx] " Jani Nikula
2021-05-03 15:57 ` [PATCH 20/27] drm/i915/gem: Return an error ptr from context_lookup Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 21/27] drm/i915/gt: Drop i915_address_space::file (v2) Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 15:57 ` [PATCH 22/27] drm/i915/gem: Delay context creation Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 19:38   ` kernel test robot
2021-05-03 19:38     ` kernel test robot
2021-05-03 19:38     ` kernel test robot
2021-05-04 20:53     ` Daniel Vetter
2021-05-04 20:53       ` Daniel Vetter
2021-05-04 20:53       ` Daniel Vetter
2021-05-04 20:53   ` Daniel Vetter
2021-05-04 20:53     ` Daniel Vetter
2021-05-03 15:57 ` [PATCH 23/27] drm/i915/gem: Don't allow changing the VM on running contexts Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-03 18:52   ` kernel test robot
2021-05-03 18:52     ` kernel test robot
2021-05-03 18:52     ` kernel test robot
2021-05-04 21:00     ` Daniel Vetter
2021-05-04 21:00       ` Daniel Vetter
2021-05-04 21:00       ` Daniel Vetter
2021-05-04 21:17   ` Daniel Vetter
2021-05-04 21:17     ` Daniel Vetter
2021-05-03 15:57 ` [PATCH 24/27] drm/i915/gem: Don't allow changing the engine set " Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-05  9:49   ` Daniel Vetter
2021-05-05  9:49     ` Daniel Vetter
2021-05-03 15:57 ` [PATCH 25/27] drm/i915/selftests: Take a VM in kernel_context() Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-05  9:50   ` Daniel Vetter
2021-05-05  9:50     ` [Intel-gfx] " Daniel Vetter
2021-05-03 15:57 ` [PATCH 26/27] i915/gem/selftests: Assign the VM at context creation in igt_shared_ctx_exec Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-05  9:53   ` Daniel Vetter
2021-05-05  9:53     ` Daniel Vetter
2021-05-03 15:57 ` [PATCH 27/27] drm/i915/gem: Roll all of context creation together Jason Ekstrand
2021-05-03 15:57   ` [Intel-gfx] " Jason Ekstrand
2021-05-05 10:05   ` Daniel Vetter
2021-05-05 10:05     ` Daniel Vetter
2021-05-03 20:33 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915/gem: ioctl clean-ups (rev4) Patchwork
2021-05-03 20:35 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2021-05-03 20:38 ` [Intel-gfx] ✗ Fi.CI.DOCS: " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.