diff mbox series

[v4,02/40] drm/gpuvm: Allow VAs to hold soft reference to BOs

Message ID 20250514175527.42488-3-robdclark@gmail.com
State Superseded
Headers show
Series drm/msm: sparse / "VM_BIND" support | expand

Commit Message

Rob Clark May 14, 2025, 5:53 p.m. UTC
From: Rob Clark <robdclark@chromium.org>

Eases migration for drivers where VAs don't hold hard references to
their associated BO, avoiding reference loops.

In particular, msm uses soft references to optimistically keep around
mappings until the BO is distroyed.  Which obviously won't work if the
VA (the mapping) is holding a reference to the BO.

By making this a per-VM flag, we can use normal hard-references for
mappings in a "VM_BIND" managed VM, but soft references in other cases,
such as kernel-internal VMs (for display scanout, etc).

Signed-off-by: Rob Clark <robdclark@chromium.org>
---
 drivers/gpu/drm/drm_gpuvm.c |  8 ++++++--
 include/drm/drm_gpuvm.h     | 12 ++++++++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

Comments

Rob Clark May 15, 2025, 5:34 p.m. UTC | #1
On Thu, May 15, 2025 at 8:30 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Thu, May 15, 2025 at 07:59:16AM -0700, Rob Clark wrote:
>
> Thanks for the detailed explanation!
>
> > On Thu, May 15, 2025 at 2:00 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > >
> > > On Wed, May 14, 2025 at 10:53:16AM -0700, Rob Clark wrote:
> > > > From: Rob Clark <robdclark@chromium.org>
> > > >
> > > > Eases migration for drivers where VAs don't hold hard references to
> > > > their associated BO, avoiding reference loops.
> > > >
> > > > In particular, msm uses soft references to optimistically keep around
> > > > mappings until the BO is distroyed.  Which obviously won't work if the
> > > > VA (the mapping) is holding a reference to the BO.
> > >
> > > Ick! This is all complicated enough. Allow drivers to bypass the proper
> > > reference counting for GEM objects in the context of VM_BO structures seems like
> > > an insane footgun.
> > >
> > > I don't understand why MSM would need weak references here. Why does msm need
> > > that, but nouveau, Xe, panthor, PowerVR do not?
> >
> > Most of those drivers were designed (and had their UABI designed) with
> > gpuvm, or at least sparse, in mind from the get go.  I'm not sure
> > about nouveau, but I guess it just got lucky that it's UABI semantics
> > fit having the VMA hold a reference to the BO.
> >
> > Unfortunately, msm pre-dates sparse.. and in the beginning there was
> > only a single global VM, multiple VMs was something retrofitted ~6yrs
> > (?) back.  For existing msm, the VMA(s) are implicitly torn down when
> > the GEM obj is freed.  This won't work with the VMA(s) holding hard
> > references to the BO.
>
> Ok, that makes sense to me, but why can't this be changed? I don't see how the
> uAPI would be affected, this is just an implementation detail, no?

It's about the behaviour of the API, there is no explicit VMA
creation/destruction in the uAPI.

> > When userspace opts-in to "VM_BIND" mode, which it has to do before
> > the VM is created, then we don't set this flag, the VMA holds a hard
> > reference to the BO as it does with other drivers.  But consider this
> > use-case, which is perfectly valid for old (existing) userspace:
> >
> > 1) Userspace creates a BO
> > 2) Submits rendering referencing the BO
> > 3) Immediately closes the BO handle, without waiting for the submit to complete
> >
> > In this case, the submit holds a reference to the BO which holds a
> > reference to the VMA.
>
> Can't you just instead create the VMAs, which hold a reference to the VM_BO,
> which holds a reference to the BO, then drop the drop the original BO reference
> and finally, when everything is completed, remove all VMAs of the VM_BO?

Perhaps the submit could hold a ref to the VM_BO instead of the BO to
cover that particular case.

But for the legacy world, the VMA is implicitly torn down when the BO
is freed.  Which will never happen if the VM_BO holds a reference to
the BO.

> This should do exactly the same *and* be conformant with GPUVM design.
>
> > Everything is torn down gracefully when the
> > submit completes.  But if the VMA held a hard reference to the BO then
> > you'd have a reference loop.
> >
> > So there really is no other way to use gpuvm _and_ maintain backwards
> > compatibility with the semantics of the pre-VM_BIND UAPI without this
> > flag.
>
> Again, how is this important for maintaining backwards compatibility with the
> uAPI? This all seems like a driver internal implementation detail to me.
>
> So, is there a technical reason, or is it more that it would be more effort on
> the driver end to rework things accordingly?

If there were a way to work without WEAK_REF, it seems like it would
be harder and much less of a drop in change.

BR,
-R

> > Fortunately DRM_GPUVM_VA_WEAK_REF is minimally intrusive.  Otherwise I
> > probably would have had to fork my own copy of gpuvm.
> >
> > BR,
> > -R
Danilo Krummrich May 15, 2025, 5:51 p.m. UTC | #2
On Thu, May 15, 2025 at 10:34:07AM -0700, Rob Clark wrote:
> On Thu, May 15, 2025 at 8:30 AM Danilo Krummrich <dakr@kernel.org> wrote:
> >
> > On Thu, May 15, 2025 at 07:59:16AM -0700, Rob Clark wrote:
> >
> > Thanks for the detailed explanation!
> >
> > > On Thu, May 15, 2025 at 2:00 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > > >
> > > > On Wed, May 14, 2025 at 10:53:16AM -0700, Rob Clark wrote:
> > > > > From: Rob Clark <robdclark@chromium.org>
> > > > >
> > > > > Eases migration for drivers where VAs don't hold hard references to
> > > > > their associated BO, avoiding reference loops.
> > > > >
> > > > > In particular, msm uses soft references to optimistically keep around
> > > > > mappings until the BO is distroyed.  Which obviously won't work if the
> > > > > VA (the mapping) is holding a reference to the BO.
> > > >
> > > > Ick! This is all complicated enough. Allow drivers to bypass the proper
> > > > reference counting for GEM objects in the context of VM_BO structures seems like
> > > > an insane footgun.
> > > >
> > > > I don't understand why MSM would need weak references here. Why does msm need
> > > > that, but nouveau, Xe, panthor, PowerVR do not?
> > >
> > > Most of those drivers were designed (and had their UABI designed) with
> > > gpuvm, or at least sparse, in mind from the get go.  I'm not sure
> > > about nouveau, but I guess it just got lucky that it's UABI semantics
> > > fit having the VMA hold a reference to the BO.
> > >
> > > Unfortunately, msm pre-dates sparse.. and in the beginning there was
> > > only a single global VM, multiple VMs was something retrofitted ~6yrs
> > > (?) back.  For existing msm, the VMA(s) are implicitly torn down when
> > > the GEM obj is freed.  This won't work with the VMA(s) holding hard
> > > references to the BO.
> >
> > Ok, that makes sense to me, but why can't this be changed? I don't see how the
> > uAPI would be affected, this is just an implementation detail, no?
> 
> It's about the behaviour of the API, there is no explicit VMA
> creation/destruction in the uAPI.

But that shouldn't matter? Userspace gives you a BO, the driver creates VMAs
itself, which can have a reference on the VM_BO, which references the original
BO. At this point you can drop the original reference of the BO and just destroy
all corresponding VMAs once the driver fulfilled the request from userspace?

> > > When userspace opts-in to "VM_BIND" mode, which it has to do before
> > > the VM is created, then we don't set this flag, the VMA holds a hard
> > > reference to the BO as it does with other drivers.  But consider this
> > > use-case, which is perfectly valid for old (existing) userspace:
> > >
> > > 1) Userspace creates a BO
> > > 2) Submits rendering referencing the BO
> > > 3) Immediately closes the BO handle, without waiting for the submit to complete
> > >
> > > In this case, the submit holds a reference to the BO which holds a
> > > reference to the VMA.
> >
> > Can't you just instead create the VMAs, which hold a reference to the VM_BO,
> > which holds a reference to the BO, then drop the drop the original BO reference
> > and finally, when everything is completed, remove all VMAs of the VM_BO?
> 
> Perhaps the submit could hold a ref to the VM_BO instead of the BO to
> cover that particular case.
> 
> But for the legacy world, the VMA is implicitly torn down when the BO
> is freed.  Which will never happen if the VM_BO holds a reference to
> the BO.

Sure, I get that; what I do not get is why it can't be changed, e.g. in the way
described above.

> > This should do exactly the same *and* be conformant with GPUVM design.
> >
> > > Everything is torn down gracefully when the
> > > submit completes.  But if the VMA held a hard reference to the BO then
> > > you'd have a reference loop.
> > >
> > > So there really is no other way to use gpuvm _and_ maintain backwards
> > > compatibility with the semantics of the pre-VM_BIND UAPI without this
> > > flag.
> >
> > Again, how is this important for maintaining backwards compatibility with the
> > uAPI? This all seems like a driver internal implementation detail to me.
> >
> > So, is there a technical reason, or is it more that it would be more effort on
> > the driver end to rework things accordingly?
> 
> If there were a way to work without WEAK_REF, it seems like it would
> be harder and much less of a drop in change.

So, you're saying there is no technical blocker to rework it?
Rob Clark May 15, 2025, 8:10 p.m. UTC | #3
On Thu, May 15, 2025 at 10:51 AM Danilo Krummrich <dakr@kernel.org> wrote:
>
> On Thu, May 15, 2025 at 10:34:07AM -0700, Rob Clark wrote:
> > On Thu, May 15, 2025 at 8:30 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > >
> > > On Thu, May 15, 2025 at 07:59:16AM -0700, Rob Clark wrote:
> > >
> > > Thanks for the detailed explanation!
> > >
> > > > On Thu, May 15, 2025 at 2:00 AM Danilo Krummrich <dakr@kernel.org> wrote:
> > > > >
> > > > > On Wed, May 14, 2025 at 10:53:16AM -0700, Rob Clark wrote:
> > > > > > From: Rob Clark <robdclark@chromium.org>
> > > > > >
> > > > > > Eases migration for drivers where VAs don't hold hard references to
> > > > > > their associated BO, avoiding reference loops.
> > > > > >
> > > > > > In particular, msm uses soft references to optimistically keep around
> > > > > > mappings until the BO is distroyed.  Which obviously won't work if the
> > > > > > VA (the mapping) is holding a reference to the BO.
> > > > >
> > > > > Ick! This is all complicated enough. Allow drivers to bypass the proper
> > > > > reference counting for GEM objects in the context of VM_BO structures seems like
> > > > > an insane footgun.
> > > > >
> > > > > I don't understand why MSM would need weak references here. Why does msm need
> > > > > that, but nouveau, Xe, panthor, PowerVR do not?
> > > >
> > > > Most of those drivers were designed (and had their UABI designed) with
> > > > gpuvm, or at least sparse, in mind from the get go.  I'm not sure
> > > > about nouveau, but I guess it just got lucky that it's UABI semantics
> > > > fit having the VMA hold a reference to the BO.
> > > >
> > > > Unfortunately, msm pre-dates sparse.. and in the beginning there was
> > > > only a single global VM, multiple VMs was something retrofitted ~6yrs
> > > > (?) back.  For existing msm, the VMA(s) are implicitly torn down when
> > > > the GEM obj is freed.  This won't work with the VMA(s) holding hard
> > > > references to the BO.
> > >
> > > Ok, that makes sense to me, but why can't this be changed? I don't see how the
> > > uAPI would be affected, this is just an implementation detail, no?
> >
> > It's about the behaviour of the API, there is no explicit VMA
> > creation/destruction in the uAPI.
>
> But that shouldn't matter? Userspace gives you a BO, the driver creates VMAs
> itself, which can have a reference on the VM_BO, which references the original
> BO. At this point you can drop the original reference of the BO and just destroy
> all corresponding VMAs once the driver fulfilled the request from userspace?

Having the submit hold a reference to the VM_BO, and then this funny
looking bit of code in gem_close() gets us part way there:

   vm_bo = drm_gpuvm_bo_find(ctx->vm, obj);
   if (vm_bo) {
      drm_gpuvm_bo_put(vm_bo);
      drm_gpuvm_bo_put(vm_bo);
  }

But we still leak BO's used in other VMs.. scanout, and various other
fw and other internal BOs... those would all have to be tracked down
and to find _someplace_ to break the VM_BO  circular reference loop.

> > > > When userspace opts-in to "VM_BIND" mode, which it has to do before
> > > > the VM is created, then we don't set this flag, the VMA holds a hard
> > > > reference to the BO as it does with other drivers.  But consider this
> > > > use-case, which is perfectly valid for old (existing) userspace:
> > > >
> > > > 1) Userspace creates a BO
> > > > 2) Submits rendering referencing the BO
> > > > 3) Immediately closes the BO handle, without waiting for the submit to complete
> > > >
> > > > In this case, the submit holds a reference to the BO which holds a
> > > > reference to the VMA.
> > >
> > > Can't you just instead create the VMAs, which hold a reference to the VM_BO,
> > > which holds a reference to the BO, then drop the drop the original BO reference
> > > and finally, when everything is completed, remove all VMAs of the VM_BO?
> >
> > Perhaps the submit could hold a ref to the VM_BO instead of the BO to
> > cover that particular case.
> >
> > But for the legacy world, the VMA is implicitly torn down when the BO
> > is freed.  Which will never happen if the VM_BO holds a reference to
> > the BO.
>
> Sure, I get that; what I do not get is why it can't be changed, e.g. in the way
> described above.
>
> > > This should do exactly the same *and* be conformant with GPUVM design.
> > >
> > > > Everything is torn down gracefully when the
> > > > submit completes.  But if the VMA held a hard reference to the BO then
> > > > you'd have a reference loop.
> > > >
> > > > So there really is no other way to use gpuvm _and_ maintain backwards
> > > > compatibility with the semantics of the pre-VM_BIND UAPI without this
> > > > flag.
> > >
> > > Again, how is this important for maintaining backwards compatibility with the
> > > uAPI? This all seems like a driver internal implementation detail to me.
> > >
> > > So, is there a technical reason, or is it more that it would be more effort on
> > > the driver end to rework things accordingly?
> >
> > If there were a way to work without WEAK_REF, it seems like it would
> > be harder and much less of a drop in change.
>
> So, you're saying there is no technical blocker to rework it?

Not clear.. it would certainly make conversion to gpuvm a much bigger
flag-day, because without WEAK_REF the way gpuvm works is exactly
backwards from how the thing it is replacing works.

BR,
-R
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c
index 1e89a98caad4..f1d521dc1fb0 100644
--- a/drivers/gpu/drm/drm_gpuvm.c
+++ b/drivers/gpu/drm/drm_gpuvm.c
@@ -1482,7 +1482,9 @@  drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm,
 
 	vm_bo->vm = drm_gpuvm_get(gpuvm);
 	vm_bo->obj = obj;
-	drm_gem_object_get(obj);
+
+	if (!(gpuvm->flags & DRM_GPUVM_VA_WEAK_REF))
+		drm_gem_object_get(obj);
 
 	kref_init(&vm_bo->kref);
 	INIT_LIST_HEAD(&vm_bo->list.gpuva);
@@ -1504,6 +1506,7 @@  drm_gpuvm_bo_destroy(struct kref *kref)
 	const struct drm_gpuvm_ops *ops = gpuvm->ops;
 	struct drm_gem_object *obj = vm_bo->obj;
 	bool lock = !drm_gpuvm_resv_protected(gpuvm);
+	bool unref = !(gpuvm->flags & DRM_GPUVM_VA_WEAK_REF);
 
 	if (!lock)
 		drm_gpuvm_resv_assert_held(gpuvm);
@@ -1522,7 +1525,8 @@  drm_gpuvm_bo_destroy(struct kref *kref)
 		kfree(vm_bo);
 
 	drm_gpuvm_put(gpuvm);
-	drm_gem_object_put(obj);
+	if (unref)
+		drm_gem_object_put(obj);
 }
 
 /**
diff --git a/include/drm/drm_gpuvm.h b/include/drm/drm_gpuvm.h
index 00d4e43b76b6..13ab087a45fa 100644
--- a/include/drm/drm_gpuvm.h
+++ b/include/drm/drm_gpuvm.h
@@ -205,10 +205,18 @@  enum drm_gpuvm_flags {
 	 */
 	DRM_GPUVM_RESV_PROTECTED = BIT(0),
 
+	/**
+	 * @DRM_GPUVM_VA_WEAK_REF:
+	 *
+	 * Flag indicating that the &drm_gpuva (or more correctly, the
+	 * &drm_gpuvm_bo) only holds a weak reference to the &drm_gem_object.
+	 */
+	DRM_GPUVM_VA_WEAK_REF = BIT(1),
+
 	/**
 	 * @DRM_GPUVM_USERBITS: user defined bits
 	 */
-	DRM_GPUVM_USERBITS = BIT(1),
+	DRM_GPUVM_USERBITS = BIT(2),
 };
 
 /**
@@ -651,7 +659,7 @@  struct drm_gpuvm_bo {
 
 	/**
 	 * @obj: The &drm_gem_object being mapped in @vm. This is a reference
-	 * counted pointer.
+	 * counted pointer, unless the &DRM_GPUVM_VA_WEAK_REF flag is set.
 	 */
 	struct drm_gem_object *obj;