[As requested by Daniel cross posting to intel-gfx as well].
This set is the first step towards allowing to use a DMA-buf without actually pinning the underlying resources. This in turn the the ground work for PCIe P2P operations as well as quite a bunch of other use cases.
The idea is that we build the support for unpinned operation around the already present reservation lock in the DMA-buf object. For this we now grab the reservation object lock while mapping and unmapping DMA-bufs.
The down side is that all implementations as well as users of DMA-buf needs to be audited to make sure that we don't run into double locking or lock inversions.
So please test and/or comment and report back how badly lockdep complains :)
Thanks,
Christian.
Am 28.06.2018 um 11:53 schrieb Zhang, Jerry (Junwei):
> On 06/22/2018 10:11 PM, Christian König wrote:
>> Add function variants which can be called with the reservation lock
>> already held.
>>
>> v2: reordered, add lockdep asserts, fix kerneldoc
>>
>> Signed-off-by: Christian König <christian.koenig(a)amd.com>
>> ---
>> drivers/dma-buf/dma-buf.c | 57
>> +++++++++++++++++++++++++++++++++++++++++++++++
>> include/linux/dma-buf.h | 5 +++++
>> 2 files changed, 62 insertions(+)
>>
>> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
>> index 852a3928ee71..dc94e76e2e2a 100644
>> --- a/drivers/dma-buf/dma-buf.c
>> +++ b/drivers/dma-buf/dma-buf.c
>> @@ -606,6 +606,40 @@ void dma_buf_detach(struct dma_buf *dmabuf,
>> struct dma_buf_attachment *attach)
>> }
>> EXPORT_SYMBOL_GPL(dma_buf_detach);
>>
>> +/**
>> + * dma_buf_map_attachment_locked - Maps the buffer into _device_
>> address space
>> + * with the reservation lock held. Is a wrapper for map_dma_buf() of
>> the
>> + *
>> + * Returns the scatterlist table of the attachment;
>> + * dma_buf_ops.
>> + * @attach: [in] attachment whose scatterlist is to be returned
>> + * @direction: [in] direction of DMA transfer
>> + *
>> + * Returns sg_table containing the scatterlist to be returned;
>> returns ERR_PTR
>> + * on error. May return -EINTR if it is interrupted by a signal.
>> + *
>> + * A mapping must be unmapped by using
>> dma_buf_unmap_attachment_locked(). Note
>> + * that the underlying backing storage is pinned for as long as a
>> mapping
>> + * exists, therefore users/importers should not hold onto a mapping
>> for undue
>> + * amounts of time.
>> + */
>> +struct sg_table *
>> +dma_buf_map_attachment_locked(struct dma_buf_attachment *attach,
>> + enum dma_data_direction direction)
>> +{
>> + struct sg_table *sg_table;
>> +
>
> Perhaps better to add some error check, like dma_buf_map_attachment()
>
> WARN_ON(!attach || !attach->dmabuf)
Actually I wanted to remove those from the other functions as well.
WARN_ON and BUG_ON checks for NULL pointers before using them are
totally pointless because they have the same effect as a crash.
Regards,
Christian.
>
> Apart from that, it's
> Reviewed-by: Junwei Zhang <Jerry.Zhang(a)amd.com>
>
> Jerry
>
>> + might_sleep();
>> + reservation_object_assert_held(attach->dmabuf->resv);
>> +
>> + sg_table = attach->dmabuf->ops->map_dma_buf(attach, direction);
>> + if (!sg_table)
>> + sg_table = ERR_PTR(-ENOMEM);
>> +
>> + return sg_table;
>> +}
>> +EXPORT_SYMBOL_GPL(dma_buf_map_attachment_locked);
>> +
>> /**
>> * dma_buf_map_attachment - Returns the scatterlist table of the
>> attachment;
>> * mapped into _device_ address space. Is a wrapper for
>> map_dma_buf() of the
>> @@ -639,6 +673,29 @@ struct sg_table *dma_buf_map_attachment(struct
>> dma_buf_attachment *attach,
>> }
>> EXPORT_SYMBOL_GPL(dma_buf_map_attachment);
>>
>> +/**
>> + * dma_buf_unmap_attachment_locked - unmaps the buffer with
>> reservation lock
>> + * held, should deallocate the associated scatterlist. Is a wrapper for
>> + * unmap_dma_buf() of dma_buf_ops.
>> + * @attach: [in] attachment to unmap buffer from
>> + * @sg_table: [in] scatterlist info of the buffer to unmap
>> + * @direction: [in] direction of DMA transfer
>> + *
>> + * This unmaps a DMA mapping for @attached obtained by
>> + * dma_buf_map_attachment_locked().
>> + */
>> +void dma_buf_unmap_attachment_locked(struct dma_buf_attachment *attach,
>> + struct sg_table *sg_table,
>> + enum dma_data_direction direction)
>> +{
>> + might_sleep();
>> + reservation_object_assert_held(attach->dmabuf->resv);
>> +
>> + attach->dmabuf->ops->unmap_dma_buf(attach, sg_table,
>> + direction);
>> +}
>> +EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment_locked);
>> +
>> /**
>> * dma_buf_unmap_attachment - unmaps and decreases usecount of the
>> buffer;might
>> * deallocate the scatterlist associated. Is a wrapper for
>> unmap_dma_buf() of
>> diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
>> index 991787a03199..a25e754ae2f7 100644
>> --- a/include/linux/dma-buf.h
>> +++ b/include/linux/dma-buf.h
>> @@ -384,8 +384,13 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags);
>> struct dma_buf *dma_buf_get(int fd);
>> void dma_buf_put(struct dma_buf *dmabuf);
>>
>> +struct sg_table *dma_buf_map_attachment_locked(struct
>> dma_buf_attachment *,
>> + enum dma_data_direction);
>> struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
>> enum dma_data_direction);
>> +void dma_buf_unmap_attachment_locked(struct dma_buf_attachment *,
>> + struct sg_table *,
>> + enum dma_data_direction);
>> void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct
>> sg_table *,
>> enum dma_data_direction);
>> int dma_buf_begin_cpu_access(struct dma_buf *dma_buf,
>>
Almost everyone uses dma_fence_default_wait.
v2: Also remove the BUG_ON(!ops->wait) (Chris).
Reviewed-by: Christian König <christian.koenig(a)amd.com> (v1)
Signed-off-by: Daniel Vetter <daniel.vetter(a)ffwll.ch>
Cc: Chris Wilson <chris(a)chris-wilson.co.uk>
Cc: Sumit Semwal <sumit.semwal(a)linaro.org>
Cc: Gustavo Padovan <gustavo(a)padovan.org>
Cc: linux-media(a)vger.kernel.org
Cc: linaro-mm-sig(a)lists.linaro.org
---
drivers/dma-buf/dma-fence-array.c | 1 -
drivers/dma-buf/dma-fence.c | 8 +++++---
drivers/dma-buf/sw_sync.c | 1 -
include/linux/dma-fence.h | 13 ++++++++-----
4 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c
index dd1edfb27b61..a8c254497251 100644
--- a/drivers/dma-buf/dma-fence-array.c
+++ b/drivers/dma-buf/dma-fence-array.c
@@ -104,7 +104,6 @@ const struct dma_fence_ops dma_fence_array_ops = {
.get_timeline_name = dma_fence_array_get_timeline_name,
.enable_signaling = dma_fence_array_enable_signaling,
.signaled = dma_fence_array_signaled,
- .wait = dma_fence_default_wait,
.release = dma_fence_array_release,
};
EXPORT_SYMBOL(dma_fence_array_ops);
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 59049375bd19..41ec19c9efc7 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -158,7 +158,10 @@ dma_fence_wait_timeout(struct dma_fence *fence, bool intr, signed long timeout)
return -EINVAL;
trace_dma_fence_wait_start(fence);
- ret = fence->ops->wait(fence, intr, timeout);
+ 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);
return ret;
}
@@ -562,8 +565,7 @@ dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
spinlock_t *lock, u64 context, unsigned seqno)
{
BUG_ON(!lock);
- BUG_ON(!ops || !ops->wait ||
- !ops->get_driver_name || !ops->get_timeline_name);
+ BUG_ON(!ops || !ops->get_driver_name || !ops->get_timeline_name);
kref_init(&fence->refcount);
fence->ops = ops;
diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c
index 3d78ca89a605..53c1d6d36a64 100644
--- a/drivers/dma-buf/sw_sync.c
+++ b/drivers/dma-buf/sw_sync.c
@@ -188,7 +188,6 @@ static const struct dma_fence_ops timeline_fence_ops = {
.get_timeline_name = timeline_fence_get_timeline_name,
.enable_signaling = timeline_fence_enable_signaling,
.signaled = timeline_fence_signaled,
- .wait = dma_fence_default_wait,
.release = timeline_fence_release,
.fence_value_str = timeline_fence_value_str,
.timeline_value_str = timeline_fence_timeline_value_str,
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
index c053d19e1e24..02dba8cd033d 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -191,11 +191,14 @@ struct dma_fence_ops {
/**
* @wait:
*
- * Custom wait implementation, or dma_fence_default_wait.
+ * Custom wait implementation, defaults to dma_fence_default_wait() if
+ * not set.
*
- * Must not be NULL, set to dma_fence_default_wait for default implementation.
- * the dma_fence_default_wait implementation should work for any fence, as long
- * as enable_signaling works correctly.
+ * The dma_fence_default_wait implementation should work for any fence, as long
+ * as @enable_signaling works correctly. This hook allows drivers to
+ * have an optimized version for the case where a process context is
+ * already available, e.g. if @enable_signaling for the general case
+ * needs to set up a worker thread.
*
* Must return -ERESTARTSYS if the wait is intr = true and the wait was
* interrupted, and remaining jiffies if fence has signaled, or 0 if wait
@@ -203,7 +206,7 @@ struct dma_fence_ops {
* which should be treated as if the fence is signaled. For example a hardware
* lockup could be reported like that.
*
- * This callback is mandatory.
+ * This callback is optional.
*/
signed long (*wait)(struct dma_fence *fence,
bool intr, signed long timeout);
--
2.17.0