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.
next prev 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 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.