Just cc'ing Danilo and Elliott, since I know we are starting to look at rust and ttm interactions, and these sort of lifetime/refcount fun might be something we need to solve in a rust compatible way.
On Tue, 7 Jul 2026 at 04:23, Christian König <[email protected]> wrote: > > On 7/6/26 19:01, Thomas Hellström wrote: > > On Mon, 2026-07-06 at 16:49 +0200, Christian König wrote: > >> On 7/6/26 15:14, Thomas Hellström wrote: > >>> On Fri, 2026-07-03 at 18:31 +0200, Natalie Vock wrote: > >>>> From: Christian König <[email protected]> > >>>> > >>>> Instead of keeping a separate reference count for the TTM object > >>>> also > >>>> use > >>>> the reference count for DRM GEM objects inside TTM. > >>>> > >>>> Apart from avoiding two reference counts for one object this > >>>> approach > >>>> has > >>>> the clear advantage of being able to use drm_exec inside TTM. > >>>> > >>>> v2: adjust XE assert as well and re-enable disabled test > >>>> v3: handle another case in i915 > >>>> v4: set GEM driver funcs of transfer BOs to point to the TTM free > >>>> callback (Natalie) > >>> > >>> I think the main review issue from the last time this was on the > >>> table > >>> was that we shouldn't resurrect the gem refcount. Apart from the > >>> risc > >>> of getting barriers wrong, both xe and IIRC i915 partly rely on the > >>> gem > >>> refcount never being resurrected and that callbacks for bos with > >>> zero > >>> gem refcount means that the gem part of the object is unusable. > >> > >> I've spend quite some time thinking about that and came to the > >> conclusion that this is actually harmless. > >> > >> The drivers shouldn't be able to see the resurected BO, except if > >> they go over the LRU list manually (which they shouldn't). > > > > The shrinker uses the TTM helpers for this. Basically the check needs > > to be ported to use the zombie interface but the present change also > > widens the window where we can't evict / shrink at all due to zero > > refcounts. > > > > While it might be made harmless, resurrecting a refcount like this is > > IMO not something that should leak into the gem refcount. Nobody else > > does this in the kernel tree. The bo in reality becomes a zombie once > > the gem refcount reaches zero. > > I don't really like the solution either, but I don't see much other option. > > >>> For example xe_bo.c: > >>> > >>> if (!xe_bo_is_xe_bo(bo) || !xe_bo_get_unless_zero(xe_bo)) > >>> return xe_bo_shrink_purge(ctx, bo, scanned); > >>> > >>> So IIRC the conclusion was when removing the ttm refcount we > >>> shouldn't > >>> attempt to resurrect the gem one. If the get_unless_zero() fails > >>> during > >>> evict walk, we simply find something to wait for. See previous > >>> discussion there. > >> > >> Yeah, I considered that as well but the problem is we often doesn't > >> have anything to wait on. > > > > That's not the conclusion of the previous discussion? > > > > https://lore.kernel.org/dri-devel/[email protected]/#r > > Well, I clearly rejected the idea to wait for the delayed delete worker > because that can cause deadlocks no matter how we do it. > > The only possibility I see is to grab a reference on the next busy fence and > wait for that to signal. > > But that approach still leaves a window open where the cleanup worker has not > yet cleaned up the resource before we try to allocate a new one. > > The only two possibilities I see to close that window are: > 1. Resurrect the GEM object. > 2. Keep a reference to the GEM object while it is on the LRU. > > I would really like to do #2 instead, but that requires that we distinct > between GEM object referenze and backing store reference. > > The GEM object does have some kind of backing store reference with the > handle_count field, but that unfortunately doesn't have the right semantic > (e.g. only goes from 0->1 when you actually create a handle etc..). > > >>> I fully support removing the ttm refcount, but not if it means > >>> resurrecting the gem refcount. > >>> > >>> If we want to sidestep that problem, in favour of getting the > >>> proposed > >>> locking functionality in and future proof it, I suggest using > >>> > >>> https://lore.kernel.org/all/[email protected]/ > >>> > >>> And rebase this series on that. This means we can use the ttm > >>> refcount > >>> for the transaction refcounting, and also that if we add a dma-buf > >>> map > >>> interface with a dma_resv_txn_obj, we could use that to also have > >>> exhaustive eviction that originates from a dma_buf map. > >> > >> I don't think that this is a good idea. It just adds another layer of > >> abstraction and doesn't solve the problem in any way possible. > > > > This comment confuses me. Exactly what problem isn't solved by this, > > and which of the stated benefits/use-cases in the cover-letter do you > > think aren't worthwhile? > > Of course could the drm_exec object work with different reference counters, > but as far as I can see that just complicates the situation and again creates > a TTM specific solutions which I clearly want to avoid. > > I would rather go with the resurrection approach instead, that has less > potential for problem I think. > > Alaternatively we could re-work the whole GEM refcount/GEM handle count/TTM > refcount mess, but that has even more potential to break. > > Regards, > Christian. > > > > > > Also for reference: (Section at the end and follow-up messages) > > https://lore.kernel.org/all/[email protected]/ > > > > Thanks, > > Thomas > > > > > >> Regards, > >> Christian. > >> > >>> > >>> /Thomas > >>> > >>>> > >>>> Signed-off-by: tChristian König <[email protected]> > >>>> Signed-off-by: Natalie Vock <[email protected]> > >>>> --- > >>>> drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 35 +++--- > >>>> drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c | 8 +- > >>>> drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c | 2 - > >>>> drivers/gpu/drm/ttm/ttm_bo.c | 135 > >>>> +++++++++++-- > >>>> ---------- > >>>> drivers/gpu/drm/ttm/ttm_bo_internal.h | 17 ++- > >>>> drivers/gpu/drm/ttm/ttm_bo_util.c | 15 ++- > >>>> drivers/gpu/drm/xe/xe_bo.c | 2 +- > >>>> include/drm/ttm/ttm_bo.h | 9 -- > >>>> 8 files changed, 111 insertions(+), 112 deletions(-) > >>>> > >>>> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > >>>> b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > >>>> index df3fcc2b1248e..642296602de69 100644 > >>>> --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > >>>> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c > >>>> @@ -939,7 +939,7 @@ void i915_ttm_adjust_lru(struct > >>>> drm_i915_gem_object *obj) > >>>> * Don't manipulate the TTM LRUs while in TTM bo > >>>> destruction. > >>>> * We're called through i915_ttm_delete_mem_notify(). > >>>> */ > >>>> - if (!kref_read(&bo->kref)) > >>>> + if (!kref_read(&bo->base.refcount)) > >>>> return; > >>>> > >>>> /* > >>>> @@ -957,30 +957,21 @@ void i915_ttm_adjust_lru(struct > >>>> drm_i915_gem_object *obj) > >>>> * > >>>> * TODO: consider maybe also bumping the shrinker list > >>>> here > >>>> when we have > >>>> * already unpinned it, which should give us something > >>>> more > >>>> like an LRU. > >>>> - * > >>>> - * TODO: There is a small window of opportunity for this > >>>> function to > >>>> - * get called from eviction after we've dropped the last > >>>> GEM > >>>> refcount, > >>>> - * but before the TTM deleted flag is set on the object. > >>>> Avoid > >>>> - * adjusting the shrinker list in such cases, since the > >>>> object is > >>>> - * not available to the shrinker anyway due to its zero > >>>> refcount. > >>>> - * To fix this properly we should move to a TTM shrinker > >>>> LRU > >>>> list for > >>>> - * these objects. > >>>> */ > >>>> - if (kref_get_unless_zero(&obj->base.refcount)) { > >>>> - if (shrinkable != obj->mm.ttm_shrinkable) { > >>>> - if (shrinkable) { > >>>> - if (obj->mm.madv == > >>>> I915_MADV_WILLNEED) > >>>> - > >>>> __i915_gem_object_make_s > >>>> hrinkable(obj); > >>>> - else > >>>> - > >>>> __i915_gem_object_make_p > >>>> urgeable(obj); > >>>> - } else { > >>>> - > >>>> i915_gem_object_make_unshrinkabl > >>>> e(obj); > >>>> - } > >>>> - > >>>> - obj->mm.ttm_shrinkable = shrinkable; > >>>> + i915_gem_object_get(obj); > >>>> + if (shrinkable != obj->mm.ttm_shrinkable) { > >>>> + if (shrinkable) { > >>>> + if (obj->mm.madv == I915_MADV_WILLNEED) > >>>> + __i915_gem_object_make_shrinkabl > >>>> e(ob > >>>> j); > >>>> + else > >>>> + __i915_gem_object_make_purgeable > >>>> (obj > >>>> ); > >>>> + } else { > >>>> + i915_gem_object_make_unshrinkable(obj); > >>>> } > >>>> - i915_gem_object_put(obj); > >>>> + > >>>> + obj->mm.ttm_shrinkable = shrinkable; > >>>> } > >>>> + i915_gem_object_put(obj); > >>>> > >>>> /* > >>>> * Put on the correct LRU list depending on the MADV > >>>> status > >>>> diff --git a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c > >>>> b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c > >>>> index 56ad8ef325840..904cb4da6c9b3 100644 > >>>> --- a/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c > >>>> +++ b/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c > >>>> @@ -127,7 +127,7 @@ static void > >>>> ttm_bo_init_reserved_sys_man(struct > >>>> kunit *test) > >>>> dma_resv_unlock(bo->base.resv); > >>>> > >>>> KUNIT_EXPECT_EQ(test, err, 0); > >>>> - KUNIT_EXPECT_EQ(test, kref_read(&bo->kref), 1); > >>>> + KUNIT_EXPECT_EQ(test, kref_read(&bo->base.refcount), 1); > >>>> KUNIT_EXPECT_PTR_EQ(test, bo->bdev, priv->ttm_dev); > >>>> KUNIT_EXPECT_EQ(test, bo->type, bo_type); > >>>> KUNIT_EXPECT_EQ(test, bo->page_alignment, PAGE_SIZE); > >>>> @@ -176,7 +176,7 @@ static void > >>>> ttm_bo_init_reserved_mock_man(struct > >>>> kunit *test) > >>>> dma_resv_unlock(bo->base.resv); > >>>> > >>>> KUNIT_EXPECT_EQ(test, err, 0); > >>>> - KUNIT_EXPECT_EQ(test, kref_read(&bo->kref), 1); > >>>> + KUNIT_EXPECT_EQ(test, kref_read(&bo->base.refcount), 1); > >>>> KUNIT_EXPECT_PTR_EQ(test, bo->bdev, priv->ttm_dev); > >>>> KUNIT_EXPECT_EQ(test, bo->type, bo_type); > >>>> KUNIT_EXPECT_EQ(test, ctx.bytes_moved, size); > >>>> @@ -969,6 +969,8 @@ static void > >>>> ttm_bo_validate_allowed_only_evict(struct kunit *test) > >>>> ttm_mock_manager_fini(priv->ttm_dev, mem_multihop); > >>>> } > >>>> > >>>> +extern const struct drm_gem_object_funcs > >>>> ttm_deleted_object_funcs; > >>>> + > >>>> static void ttm_bo_validate_deleted_evict(struct kunit *test) > >>>> { > >>>> struct ttm_operation_ctx ctx_init = { }, ctx_val = { }; > >>>> @@ -999,7 +1001,7 @@ static void > >>>> ttm_bo_validate_deleted_evict(struct > >>>> kunit *test) > >>>> KUNIT_EXPECT_EQ(test, ttm_resource_manager_usage(man), > >>>> big); > >>>> > >>>> dma_resv_unlock(bo_big->base.resv); > >>>> - bo_big->deleted = true; > >>>> + bo_big->base.funcs = &ttm_deleted_object_funcs; > >>>> > >>>> bo_small = ttm_bo_kunit_init(test, test->priv, small, > >>>> NULL); > >>>> bo_small->type = bo_type; > >>>> diff --git a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c > >>>> b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c > >>>> index 5cfe8f3f80d75..b7ab19e0e4b2b 100644 > >>>> --- a/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c > >>>> +++ b/drivers/gpu/drm/ttm/tests/ttm_kunit_helpers.c > >>>> @@ -189,8 +189,6 @@ struct ttm_buffer_object > >>>> *ttm_bo_kunit_init(struct kunit *test, > >>>> bo->bdev = devs->ttm_dev; > >>>> bo->destroy = dummy_ttm_bo_destroy; > >>>> > >>>> - kref_init(&bo->kref); > >>>> - > >>>> return bo; > >>>> } > >>>> EXPORT_SYMBOL_GPL(ttm_bo_kunit_init); > >>>> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c > >>>> b/drivers/gpu/drm/ttm/ttm_bo.c > >>>> index 3980f376e3ba4..2b470c1746f60 100644 > >>>> --- a/drivers/gpu/drm/ttm/ttm_bo.c > >>>> +++ b/drivers/gpu/drm/ttm/ttm_bo.c > >>>> @@ -246,88 +246,84 @@ static void ttm_bo_delayed_delete(struct > >>>> work_struct *work) > >>>> ttm_bo_put(bo); > >>>> } > >>>> > >>>> -static void ttm_bo_release(struct kref *kref) > >>>> +/* > >>>> + * All other callbacks should never ever be called on a deleted > >>>> TTM > >>>> object. > >>>> + */ > >>>> +const struct drm_gem_object_funcs ttm_deleted_object_funcs = { > >>>> + .free = ttm_bo_free > >>>> +}; > >>>> +EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_deleted_object_funcs); > >>>> + > >>>> +/* Returns true if the BO is about to get deleted */ > >>>> +static bool ttm_bo_is_zombie(struct ttm_buffer_object *bo) > >>>> +{ > >>>> + return bo->base.funcs == &ttm_deleted_object_funcs; > >>>> +} > >>>> + > >>>> +void ttm_bo_fini(struct ttm_buffer_object *bo) > >>>> { > >>>> - struct ttm_buffer_object *bo = > >>>> - container_of(kref, struct ttm_buffer_object, kref); > >>>> struct ttm_device *bdev = bo->bdev; > >>>> int ret; > >>>> > >>>> WARN_ON_ONCE(bo->pin_count); > >>>> WARN_ON_ONCE(bo->bulk_move); > >>>> > >>>> - if (!bo->deleted) { > >>>> - ret = ttm_bo_individualize_resv(bo); > >>>> - if (ret) { > >>>> - /* Last resort, if we fail to allocate > >>>> memory for the > >>>> - * fences block for the BO to become > >>>> idle > >>>> - */ > >>>> - dma_resv_wait_timeout(bo->base.resv, > >>>> - > >>>> DMA_RESV_USAGE_BOOKKEEP, false, > >>>> - 30 * HZ); > >>>> - } > >>>> + ret = ttm_bo_individualize_resv(bo); > >>>> + if (ret) { > >>>> + /* Last resort, if we fail to allocate memory > >>>> for > >>>> the > >>>> + * fences block for the BO to become idle > >>>> + */ > >>>> + dma_resv_wait_timeout(bo->base.resv, > >>>> DMA_RESV_USAGE_BOOKKEEP, > >>>> + false, 30 * HZ); > >>>> + } > >>>> > >>>> - if (bdev->funcs->release_notify) > >>>> - bdev->funcs->release_notify(bo); > >>>> + if (bo->bdev->funcs->release_notify) > >>>> + bo->bdev->funcs->release_notify(bo); > >>>> > >>>> - drm_vma_offset_remove(bdev->vma_manager, &bo- > >>>>> base.vma_node); > >>>> - ttm_mem_io_free(bdev, bo->resource); > >>>> + drm_vma_offset_remove(bdev->vma_manager, &bo- > >>>>> base.vma_node); > >>>> + ttm_mem_io_free(bdev, bo->resource); > >>>> > >>>> - if (!dma_resv_test_signaled(&bo->base._resv, > >>>> - > >>>> DMA_RESV_USAGE_BOOKKEEP) > >>>>>> > >>>> - (want_init_on_free() && (bo->ttm != NULL)) > >>>> || > >>>> - bo->type == ttm_bo_type_sg || > >>>> - !dma_resv_trylock(bo->base.resv)) { > >>>> - /* The BO is not idle, resurrect it for > >>>> delayed destroy */ > >>>> - ttm_bo_flush_all_fences(bo); > >>>> - bo->deleted = true; > >>>> + if (!dma_resv_test_signaled(&bo->base._resv, > >>>> DMA_RESV_USAGE_BOOKKEEP) || > >>>> + (want_init_on_free() && (bo->ttm != NULL)) || > >>>> + bo->type == ttm_bo_type_sg || > >>>> + !dma_resv_trylock(bo->base.resv)) { > >>>> + /* The BO is not idle, resurrect it for delayed > >>>> destroy */ > >>>> + ttm_bo_flush_all_fences(bo); > >>>> > >>>> - spin_lock(&bdev->lru_lock); > >>>> - > >>>> - /* > >>>> - * Make pinned bos immediately available > >>>> to > >>>> - * shrinkers, now that they are queued > >>>> for > >>>> - * destruction. > >>>> - * > >>>> - * FIXME: QXL is triggering this. Can be > >>>> removed when the > >>>> - * driver is fixed. > >>>> - */ > >>>> - if (bo->pin_count) { > >>>> - bo->pin_count = 0; > >>>> - > >>>> ttm_resource_move_to_lru_tail(bo- > >>>>> resource); > >>>> - } > >>>> + spin_lock(&bo->bdev->lru_lock); > >>>> > >>>> - kref_init(&bo->kref); > >>>> - spin_unlock(&bdev->lru_lock); > >>>> + /* > >>>> + * Make pinned bos immediately available to > >>>> + * shrinkers, now that they are queued for > >>>> + * destruction. > >>>> + * > >>>> + * FIXME: QXL is triggering this. Can be removed > >>>> when the > >>>> + * driver is fixed. > >>>> + */ > >>>> + if (bo->pin_count) { > >>>> + bo->pin_count = 0; > >>>> + ttm_resource_move_to_lru_tail(bo- > >>>>> resource); > >>>> + } > >>>> > >>>> - INIT_WORK(&bo->delayed_delete, > >>>> ttm_bo_delayed_delete); > >>>> + kref_init(&bo->base.refcount); > >>>> + bo->base.funcs = &ttm_deleted_object_funcs; > >>>> + spin_unlock(&bo->bdev->lru_lock); > >>>> > >>>> - /* Schedule the worker on the closest > >>>> NUMA > >>>> node. This > >>>> - * improves performance since system > >>>> memory > >>>> might be > >>>> - * cleared on free and that is best done > >>>> on > >>>> a CPU core > >>>> - * close to it. > >>>> - */ > >>>> - queue_work_node(bdev->pool.nid, bdev- > >>>>> wq, > >>>> &bo->delayed_delete); > >>>> - return; > >>>> - } > >>>> + INIT_WORK(&bo->delayed_delete, > >>>> ttm_bo_delayed_delete); > >>>> > >>>> + /* Schedule the worker on the closest NUMA node. > >>>> This > >>>> + * improves performance since system memory > >>>> might be > >>>> + * cleared on free and that is best done on a > >>>> CPU > >>>> core > >>>> + * close to it. > >>>> + */ > >>>> + queue_work_node(bdev->pool.nid, bdev->wq, &bo- > >>>>> delayed_delete); > >>>> + } else { > >>>> ttm_bo_cleanup_memtype_use(bo); > >>>> dma_resv_unlock(bo->base.resv); > >>>> - } > >>>> > >>>> - atomic_dec(&ttm_glob.bo_count); > >>>> - bo->destroy(bo); > >>>> -} > >>>> - > >>>> -/* TODO: remove! */ > >>>> -void ttm_bo_put(struct ttm_buffer_object *bo) > >>>> -{ > >>>> - kref_put(&bo->kref, ttm_bo_release); > >>>> -} > >>>> - > >>>> -void ttm_bo_fini(struct ttm_buffer_object *bo) > >>>> -{ > >>>> - ttm_bo_put(bo); > >>>> + atomic_dec(&ttm_glob.bo_count); > >>>> + bo->destroy(bo); > >>>> + } > >>>> } > >>>> EXPORT_SYMBOL(ttm_bo_fini); > >>>> > >>>> @@ -470,7 +466,7 @@ int ttm_bo_evict_first(struct ttm_device > >>>> *bdev, > >>>> struct ttm_resource_manager *man > >>>> if (!bo->resource || bo->resource->mem_type != mem_type) > >>>> goto out_bo_moved; > >>>> > >>>> - if (bo->deleted) { > >>>> + if (ttm_bo_is_zombie(bo)) { > >>>> ret = ttm_bo_wait_ctx(bo, ctx); > >>>> if (!ret) > >>>> ttm_bo_cleanup_memtype_use(bo); > >>>> @@ -524,7 +520,7 @@ static s64 ttm_bo_evict_cb(struct > >>>> ttm_lru_walk > >>>> *walk, struct ttm_buffer_object * > >>>> if (bo->pin_count || !bo->bdev->funcs- > >>>>> eviction_valuable(bo, > >>>> evict_walk->place)) > >>>> return 0; > >>>> > >>>> - if (bo->deleted) { > >>>> + if (ttm_bo_is_zombie(bo)) { > >>>> lret = ttm_bo_wait_ctx(bo, walk->arg.ctx); > >>>> if (!lret) > >>>> ttm_bo_cleanup_memtype_use(bo); > >>>> @@ -624,7 +620,6 @@ static int ttm_bo_evict_alloc(struct > >>>> ttm_device > >>>> *bdev, > >>>> void ttm_bo_pin(struct ttm_buffer_object *bo) > >>>> { > >>>> dma_resv_assert_held(bo->base.resv); > >>>> - WARN_ON_ONCE(!kref_read(&bo->kref)); > >>>> spin_lock(&bo->bdev->lru_lock); > >>>> if (bo->resource) > >>>> ttm_resource_del_bulk_move(bo->resource, bo); > >>>> @@ -643,7 +638,6 @@ EXPORT_SYMBOL(ttm_bo_pin); > >>>> void ttm_bo_unpin(struct ttm_buffer_object *bo) > >>>> { > >>>> dma_resv_assert_held(bo->base.resv); > >>>> - WARN_ON_ONCE(!kref_read(&bo->kref)); > >>>> if (WARN_ON_ONCE(!bo->pin_count)) > >>>> return; > >>>> > >>>> @@ -934,7 +928,6 @@ int ttm_bo_init_reserved(struct ttm_device > >>>> *bdev, > >>>> struct ttm_buffer_object *bo, > >>>> { > >>>> int ret; > >>>> > >>>> - kref_init(&bo->kref); > >>>> bo->bdev = bdev; > >>>> bo->type = type; > >>>> bo->page_alignment = alignment; > >>>> @@ -1131,8 +1124,8 @@ ttm_bo_swapout_cb(struct ttm_lru_walk > >>>> *walk, > >>>> struct ttm_buffer_object *bo) > >>>> goto out; > >>>> } > >>>> > >>>> - if (bo->deleted) { > >>>> - pgoff_t num_pages = tt->num_pages; > >>>> + if (ttm_bo_is_zombie(bo)) { > >>>> + pgoff_t num_pages = bo->ttm->num_pages; > >>>> > >>>> ret = ttm_bo_wait_ctx(bo, ctx); > >>>> if (ret) > >>>> diff --git a/drivers/gpu/drm/ttm/ttm_bo_internal.h > >>>> b/drivers/gpu/drm/ttm/ttm_bo_internal.h > >>>> index e0d48eac74b03..ded2a47be0bcb 100644 > >>>> --- a/drivers/gpu/drm/ttm/ttm_bo_internal.h > >>>> +++ b/drivers/gpu/drm/ttm/ttm_bo_internal.h > >>>> @@ -27,6 +27,14 @@ > >>>> > >>>> #include <drm/ttm/ttm_bo.h> > >>>> > >>>> +static inline void ttm_bo_free(struct drm_gem_object *gobj) > >>>> +{ > >>>> + struct ttm_buffer_object *bo = container_of(gobj, > >>>> typeof(*bo), base); > >>>> + > >>>> + atomic_dec(&ttm_glob.bo_count); > >>>> + bo->destroy(bo); > >>>> +} > >>>> + > >>>> /** > >>>> * ttm_bo_get - reference a struct ttm_buffer_object > >>>> * > >>>> @@ -34,7 +42,7 @@ > >>>> */ > >>>> static inline void ttm_bo_get(struct ttm_buffer_object *bo) > >>>> { > >>>> - kref_get(&bo->kref); > >>>> + drm_gem_object_get(&bo->base); > >>>> } > >>>> > >>>> /** > >>>> @@ -50,11 +58,14 @@ static inline void ttm_bo_get(struct > >>>> ttm_buffer_object *bo) > >>>> static inline __must_check struct ttm_buffer_object * > >>>> ttm_bo_get_unless_zero(struct ttm_buffer_object *bo) > >>>> { > >>>> - if (!kref_get_unless_zero(&bo->kref)) > >>>> + if (!kref_get_unless_zero(&bo->base.refcount)) > >>>> return NULL; > >>>> return bo; > >>>> } > >>>> > >>>> -void ttm_bo_put(struct ttm_buffer_object *bo); > >>>> +static inline void ttm_bo_put(struct ttm_buffer_object *bo) > >>>> +{ > >>>> + drm_gem_object_put(&bo->base); > >>>> +} > >>>> > >>>> #endif > >>>> diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c > >>>> b/drivers/gpu/drm/ttm/ttm_bo_util.c > >>>> index 3e3c201a02226..7ed085adf1c9b 100644 > >>>> --- a/drivers/gpu/drm/ttm/ttm_bo_util.c > >>>> +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c > >>>> @@ -41,6 +41,18 @@ > >>>> > >>>> #include "ttm_bo_internal.h" > >>>> > >>>> +static void ttm_transfer_object_free(struct drm_gem_object *obj) > >>>> +{ > >>>> + struct ttm_buffer_object *bo = > >>>> + container_of(obj, struct ttm_buffer_object, > >>>> base); > >>>> + > >>>> + ttm_bo_fini(bo); > >>>> +} > >>>> + > >>>> +const struct drm_gem_object_funcs ttm_transfer_object_funcs = { > >>>> + .free = ttm_transfer_object_free, > >>>> +}; > >>>> + > >>>> struct ttm_transfer_obj { > >>>> struct ttm_buffer_object base; > >>>> struct ttm_buffer_object *bo; > >>>> @@ -247,7 +259,8 @@ static int ttm_buffer_object_transfer(struct > >>>> ttm_buffer_object *bo, > >>>> atomic_inc(&ttm_glob.bo_count); > >>>> drm_vma_node_reset(&fbo->base.base.vma_node); > >>>> > >>>> - kref_init(&fbo->base.kref); > >>>> + kref_init(&fbo->base.base.refcount); > >>>> + fbo->base.base.funcs = &ttm_transfer_object_funcs; > >>>> fbo->base.destroy = &ttm_transfered_destroy; > >>>> fbo->base.pin_count = 0; > >>>> if (bo->type != ttm_bo_type_sg) > >>>> diff --git a/drivers/gpu/drm/xe/xe_bo.c > >>>> b/drivers/gpu/drm/xe/xe_bo.c > >>>> index 85e6d9a0f575b..5843f850339c7 100644 > >>>> --- a/drivers/gpu/drm/xe/xe_bo.c > >>>> +++ b/drivers/gpu/drm/xe/xe_bo.c > >>>> @@ -1651,7 +1651,7 @@ static bool > >>>> xe_ttm_bo_lock_in_destructor(struct > >>>> ttm_buffer_object *ttm_bo) > >>>> struct xe_device *xe = ttm_to_xe_device(ttm_bo->bdev); > >>>> bool locked; > >>>> > >>>> - xe_assert(xe, !kref_read(&ttm_bo->kref)); > >>>> + xe_assert(xe, !kref_read(&ttm_bo->base.refcount)); > >>>> > >>>> /* > >>>> * We can typically only race with TTM trylocking under > >>>> the > >>>> diff --git a/include/drm/ttm/ttm_bo.h b/include/drm/ttm/ttm_bo.h > >>>> index 8310bc3d55f90..1eae9eea5ff32 100644 > >>>> --- a/include/drm/ttm/ttm_bo.h > >>>> +++ b/include/drm/ttm/ttm_bo.h > >>>> @@ -78,11 +78,8 @@ enum ttm_bo_type { > >>>> * @type: The bo type. > >>>> * @page_alignment: Page alignment. > >>>> * @destroy: Destruction function. If NULL, kfree is used. > >>>> - * @kref: Reference count of this buffer object. When this > >>>> refcount > >>>> reaches > >>>> - * zero, the object is destroyed or put on the delayed delete > >>>> list. > >>>> * @resource: structure describing current placement. > >>>> * @ttm: TTM structure holding system pages. > >>>> - * @deleted: True if the object is only a zombie and already > >>>> deleted. > >>>> * @bulk_move: The bulk move object. > >>>> * @priority: Priority for LRU, BOs with lower priority are > >>>> evicted > >>>> first. > >>>> * @pin_count: Pin count. > >>>> @@ -109,17 +106,11 @@ struct ttm_buffer_object { > >>>> uint32_t page_alignment; > >>>> void (*destroy) (struct ttm_buffer_object *); > >>>> > >>>> - /* > >>>> - * Members not needing protection. > >>>> - */ > >>>> - struct kref kref; > >>>> - > >>>> /* > >>>> * Members protected by the bo::resv::reserved lock. > >>>> */ > >>>> struct ttm_resource *resource; > >>>> struct ttm_tt *ttm; > >>>> - bool deleted; > >>>> struct ttm_lru_bulk_move *bulk_move; > >>>> unsigned priority; > >>>> unsigned pin_count; >
