Commit 541c8f24 authored by Christian König's avatar Christian König
Browse files

dma-buf: detach fence ops on signal v3



When neither a release nor a wait backend ops is specified it is possible
to let the dma_fence live on independently of the module who issued it.

This makes it possible to unload drivers and only wait for all their
fences to signal.

v2: fix typo in comment
v3: fix sparse rcu warnings

Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Reviewed-by: default avatarTvrtko Ursulin <tvrtko.ursulin@igalia.com>
Reviewed-by: default avatarPhilipp Stanner <phasta@kernel.org>
Reviewed-by: default avatarBoris Brezillon <boris.brezillon@collabora.com>
Link: https://lore.kernel.org/r/20260219160822.1529-3-christian.koenig@amd.com
parent f4cc3ab8
Loading
Loading
Loading
Loading
+14 −4
Original line number Diff line number Diff line
@@ -362,6 +362,7 @@ void __dma_fence_might_wait(void)
void dma_fence_signal_timestamp_locked(struct dma_fence *fence,
				      ktime_t timestamp)
{
	const struct dma_fence_ops *ops;
	struct dma_fence_cb *cur, *tmp;
	struct list_head cb_list;

@@ -371,6 +372,15 @@ void dma_fence_signal_timestamp_locked(struct dma_fence *fence,
				      &fence->flags)))
		return;

	/*
	 * When neither a release nor a wait operation is specified set the ops
	 * pointer to NULL to allow the fence structure to become independent
	 * from who originally issued it.
	 */
	ops = rcu_dereference_protected(fence->ops, true);
	if (!ops->release && !ops->wait)
		RCU_INIT_POINTER(fence->ops, NULL);

	/* Stash the cb_list before replacing it with the timestamp */
	list_replace(&fence->cb_list, &cb_list);

@@ -537,7 +547,7 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout)
	rcu_read_lock();
	ops = rcu_dereference(fence->ops);
	trace_dma_fence_wait_start(fence);
	if (ops->wait) {
	if (ops && ops->wait) {
		/*
		 * Implementing the wait ops is deprecated and not supported for
		 * issuers of fences who need their lifetime to be independent
@@ -603,7 +613,7 @@ void dma_fence_release(struct kref *kref)
	}

	ops = rcu_dereference(fence->ops);
	if (ops->release)
	if (ops && ops->release)
		ops->release(fence);
	else
		dma_fence_free(fence);
@@ -639,7 +649,7 @@ static bool __dma_fence_enable_signaling(struct dma_fence *fence)

	rcu_read_lock();
	ops = rcu_dereference(fence->ops);
	if (!was_set && ops->enable_signaling) {
	if (!was_set && ops && ops->enable_signaling) {
		trace_dma_fence_enable_signal(fence);

		if (!ops->enable_signaling(fence)) {
@@ -1025,7 +1035,7 @@ void dma_fence_set_deadline(struct dma_fence *fence, ktime_t deadline)

	rcu_read_lock();
	ops = rcu_dereference(fence->ops);
	if (ops->set_deadline && !dma_fence_is_signaled(fence))
	if (ops && ops->set_deadline && !dma_fence_is_signaled(fence))
		ops->set_deadline(fence, deadline);
	rcu_read_unlock();
}
+2 −2
Original line number Diff line number Diff line
@@ -472,7 +472,7 @@ dma_fence_is_signaled_locked(struct dma_fence *fence)

	rcu_read_lock();
	ops = rcu_dereference(fence->ops);
	if (ops->signaled && ops->signaled(fence)) {
	if (ops && ops->signaled && ops->signaled(fence)) {
		rcu_read_unlock();
		dma_fence_signal_locked(fence);
		return true;
@@ -508,7 +508,7 @@ dma_fence_is_signaled(struct dma_fence *fence)

	rcu_read_lock();
	ops = rcu_dereference(fence->ops);
	if (ops->signaled && ops->signaled(fence)) {
	if (ops && ops->signaled && ops->signaled(fence)) {
		rcu_read_unlock();
		dma_fence_signal(fence);
		return true;