Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: "Danilo Krummrich" <dakr@kernel.org>
To: "Matthew Brost" <matthew.brost@intel.com>
Cc: intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Boris Brezillon" <boris.brezillon@collabora.com>,
	"David Airlie" <airlied@gmail.com>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Liviu Dudau" <liviu.dudau@arm.com>,
	"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
	"Maxime Ripard" <mripard@kernel.org>,
	"Rodrigo Vivi" <rodrigo.vivi@intel.com>,
	"Shuah Khan" <skhan@linuxfoundation.org>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Steven Price" <steven.price@arm.com>,
	"Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
	"Thomas Zimmermann" <tzimmermann@suse.de>
Subject: Re: [PATCH 1/3] drm/gpuvm: allow locking external objects in two passes
Date: Thu, 01 Oct 2026 13:46:52 +0200	[thread overview]
Message-ID: <DLTH6V7D5VNW.TD696VJNM98E@kernel.org> (raw)
In-Reply-To: <20260814073258.893007-2-matthew.brost@intel.com>

On Fri Aug 14, 2026 at 9:32 AM CEST, Matthew Brost wrote:
> So let a driver set drm_gpuvm_exec::two_pass and have
> drm_gpuvm_exec_lock() acquire its locks in two steps:
>
>   DRM_GPUVM_EXEC_PASS_EARLY validates what the transaction already
>   holds. The GPUVM's own dma-resv is locked from the start, so that is
>   every private object, and the driver validates the evicted ones. The
>   pass also opportunistically locks the external objects which are
>   evicted, since those need validating anyway, and the driver validates
>   those too. The resident external objects are left unlocked, then
>
>   DRM_GPUVM_EXEC_PASS_LATE locks everything else, i.e. exactly what the
>   early pass left out. The driver validates anything which raced with
>   the early pass and does whatever needs every lock held, such as
>   attaching its job's fence.
>
> Both passes share one drm_exec transaction. The early pass keeps
> everything it locked and the late pass only ever adds to it, so there is
> no window in which another thread can undo the early pass' work, and no
> recheck or retry logic is needed. The extra.fn callback is invoked once
> per pass, with drm_gpuvm_exec::pass telling it which one it is in.
>
> Only the external objects are divided up like this. The passes have to
> agree on which objects belong to which, and the GPUVM's common dma-resv
> is what gives that, so it is held throughout.

That's a nice optimization!

> The early pass reads drm_gpuvm_bo::evicted without holding the object's
> dma-resv, that being the lock it is trying not to take. The race is
> benign: an object evicted just after being skipped is validated by the
> late pass instead, exactly as if it had been evicted a moment later
> still.

I only read this after I stumbled across this in the code below.  Leaving this
as-is is still a data race per LKMM and I'd expect KCSAN to flag it.

In any case, please also add the corresponding WRITE_ONCE() as well as a comment
that explains why in this specific case it is OK to read the value without the
dma-resv lock held and why ordering is not an issue.

> Two pass locking requires a DRM_GPUVM_RESV_PROTECTED drm_gpuvm.

This is unfortunate, I don't want to have any second class citizens.

That said, I think I can make nouveau switch to DRM_GPUVM_RESV_PROTECTED. With
this, only MSM is left, and it says

	* We mostly want to use DRM_GPUVM_RESV_PROTECTED, except that
	* makes drm_gpuvm_bo_evict() a no-op for extobjs (ie. we loose
	* tracking that an extobj is evicted) :facepalm:

which is probably similar to why nouveau didn't do it in the first place. I
could have a look after LPC so we can get rid of !DRM_GPUVM_RESV_PROTECTED
entirely, which I think would be great.

> Assisted-by: GitHub_Copilot:claude-opus-5

Please use Assisted-by: LLM instead.

> +/**
> + * DOC: Two pass locking

I think this should say that this is about "preparing" objects and object
validation.

Maybe "GPUVM EXEC two-pass locking"?

> +static bool
> +drm_gpuvm_prepare_skip(struct drm_gpuvm_bo *vm_bo,
> +		       enum drm_gpuvm_exec_pass pass)
> +{
> +	drm_gpuvm_pass_assert_held(vm_bo->vm, pass);
> +
> +	switch (pass) {
> +	case DRM_GPUVM_EXEC_PASS_EARLY:
> +		vm_bo->lock_skipped = !READ_ONCE(vm_bo->evicted);

Ick! Not a huge fan of this, but I guess it makes sense. AFAICS this can race
with drm_gpuvm_bo_evict() though.

> +int
> +drm_gpuvm_prepare_objects_pass(struct drm_gpuvm *gpuvm,
> +			       struct drm_exec *exec,
> +			       unsigned int num_fences,
> +			       enum drm_gpuvm_exec_pass pass)
> +{
> +	if (pass != DRM_GPUVM_EXEC_PASS_ALL &&
> +	    drm_WARN_ON(gpuvm->drm, !drm_gpuvm_resv_protected(gpuvm)))

drm_WARN_ON_ONCE() seems to make more sense here.

> @@ -1360,6 +1603,10 @@ drm_gpuvm_exec_lock(struct drm_gpuvm_exec *vm_exec)
>  	unsigned int num_fences = vm_exec->num_fences;
>  	int ret;
>  
> +	if (vm_exec->two_pass &&
> +	    drm_WARN_ON(gpuvm->drm, !drm_gpuvm_resv_protected(gpuvm)))

Same here...

> @@ -1422,6 +1680,9 @@ drm_gpuvm_exec_lock_array(struct drm_gpuvm_exec *vm_exec,
>  		unsigned int num_objs;
>  	} args;
>  
> +	if (drm_WARN_ON(vm_exec->vm->drm, vm_exec->two_pass))

...and here.

> +int
> +drm_gpuvm_validate_pass(struct drm_gpuvm *gpuvm, struct drm_exec *exec,
> +			enum drm_gpuvm_exec_pass pass)
>  {
>  	const struct drm_gpuvm_ops *ops = gpuvm->ops;
>  
>  	if (unlikely(!ops || !ops->vm_bo_validate))
>  		return -EOPNOTSUPP;
>  
> +	if (pass != DRM_GPUVM_EXEC_PASS_ALL &&
> +	    drm_WARN_ON(gpuvm->drm, !drm_gpuvm_resv_protected(gpuvm)))

That's really a lot of !drm_gpuvm_resv_protected() checks needed. :(

> +bool
> +drm_gpuvm_has_evicted(struct drm_gpuvm *gpuvm, enum drm_gpuvm_exec_pass pass)

The name is a bit confusing, as the scope of the function is limited to an
exec_pass, but not the VM in general.

Even though a bit verbose, I think drm_gpuvm_exec_pass_has_evicted() is better.
I'd probably also use the drm_gpuvm_exec_pass prefiy consistently for the
functions newly introduced for the feature.

> @@ -680,6 +799,18 @@ struct drm_gpuvm_bo {
>  	 */
>  	bool evicted;
>  
> +	/**
> +	 * @lock_skipped: Indicates that the current &drm_exec transaction does
> +	 * not hold this &drm_gpuvm_bo's dma-resv, because
> +	 * %DRM_GPUVM_EXEC_PASS_EARLY skipped it as not needing validation.
> +	 * Unlike @evicted this is stable for the duration of a locking
> +	 * sequence, which is what makes it safe for drm_gpuvm_validate_pass()
> +	 * to key off, and what tells %DRM_GPUVM_EXEC_PASS_LATE which objects
> +	 * are still missing. Field protected the same way as the &drm_gpuvm's
> +	 * extobj list.
> +	 */
> +	bool lock_skipped;

That's a bit nasty, but it works and I can't think of a cleaner solution.

  parent reply	other threads:[~2026-10-01 11:47 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-14  7:32 [PATCH 0/3] drm/gpuvm: two pass locking for exec Matthew Brost
2026-08-14  7:32 ` [PATCH 1/3] drm/gpuvm: allow locking external objects in two passes Matthew Brost
2026-08-14  7:51   ` sashiko-bot
2026-08-14  8:18     ` Matthew Brost
2026-09-11 10:44   ` Liviu Dudau
2026-10-01 11:46   ` Danilo Krummrich [this message]
2026-08-14  7:32 ` [PATCH 2/3] drm/xe: lock the resident BOs of an exec last Matthew Brost
2026-10-01  9:55   ` Francois Dugast
2026-08-14  7:32 ` [PATCH 3/3] drm/panthor: lock the resident BOs of a submit last Matthew Brost
2026-09-11 10:47   ` Liviu Dudau
2026-08-14  7:49 ` ✓ CI.KUnit: success for drm/gpuvm: two pass locking for exec Patchwork
2026-08-14  8:57 ` ✓ Xe.CI.BAT: " Patchwork
2026-08-14 10:58 ` ✓ Xe.CI.FULL: " Patchwork
     [not found] ` <c87a906a82dcce2c52352a2796e21cc9037c71b3.camel@linux.intel.com>
     [not found]   ` <an+Mzd5xuu0KHxhE@gsse-cloud1.jf.intel.com>
     [not found]     ` <09b2029f7942c997c9355508b1f757f8731a9ad5.camel@linux.intel.com>
2026-08-18 21:44       ` [PATCH 0/3] " Matthew Brost

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DLTH6V7D5VNW.TD696VJNM98E@kernel.org \
    --to=dakr@kernel.org \
    --cc=airlied@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=boris.brezillon@collabora.com \
    --cc=corbet@lwn.net \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=liviu.dudau@arm.com \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=matthew.brost@intel.com \
    --cc=mripard@kernel.org \
    --cc=rodrigo.vivi@intel.com \
    --cc=simona@ffwll.ch \
    --cc=skhan@linuxfoundation.org \
    --cc=steven.price@arm.com \
    --cc=thomas.hellstrom@linux.intel.com \
    --cc=tzimmermann@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox