diff options
Diffstat (limited to 'drivers/dma-buf/dma-fence.c')
-rw-r--r-- | drivers/dma-buf/dma-fence.c | 167 |
1 files changed, 145 insertions, 22 deletions
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index f0cdd3e99d36..3f78c56b58dc 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -511,12 +511,20 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout) dma_fence_enable_sw_signaling(fence); - trace_dma_fence_wait_start(fence); + if (trace_dma_fence_wait_start_enabled()) { + rcu_read_lock(); + trace_dma_fence_wait_start(fence); + rcu_read_unlock(); + } if (fence->ops->wait) ret = fence->ops->wait(fence, intr, timeout); else ret = dma_fence_default_wait(fence, intr, timeout); - trace_dma_fence_wait_end(fence); + if (trace_dma_fence_wait_end_enabled()) { + rcu_read_lock(); + trace_dma_fence_wait_end(fence); + rcu_read_unlock(); + } return ret; } EXPORT_SYMBOL(dma_fence_wait_timeout); @@ -533,16 +541,23 @@ void dma_fence_release(struct kref *kref) struct dma_fence *fence = container_of(kref, struct dma_fence, refcount); + rcu_read_lock(); trace_dma_fence_destroy(fence); - if (WARN(!list_empty(&fence->cb_list) && - !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags), - "Fence %s:%s:%llx:%llx released with pending signals!\n", - fence->ops->get_driver_name(fence), - fence->ops->get_timeline_name(fence), - fence->context, fence->seqno)) { + if (!list_empty(&fence->cb_list) && + !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { + const char __rcu *timeline; + const char __rcu *driver; unsigned long flags; + driver = dma_fence_driver_name(fence); + timeline = dma_fence_timeline_name(fence); + + WARN(1, + "Fence %s:%s:%llx:%llx released with pending signals!\n", + rcu_dereference(driver), rcu_dereference(timeline), + fence->context, fence->seqno); + /* * Failed to signal before release, likely a refcounting issue. * @@ -556,6 +571,8 @@ void dma_fence_release(struct kref *kref) spin_unlock_irqrestore(fence->lock, flags); } + rcu_read_unlock(); + if (fence->ops->release) fence->ops->release(fence); else @@ -982,13 +999,43 @@ EXPORT_SYMBOL(dma_fence_set_deadline); */ void dma_fence_describe(struct dma_fence *fence, struct seq_file *seq) { + const char __rcu *timeline; + const char __rcu *driver; + + rcu_read_lock(); + + timeline = dma_fence_timeline_name(fence); + driver = dma_fence_driver_name(fence); + seq_printf(seq, "%s %s seq %llu %ssignalled\n", - fence->ops->get_driver_name(fence), - fence->ops->get_timeline_name(fence), fence->seqno, + rcu_dereference(driver), + rcu_dereference(timeline), + fence->seqno, dma_fence_is_signaled(fence) ? "" : "un"); + + rcu_read_unlock(); } EXPORT_SYMBOL(dma_fence_describe); +static void +__dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops, + spinlock_t *lock, u64 context, u64 seqno, unsigned long flags) +{ + BUG_ON(!lock); + BUG_ON(!ops || !ops->get_driver_name || !ops->get_timeline_name); + + kref_init(&fence->refcount); + fence->ops = ops; + INIT_LIST_HEAD(&fence->cb_list); + fence->lock = lock; + fence->context = context; + fence->seqno = seqno; + fence->flags = flags; + fence->error = 0; + + trace_dma_fence_init(fence); +} + /** * dma_fence_init - Initialize a custom fence. * @fence: the fence to initialize @@ -1008,18 +1055,94 @@ void dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops, spinlock_t *lock, u64 context, u64 seqno) { - BUG_ON(!lock); - BUG_ON(!ops || !ops->get_driver_name || !ops->get_timeline_name); + __dma_fence_init(fence, ops, lock, context, seqno, 0UL); +} +EXPORT_SYMBOL(dma_fence_init); - kref_init(&fence->refcount); - fence->ops = ops; - INIT_LIST_HEAD(&fence->cb_list); - fence->lock = lock; - fence->context = context; - fence->seqno = seqno; - fence->flags = 0UL; - fence->error = 0; +/** + * dma_fence_init64 - Initialize a custom fence with 64-bit seqno support. + * @fence: the fence to initialize + * @ops: the dma_fence_ops for operations on this fence + * @lock: the irqsafe spinlock to use for locking this fence + * @context: the execution context this fence is run on + * @seqno: a linear increasing sequence number for this context + * + * Initializes an allocated fence, the caller doesn't have to keep its + * refcount after committing with this fence, but it will need to hold a + * refcount again if &dma_fence_ops.enable_signaling gets called. + * + * Context and seqno are used for easy comparison between fences, allowing + * to check which fence is later by simply using dma_fence_later(). + */ +void +dma_fence_init64(struct dma_fence *fence, const struct dma_fence_ops *ops, + spinlock_t *lock, u64 context, u64 seqno) +{ + __dma_fence_init(fence, ops, lock, context, seqno, + BIT(DMA_FENCE_FLAG_SEQNO64_BIT)); +} +EXPORT_SYMBOL(dma_fence_init64); - trace_dma_fence_init(fence); +/** + * dma_fence_driver_name - Access the driver name + * @fence: the fence to query + * + * Returns a driver name backing the dma-fence implementation. + * + * IMPORTANT CONSIDERATION: + * Dma-fence contract stipulates that access to driver provided data (data not + * directly embedded into the object itself), such as the &dma_fence.lock and + * memory potentially accessed by the &dma_fence.ops functions, is forbidden + * after the fence has been signalled. Drivers are allowed to free that data, + * and some do. + * + * To allow safe access drivers are mandated to guarantee a RCU grace period + * between signalling the fence and freeing said data. + * + * As such access to the driver name is only valid inside a RCU locked section. + * The pointer MUST be both queried and USED ONLY WITHIN a SINGLE block guarded + * by the &rcu_read_lock and &rcu_read_unlock pair. + */ +const char __rcu *dma_fence_driver_name(struct dma_fence *fence) +{ + RCU_LOCKDEP_WARN(!rcu_read_lock_held(), + "RCU protection is required for safe access to returned string"); + + if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) + return fence->ops->get_driver_name(fence); + else + return "detached-driver"; } -EXPORT_SYMBOL(dma_fence_init); +EXPORT_SYMBOL(dma_fence_driver_name); + +/** + * dma_fence_timeline_name - Access the timeline name + * @fence: the fence to query + * + * Returns a timeline name provided by the dma-fence implementation. + * + * IMPORTANT CONSIDERATION: + * Dma-fence contract stipulates that access to driver provided data (data not + * directly embedded into the object itself), such as the &dma_fence.lock and + * memory potentially accessed by the &dma_fence.ops functions, is forbidden + * after the fence has been signalled. Drivers are allowed to free that data, + * and some do. + * + * To allow safe access drivers are mandated to guarantee a RCU grace period + * between signalling the fence and freeing said data. + * + * As such access to the driver name is only valid inside a RCU locked section. + * The pointer MUST be both queried and USED ONLY WITHIN a SINGLE block guarded + * by the &rcu_read_lock and &rcu_read_unlock pair. + */ +const char __rcu *dma_fence_timeline_name(struct dma_fence *fence) +{ + RCU_LOCKDEP_WARN(!rcu_read_lock_held(), + "RCU protection is required for safe access to returned string"); + + if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) + return fence->ops->get_driver_name(fence); + else + return "signaled-timeline"; +} +EXPORT_SYMBOL(dma_fence_timeline_name); |