mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 12:31:52 -04:00
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: Christian König <christian.koenig@amd.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com> Reviewed-by: Philipp Stanner <phasta@kernel.org> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com> Link: https://lore.kernel.org/r/20260219160822.1529-3-christian.koenig@amd.com
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user