amdgpu/sync_file shared semaphores
Subsystems (5)
This is a repost of the file_sync semaphore support.
The main difference in this patch is patch1 does a lot better at handling NULL fences in some places. The poll code and ioctls should handle ending up with fence being NULL properly now.
Dave.
_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
A message that is not in the archive (sent off-list or not yet received): 20170320070307.18344-1-airlied-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
PATCH 1/4 sync_file: add a mutex to protect fence and callback members. (v3)
From: Dave Airlie <[email protected]>
This patch allows the underlying fence in a sync_file to be changed or set to NULL. This isn't currently required but for Vulkan semaphores we need to be able to swap and reset the fence.
In order to faciliate this, it uses rcu to protect the fence, along with a new mutex. The mutex also protects the callback. It also checks for NULL when retrieving the rcu protected fence in case it has been reset.
v1.1: fix the locking (Julia Lawall).
v2: use rcu try one
v3: fix poll to use proper rcu, fixup merge/fill ioctls to not crash on NULL fence cases.
--- drivers/dma-buf/sync_file.c | 112 +++++++++++++++++++++++++++++++++++--------- include/linux/sync_file.h | 5 +- 2 files changed, 94 insertions(+), 23 deletions(-)
drivers/dma-buf/sync_file.c +90 -22
@@ -28,6 +28,10 @@static const struct file_operations sync_file_fops; +#define sync_file_held (obj) lockdep_is_held(&(obj)->lock) +#define sync_file_assert_held (obj) \ + lockdep_assert_held(&(obj)->lock) +static struct sync_file *sync_file_alloc (void ) {struct sync_file *sync_file;
@@ -47,6 +51,9 @@ static struct sync_file *sync_file_alloc(void)INIT_LIST_HEAD (&sync_file->cb.node); +RCU_INIT_POINTER (sync_file->fence,NULL ); + +mutex_init (&sync_file->lock);return sync_file; err:
@@ -80,7 +87,9 @@ struct sync_file *sync_file_create(struct dma_fence *fence)if (!sync_file)return NULL ; - sync_file->fence =dma_fence_get (fence); +dma_fence_get (fence); + +RCU_INIT_POINTER (sync_file->fence, fence); snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%llu-%d", fence->ops->get_driver_name(fence),
@@ -124,13 +133,26 @@ struct dma_fence *sync_file_get_fence(int fd)if (!sync_file)return NULL ; - fence =dma_fence_get (sync_file->fence); +if (!rcu_access_pointer (sync_file->fence)) +return NULL ; + +rcu_read_lock (); + fence =dma_fence_get_rcu_safe (&sync_file->fence); +rcu_read_unlock (); +fput (sync_file->file);return fence; }EXPORT_SYMBOL (sync_file_get_fence); +static inline struct dma_fence * +sync_file_get_fence_locked (struct sync_file *sync_file) +{ +return rcu_dereference_protected (sync_file->fence, +sync_file_held (sync_file)); +} +static int sync_file_set_fence (struct sync_file *sync_file,struct dma_fence **fences,int num_fences) {
@@ -143,7 +165,7 @@ static int sync_file_set_fence(struct sync_file *sync_file,* we own the reference of the dma_fence_array creation. */ if (num_fences ==1 ) { - sync_file->fence = fences[0 ]; +RCU_INIT_POINTER (sync_file->fence, fences[0 ]);kfree (fences); }else { array = dma_fence_array_create(num_fences, fences,
@@ -152,17 +174,25 @@ static int sync_file_set_fence(struct sync_file *sync_file,if (!array)return -ENOMEM ; - sync_file->fence = &array->base; +RCU_INIT_POINTER (sync_file->fence, &array->base); }return 0 ; } +/* must be called with sync_file lock taken */ static struct dma_fence **get_fences (struct sync_file *sync_file,int *num_fences) { -if (dma_fence_is_array (sync_file->fence)) { -struct dma_fence_array *array =to_dma_fence_array (sync_file->fence); +struct dma_fence *fence =sync_file_get_fence_locked (sync_file); + +if (!fence) { + *num_fences =0 ; +return NULL ; + } + +if (dma_fence_is_array (fence)) { +struct dma_fence_array *array =to_dma_fence_array (fence); *num_fences = array->num_fences;return array->fences;
@@ -204,10 +234,16 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,if (!sync_file)return NULL ; +mutex_lock (&a->lock); +mutex_lock (&b->lock); a_fences =get_fences (a, &a_num_fences); b_fences =get_fences (b, &b_num_fences); -if (a_num_fences >INT_MAX - b_num_fences) -return NULL ; +if (!a_num_fences || !b_num_fences) + goto unlock; + +if (a_num_fences >INT_MAX - b_num_fences) { + goto unlock; + } num_fences = a_num_fences + b_num_fences;
@@ -268,11 +304,17 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, goto err; } +mutex_unlock (&b->lock); +mutex_unlock (&a->lock); +strlcpy (sync_file->name, name,sizeof (sync_file->name));return sync_file; err:fput (sync_file->file); +unlock: +mutex_unlock (&b->lock); +mutex_unlock (&a->lock);return NULL ; }
@@ -281,10 +323,15 @@ static void sync_file_free(struct kref *kref) { struct sync_file *sync_file = container_of(kref, struct sync_file, kref); +struct dma_fence *fence; + + fence =rcu_dereference_protected (sync_file->fence,1 ); +if (fence) { +if (test_bit (POLL_ENABLED , &fence->flags)) +dma_fence_remove_callback (fence, &sync_file->cb); +dma_fence_put (fence); + } -if (test_bit (POLL_ENABLED , &sync_file->fence->flags)) -dma_fence_remove_callback (sync_file->fence, &sync_file->cb); -dma_fence_put (sync_file->fence);kfree (sync_file); }
@@ -299,16 +346,25 @@ static int sync_file_release(struct inode *inode, struct file *file)static unsigned int sync_file_poll (struct file *file,poll_table *wait) {struct sync_file *sync_file = file->private_data; +unsigned int ret_val =0 ; +struct dma_fence *fence;poll_wait (file, &sync_file->wq, wait); -if (!test_and_set_bit (POLL_ENABLED , &sync_file->fence->flags)) { -if (dma_fence_add_callback (sync_file->fence, &sync_file->cb, - fence_check_cb_func) <0 ) -wake_up_all (&sync_file->wq); +mutex_lock (&sync_file->lock); + + fence =sync_file_get_fence_locked (sync_file); +if (fence) { +if (!test_and_set_bit (POLL_ENABLED , &fence->flags)) { +if (dma_fence_add_callback (fence, &sync_file->cb, + fence_check_cb_func) <0 ) +wake_up_all (&sync_file->wq); + } + ret_val =dma_fence_is_signaled (fence) ?POLLIN :0 ; } +mutex_unlock (&sync_file->lock); -return dma_fence_is_signaled (sync_file->fence) ?POLLIN :0 ; +return ret_val; } static long sync_file_ioctl_merge(struct sync_file *sync_file,
@@ -393,8 +449,13 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,if (info.flags || info.pad)return -EINVAL ; +mutex_lock (&sync_file->lock); fences =get_fences (sync_file, &num_fences); +/* if there are no fences in the sync_file just return */ +if (!num_fences) + goto no_fences; +/* * Passing num_fences = 0 means that userspace doesn't want to * retrieve any sync_fence_info. If num_fences = 0 we skip filling
@@ -404,13 +465,17 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,if (!info.num_fences) goto no_fences; -if (info.num_fences < num_fences) -return -EINVAL ; +if (info.num_fences < num_fences) { + ret = -EINVAL ; + goto out; + } size = num_fences *sizeof (*fence_info); fence_info =kzalloc (size,GFP_KERNEL ); -if (!fence_info) -return -ENOMEM ; +if (!fence_info) { + ret = -ENOMEM ; + goto out; + }for (i =0 ; i < num_fences; i++)sync_fill_fence_info (fences[i], &fence_info[i]);
@@ -423,7 +488,10 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file, no_fences:strlcpy (info.name, sync_file->name,sizeof (info.name)); - info.status =dma_fence_is_signaled (sync_file->fence); +if (num_fences) + info.status =dma_fence_is_signaled (sync_file->fence); +else + info.status = -ENOENT ; info.num_fences = num_fences;if (copy_to_user ((void __user *)arg, &info,sizeof (info)))
@@ -433,7 +501,7 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file, out:kfree (fence_info); - +mutex_unlock (&sync_file->lock);return ret; }
include/linux/sync_file.h +4 -1
@@ -30,6 +30,7 @@* @wq: wait queue for fence signaling * @fence: fence with the fences in the sync_file * @cb: fence callback information +* @lock: mutex to protect fence/cb - used for semaphores */ struct sync_file {struct file *file;
@@ -41,8 +42,10 @@ struct sync_file {wait_queue_head_t wq; -struct dma_fence *fence; +struct dma_fence __rcu *fence;struct dma_fence_cb cb; +/* protects the fence pointer and cb */ +struct mutex lock; };#define POLL_ENABLED DMA_FENCE_FLAG_USER_BITS
Signature · 6 lines
2.7.4 _______________________________________________ amd-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/amd-gfx
A message that is not in the archive (sent off-list or not yet received): 20170320070307.18344-2-airlied-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
Re: [PATCH 1/4] sync_file: add a mutex to protect fence and callback members. (v3)
Quoted 30 lines · Dave Airlie
From: Dave Airlie <[email protected]>
This patch allows the underlying fence in a
sync_fileto be changed or set to NULL. This isn't currently required but for Vulkan semaphores we need to be able to swap and reset the fence.In order to faciliate this, it uses rcu to protect the fence, along with a new mutex. The mutex also protects the callback. It also checks for NULL when retrieving the rcu protected fence in case it has been reset.
v1.1: fix the locking (Julia Lawall).
v2: use rcu try one
v3: fix poll to use proper rcu, fixup merge/fill ioctls to not crash on NULL fence cases.Signed-off-by Dave Airlie <[email protected]>---
drivers/dma-buf/sync_file.c +3
-1@@ -80,7 +87,9 @@ struct sync_file *sync_file_create(struct dma_fence *fence)if (!sync_file)return NULL ; - sync_file->fence =dma_fence_get (fence); +dma_fence_get (fence); + +RCU_INIT_POINTER (sync_file->fence, fence); snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%llu-%d", fence->ops->get_driver_name(fence),
drivers/dma-buf/sync_file.c struct dma_fence *sync_file_get_fence(int fd) · line 137
Quoted 6 lines
drivers/dma-buf/sync_file.c +2
-1@@ -124,13 +133,26 @@ struct dma_fence *sync_file_get_fence(int fd)if (!sync_file)return NULL ; - fence =dma_fence_get (sync_file->fence); +if (!rcu_access_pointer (sync_file->fence)) +return NULL ;
Missed fput.
Quoted 12 lines
drivers/dma-buf/sync_file.c +5
-0+ +rcu_read_lock (); + fence =dma_fence_get_rcu_safe (&sync_file->fence); +rcu_read_unlock (); +fput (sync_file->file);return fence; }EXPORT_SYMBOL (sync_file_get_fence);
drivers/dma-buf/sync_file.c static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, · line 238
Quoted 5 lines
drivers/dma-buf/sync_file.c +2
-0@@ -204,10 +234,16 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,if (!sync_file)return NULL ; +mutex_lock (&a->lock); +mutex_lock (&b->lock);
This allows userspace to trigger lockdep (just merge the same pair of sync_files again in opposite order). if (b < a) swap(a, b); ?
Quoted 14 lines
drivers/dma-buf/sync_file.c +6
-2a_fences =get_fences (a, &a_num_fences); b_fences =get_fences (b, &b_num_fences); -if (a_num_fences >INT_MAX - b_num_fences) -return NULL ; +if (!a_num_fences || !b_num_fences) + goto unlock; + +if (a_num_fences >INT_MAX - b_num_fences) { + goto unlock; + } num_fences = a_num_fences + b_num_fences;
drivers/dma-buf/sync_file.c static void sync_file_free(struct kref *kref) · line 327
Quoted 5 lines
drivers/dma-buf/sync_file.c +2
-0@@ -281,10 +323,15 @@ static void sync_file_free(struct kref *kref) { struct sync_file *sync_file = container_of(kref, struct sync_file, kref); +struct dma_fence *fence; +
Somewhere, here?, it would be useful to add a comment that the rcu delayed free is provided by fput.
Quoted 19 lines
drivers/dma-buf/sync_file.c +8
-3+ fence =rcu_dereference_protected (sync_file->fence,1 ); +if (fence) { +if (test_bit (POLL_ENABLED , &fence->flags)) +dma_fence_remove_callback (fence, &sync_file->cb); +dma_fence_put (fence); + } -if (test_bit (POLL_ENABLED , &sync_file->fence->flags)) -dma_fence_remove_callback (sync_file->fence, &sync_file->cb); -dma_fence_put (sync_file->fence);kfree (sync_file); }@@ -299,16 +346,25 @@ static int sync_file_release(struct inode *inode, struct file *file)static unsigned int sync_file_poll (struct file *file,poll_table *wait) {struct sync_file *sync_file = file->private_data; +unsigned int ret_val =0 ; +struct dma_fence *fence;
drivers/dma-buf/sync_file.c static int sync_file_release(struct inode *inode, struct file *file) · line 356
Quoted 10 lines
drivers/dma-buf/sync_file.c +3
-4poll_wait (file, &sync_file->wq, wait); -if (!test_and_set_bit (POLL_ENABLED , &sync_file->fence->flags)) { -if (dma_fence_add_callback (sync_file->fence, &sync_file->cb, - fence_check_cb_func) <0 ) -wake_up_all (&sync_file->wq); +mutex_lock (&sync_file->lock); + + fence =sync_file_get_fence_locked (sync_file);
Why do you need the locked version here and not just the rcu variant?
drivers/dma-buf/sync_file.c static int sync_file_release(struct inode *inode, struct file *file) · line 365
Quoted 9 lines
drivers/dma-buf/sync_file.c +8
-0+if (fence) { +if (!test_and_set_bit (POLL_ENABLED , &fence->flags)) { +if (dma_fence_add_callback (fence, &sync_file->cb, + fence_check_cb_func) <0 ) +wake_up_all (&sync_file->wq); + } + ret_val =dma_fence_is_signaled (fence) ?POLLIN :0 ; } +mutex_unlock (&sync_file->lock);
So an empty sync_file is incomplete and blocks forever? Why? It's the opposite behaviour to e.g. reservation_object so a quick explanation of how that is used by VkSemaphore will cement the differences. -Chris
Signature · 5 lines
Chris Wilson, Intel Open Source Technology Centre _______________________________________________ amd-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Re: [PATCH 1/4] sync_file: add a mutex to protect fence and callback members. (v3)
Quoted 55 lines · Chris Wilson
Quoted 30 lines · Dave Airlie
From: Dave Airlie <[email protected]>
This patch allows the underlying fence in a
sync_fileto be changed or set to NULL. This isn't currently required but for Vulkan semaphores we need to be able to swap and reset the fence.In order to faciliate this, it uses rcu to protect the fence, along with a new mutex. The mutex also protects the callback. It also checks for NULL when retrieving the rcu protected fence in case it has been reset.
v1.1: fix the locking (Julia Lawall).
v2: use rcu try one
v3: fix poll to use proper rcu, fixup merge/fill ioctls to not crash on NULL fence cases.Signed-off-by Dave Airlie <[email protected]>---
drivers/dma-buf/sync_file.c +3
-1@@ -80,7 +87,9 @@ struct sync_file *sync_file_create(struct dma_fence *fence)if (!sync_file)return NULL ; - sync_file->fence =dma_fence_get (fence); +dma_fence_get (fence); + +RCU_INIT_POINTER (sync_file->fence, fence); snprintf(sync_file->name, sizeof(sync_file->name), "%s-%s%llu-%d", fence->ops->get_driver_name(fence),drivers/dma-buf/sync_file.c struct dma_fence *sync_file_get_fence(int fd) · line 137
Quoted 6 lines
drivers/dma-buf/sync_file.c +2
-1@@ -124,13 +133,26 @@ struct dma_fence *sync_file_get_fence(int fd)if (!sync_file)return NULL ; - fence =dma_fence_get (sync_file->fence); +if (!rcu_access_pointer (sync_file->fence)) +return NULL ;Missed fput.
Quoted 15 lines
drivers/dma-buf/sync_file.c +5
-0+ +rcu_read_lock (); + fence =dma_fence_get_rcu_safe (&sync_file->fence); +rcu_read_unlock (); +fput (sync_file->file);return fence; }EXPORT_SYMBOL (sync_file_get_fence);@@ -204,10 +234,16 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,if (!sync_file)return NULL ;
Quoted 5 lines
drivers/dma-buf/sync_file.c static struct sync_file *sync_file_merge(const char *name, struct sync_file *a, · line 238
Quoted 2 lines
drivers/dma-buf/sync_file.c +2
-0+mutex_lock (&a->lock); +mutex_lock (&b->lock);This allows userspace to trigger lockdep (just merge the same pair of
sync_filesagain in opposite order). if (b < a)swap(a, b); ?
Do we even need the look? 1) rcu-lookup the fences (which are invariant)
2) merge them 3) create new syncfile for them. I don't see a need for taking locks here.
Quoted 46 lines
Quoted 15 lines
drivers/dma-buf/sync_file.c +6
-2a_fences =get_fences (a, &a_num_fences); b_fences =get_fences (b, &b_num_fences); -if (a_num_fences >INT_MAX - b_num_fences) -return NULL ; +if (!a_num_fences || !b_num_fences) + goto unlock; + +if (a_num_fences >INT_MAX - b_num_fences) { + goto unlock; + } num_fences = a_num_fences + b_num_fences;drivers/dma-buf/sync_file.c static void sync_file_free(struct kref *kref) · line 327
Quoted 5 lines
drivers/dma-buf/sync_file.c +2
-0@@ -281,10 +323,15 @@ static void sync_file_free(struct kref *kref) { struct sync_file *sync_file = container_of(kref, struct sync_file, kref); +struct dma_fence *fence; +Somewhere, here?, it would be useful to add a comment that the rcu delayed free is provided by fput.
Quoted 22 lines
drivers/dma-buf/sync_file.c +8
-3+ fence =rcu_dereference_protected (sync_file->fence,1 ); +if (fence) { +if (test_bit (POLL_ENABLED , &fence->flags)) +dma_fence_remove_callback (fence, &sync_file->cb); +dma_fence_put (fence); + } -if (test_bit (POLL_ENABLED , &sync_file->fence->flags)) -dma_fence_remove_callback (sync_file->fence, &sync_file->cb); -dma_fence_put (sync_file->fence);kfree (sync_file); }@@ -299,16 +346,25 @@ static int sync_file_release(struct inode *inode, struct file *file)static unsigned int sync_file_poll (struct file *file,poll_table *wait) {struct sync_file *sync_file = file->private_data; +unsigned int ret_val =0 ; +struct dma_fence *fence;poll_wait (file, &sync_file->wq, wait);
Quoted 9 lines
drivers/dma-buf/sync_file.c static int sync_file_release(struct inode *inode, struct file *file) · line 356
Quoted 7 lines
drivers/dma-buf/sync_file.c +3
-4-if (!test_and_set_bit (POLL_ENABLED , &sync_file->fence->flags)) { -if (dma_fence_add_callback (sync_file->fence, &sync_file->cb, - fence_check_cb_func) <0 ) -wake_up_all (&sync_file->wq); +mutex_lock (&sync_file->lock); + + fence =sync_file_get_fence_locked (sync_file);Why do you need the locked version here and not just the rcu variant?
+1 :-) I think the lock should only be needed when you update the fence, everywhere else we should be able to get away with rcu.
Quoted 5 lines
Quoted 5 lines
drivers/dma-buf/sync_file.c +5
-0+if (fence) { +if (!test_and_set_bit (POLL_ENABLED , &fence->flags)) { +if (dma_fence_add_callback (fence, &sync_file->cb, + fence_check_cb_func) <0 ) +wake_up_all (&sync_file->wq);
Quoted 8 lines
drivers/dma-buf/sync_file.c static int sync_file_release(struct inode *inode, struct file *file) · line 365
Quoted 4 lines
drivers/dma-buf/sync_file.c +3
-0+ } + ret_val =dma_fence_is_signaled (fence) ?POLLIN :0 ; } +mutex_unlock (&sync_file->lock);So an empty
sync_fileis incomplete and blocks forever? Why? It's the opposite behaviour to e.g.reservation_objectso a quick explanation of how that is used by VkSemaphore will cement the differences.
Well if we reuse this for future fences then "not yet signalled" is kinda what we want. In the end it doesn't matter until we wire up things properly (i.e. block in sync_file_get_fence until the fence shows up).
Cheers, Daniel
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 1/4] sync_file: add a mutex to protect fence and callback members. (v3)
In reply to a message not in the archiveQuoted 21 lines · Dave Airlie
From: Dave Airlie <[email protected]>
This patch allows the underlying fence in a
sync_fileto be changed or set to NULL. This isn't currently required but for Vulkan semaphores we need to be able to swap and reset the fence.In order to faciliate this, it uses rcu to protect the fence, along with a new mutex. The mutex also protects the callback. It also checks for NULL when retrieving the rcu protected fence in case it has been reset.
v1.1: fix the locking (Julia Lawall).
v2: use rcu try one
v3: fix poll to use proper rcu, fixup merge/fill ioctls to not crash on NULL fence cases.Signed-off-by Dave Airlie <[email protected]>---
drivers/dma-buf/sync_file.c +0
-0@@ -124,13 +133,26 @@ struct dma_fence *sync_file_get_fence(int fd)if (!sync_file)return NULL ;
drivers/dma-buf/sync_file.c struct dma_fence *sync_file_get_fence(int fd) · line 143
Quoted 10 lines
drivers/dma-buf/sync_file.c +7
-1- fence =dma_fence_get (sync_file->fence); +if (!rcu_access_pointer (sync_file->fence)) +return NULL ; + +rcu_read_lock (); + fence =dma_fence_get_rcu_safe (&sync_file->fence); +rcu_read_unlock (); +fput (sync_file->file);
So poll will wait until the fence is set before the sync_file is signaled, but here we return NULL. At the moment this is interpretted by the callers as an error (since we can't distinguish between the lookup error and the empty sync_file). However, if it is empty we also want to delay the dependent execution until the fence is set to match the poll semantics.
-Chris
Signature · 5 lines
Chris Wilson, Intel Open Source Technology Centre _______________________________________________ amd-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/amd-gfx
PATCH 3/4 amdgpu/cs: split out fence dependency checking
In reply to a message not in the archiveFrom: Dave Airlie <[email protected]>
This just splits out the fence depenency checking into it's own function to make it easier to add semaphore dependencies.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 86 +++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 38 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +48 -38
@@ -963,56 +963,66 @@ static int amdgpu_cs_ib_fill(struct amdgpu_device *adev,return 0 ; } -static int amdgpu_cs_dependencies (struct amdgpu_device *adev, -struct amdgpu_cs_parser *p) +static int amdgpu_process_fence_dep (struct amdgpu_device *adev, +struct amdgpu_cs_parser *p, +struct amdgpu_cs_chunk *chunk) {struct amdgpu_fpriv *fpriv = p->filp->driver_priv; -int i, j, r; - -for (i =0 ; i < p->nchunks; ++i) { -struct drm_amdgpu_cs_chunk_dep *deps; -struct amdgpu_cs_chunk *chunk; -unsigned num_deps; +unsigned num_deps; +int i, r; +struct drm_amdgpu_cs_chunk_dep *deps; - chunk = &p->chunks[i]; + deps = (struct drm_amdgpu_cs_chunk_dep *)chunk->kdata; + num_deps = chunk->length_dw *4 / +sizeof (struct drm_amdgpu_cs_chunk_dep ); -if (chunk->chunk_id !=AMDGPU_CHUNK_ID_DEPENDENCIES ) -continue ; +for (i =0 ; i < num_deps; ++i) { +struct amdgpu_ring *ring; +struct amdgpu_ctx *ctx; +struct dma_fence *fence; - deps = (struct drm_amdgpu_cs_chunk_dep *)chunk->kdata; - num_deps = chunk->length_dw *4 / -sizeof (struct drm_amdgpu_cs_chunk_dep ); + r =amdgpu_cs_get_ring (adev, deps[i].ip_type, + deps[i].ip_instance, + deps[i].ring, &ring); +if (r) +return r; -for (j =0 ; j < num_deps; ++j) { -struct amdgpu_ring *ring; -struct amdgpu_ctx *ctx; -struct dma_fence *fence; + ctx =amdgpu_ctx_get (fpriv, deps[i].ctx_id); +if (ctx ==NULL ) +return -EINVAL ; - r =amdgpu_cs_get_ring (adev, deps[j].ip_type, - deps[j].ip_instance, - deps[j].ring, &ring); + fence =amdgpu_ctx_get_fence (ctx, ring, + deps[i].handle); +if (IS_ERR (fence)) { + r =PTR_ERR (fence); +amdgpu_ctx_put (ctx); +return r; + }else if (fence) { + r =amdgpu_sync_fence (adev, &p->job->sync, + fence); +dma_fence_put (fence); +amdgpu_ctx_put (ctx);if (r)return r; + } + } +return 0 ; +} - ctx =amdgpu_ctx_get (fpriv, deps[j].ctx_id); -if (ctx ==NULL ) -return -EINVAL ; +static int amdgpu_cs_dependencies (struct amdgpu_device *adev, +struct amdgpu_cs_parser *p) +{ +int i, r; - fence =amdgpu_ctx_get_fence (ctx, ring, - deps[j].handle); -if (IS_ERR (fence)) { - r =PTR_ERR (fence); -amdgpu_ctx_put (ctx); -return r; +for (i =0 ; i < p->nchunks; ++i) { +struct amdgpu_cs_chunk *chunk; - }else if (fence) { - r =amdgpu_sync_fence (adev, &p->job->sync, - fence); -dma_fence_put (fence); -amdgpu_ctx_put (ctx); -if (r) -return r; - } + chunk = &p->chunks[i]; + +if (chunk->chunk_id ==AMDGPU_CHUNK_ID_DEPENDENCIES ) { + r =amdgpu_process_fence_dep (adev, p, chunk); +if (r) +return r; } }
Signature · 6 lines
2.7.4 _______________________________________________ amd-gfx mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/amd-gfx
Dave Airlie
maintainerPATCH 2/4 sync_file: add replace and export some functionality (v2)
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
Using sync_file to back vulkan semaphores means need to replace the fence underlying the sync file. This replace function removes the callback, swaps the fence, and returns the old one. This also exports the alloc and fdget functionality for the semaphore wrapper code.
v2: use rcu.
--- drivers/dma-buf/sync_file.c | 42 ++++++++++++++++++++++++++++++++++++++++-- include/linux/sync_file.h | 5 ++++- 2 files changed, 44 insertions(+), 3 deletions(-)
drivers/dma-buf/sync_file.c +40 -2
@@ -32,7 +32,14 @@ static const struct file_operations sync_file_fops;#define sync_file_assert_held (obj) \ lockdep_assert_held(&(obj)->lock) -static struct sync_file *sync_file_alloc (void ) +/** +* sync_file_alloc() - allocate an unfenced sync file +* +* Creates a sync_file. +* The sync_file can be released with fput(sync_file->file). +* Returns the sync_file or NULL in case of error. +*/ +struct sync_file *sync_file_alloc (void ) {struct sync_file *sync_file;
@@ -60,6 +67,7 @@ static struct sync_file *sync_file_alloc(void)kfree (sync_file);return NULL ; } +EXPORT_SYMBOL (sync_file_alloc);static void fence_check_cb_func (struct dma_fence *f,struct dma_fence_cb *cb) {
@@ -100,7 +108,7 @@ struct sync_file *sync_file_create(struct dma_fence *fence) }EXPORT_SYMBOL (sync_file_create); -static struct sync_file *sync_file_fdget (int fd) +struct sync_file *sync_file_fdget (int fd) {struct file *file =fget (fd);
@@ -116,6 +124,7 @@ static struct sync_file *sync_file_fdget(int fd)fput (file);return NULL ; } +EXPORT_SYMBOL (sync_file_fdget);/** * sync_file_get_fence - get the fence related to the sync_file fd
@@ -153,6 +162,35 @@ sync_file_get_fence_locked(struct sync_file *sync_file) sync_file_held(sync_file)); } +/** +* sync_file_replace_fence - replace the fence related to the sync_file +* @sync_file: sync file to replace fence in +* @fence: fence to replace with (or NULL for no fence). +* Returns previous fence. +*/ +struct dma_fence *sync_file_replace_fence (struct sync_file *sync_file, +struct dma_fence *fence) +{ +struct dma_fence *ret_fence =NULL ; + +if (fence) +dma_fence_get (fence); + +mutex_lock (&sync_file->lock); + + ret_fence =sync_file_get_fence_locked (sync_file); +if (ret_fence) { +if (test_bit (POLL_ENABLED , &ret_fence->flags)) +dma_fence_remove_callback (ret_fence, &sync_file->cb); + } + +RCU_INIT_POINTER (sync_file->fence, fence); + +mutex_unlock (&sync_file->lock); +return ret_fence; +} +EXPORT_SYMBOL (sync_file_replace_fence); +static int sync_file_set_fence (struct sync_file *sync_file,struct dma_fence **fences,int num_fences) {
include/linux/sync_file.h +4 -1
@@ -50,7 +50,10 @@ struct sync_file {#define POLL_ENABLED DMA_FENCE_FLAG_USER_BITS +struct sync_file *sync_file_alloc (void );struct sync_file *sync_file_create (struct dma_fence *fence);struct dma_fence *sync_file_get_fence (int fd); - +struct sync_file *sync_file_fdget (int fd); +struct dma_fence *sync_file_replace_fence (struct sync_file *sync_file, +struct dma_fence *fence);#endif /* _LINUX_SYNC_H */
Signature · 6 lines
2.7.4 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Dave Airlie
maintainerPATCH 4/4 amdgpu: use sync file for shared semaphores
In reply to Dave AirlieFrom: Dave Airlie <[email protected]>
This creates a new interface for amdgpu with ioctls to create/destroy/import and export shared semaphores using sem object backed by the sync_file code. The semaphores are not installed as fd (except for export), but rather like other driver internal objects in an idr. The idr holds the initial reference on the sync file.
The command submission interface is enhanced with two new chunks, one for semaphore waiting, one for semaphore signalling and just takes a list of handles for each.
This is based on work originally done by David Zhou at AMD, with input from Christian Konig on what things should look like.
NOTE: this interface addition needs a version bump to expose it to userspace.
v1.1: keep file reference on import.
--- drivers/gpu/drm/amd/amdgpu/Makefile | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 12 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 70 ++++++++++- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 8 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_sem.c | 203 ++++++++++++++++++++++++++++++++ include/uapi/drm/amdgpu_drm.h | 28 +++++ 6 files changed, 321 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_sem.c
drivers/gpu/drm/amd/amdgpu/Makefile +1 -1
@@ -24,7 +24,7 @@ amdgpu-y += amdgpu_device.o amdgpu_kms.o \ atombios_encoders.o amdgpu_sa.o atombios_i2c.o \ amdgpu_prime.o amdgpu_vm.o amdgpu_ib.o amdgpu_pll.o \ amdgpu_ucode.o amdgpu_bo_list.o amdgpu_ctx.o amdgpu_sync.o \ - amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o + amdgpu_gtt_mgr.o amdgpu_vram_mgr.o amdgpu_virt.o amdgpu_sem.o # add asic specific block amdgpu-$(CONFIG_DRM_AMDGPU_CIK)+= cik.o cik_ih.o kv_smc.o kv_dpm.o \
drivers/gpu/drm/amd/amdgpu/amdgpu.h +12 -0
@@ -702,6 +702,8 @@ struct amdgpu_fpriv {struct mutex bo_list_lock;struct idr bo_list_handles;struct amdgpu_ctx_mgr ctx_mgr; +spinlock_t sem_handles_lock; +struct idr sem_handles; };/*
@@ -1814,5 +1816,15 @@ amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser, uint64_t addr, struct amdgpu_bo **bo);int amdgpu_cs_sysvm_access_required (struct amdgpu_cs_parser *parser); +int amdgpu_sem_ioctl (struct drm_device *dev,void *data, +struct drm_file *filp); +void amdgpu_sem_destroy (struct amdgpu_fpriv *fpriv,u32 handle); +int amdgpu_sem_lookup_and_signal (struct amdgpu_fpriv *fpriv, +uint32_t handle, +struct dma_fence *fence); +int amdgpu_sem_lookup_and_sync (struct amdgpu_device *adev, +struct amdgpu_fpriv *fpriv, +struct amdgpu_sync *sync, +uint32_t handle);#include "amdgpu_object.h" #endif
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +69 -1
100 lines not on this page · raw message
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +8 -0
@@ -664,6 +664,8 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)mutex_init (&fpriv->bo_list_lock);idr_init (&fpriv->bo_list_handles); +spin_lock_init (&fpriv->sem_handles_lock); +idr_init (&fpriv->sem_handles);amdgpu_ctx_mgr_init (&fpriv->ctx_mgr); file_priv->driver_priv = fpriv;
@@ -689,6 +691,7 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,struct amdgpu_device *adev = dev->dev_private;struct amdgpu_fpriv *fpriv = file_priv->driver_priv;struct amdgpu_bo_list *list; +struct amdgpu_sem *sem;int handle;if (!fpriv)
@@ -715,6 +718,10 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev,idr_destroy (&fpriv->bo_list_handles);mutex_destroy (&fpriv->bo_list_lock); +idr_for_each_entry (&fpriv->sem_handles, sem, handle) +amdgpu_sem_destroy (fpriv, handle); +idr_destroy (&fpriv->sem_handles); +kfree (fpriv); file_priv->driver_priv =NULL ;
@@ -896,6 +903,7 @@ const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {DRM_IOCTL_DEF_DRV (AMDGPU_GEM_VA , amdgpu_gem_va_ioctl,DRM_AUTH |DRM_RENDER_ALLOW ),DRM_IOCTL_DEF_DRV (AMDGPU_GEM_OP , amdgpu_gem_op_ioctl,DRM_AUTH |DRM_RENDER_ALLOW ),DRM_IOCTL_DEF_DRV (AMDGPU_GEM_USERPTR , amdgpu_gem_userptr_ioctl,DRM_AUTH |DRM_RENDER_ALLOW ), + DRM_IOCTL_DEF_DRV(AMDGPU_SEM, amdgpu_sem_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), };const int amdgpu_max_kms_ioctl =ARRAY_SIZE (amdgpu_ioctls_kms);
drivers/gpu/drm/amd/amdgpu/amdgpu_sem.c new file +203 -0
203 lines not on this page · raw message
include/uapi/drm/amdgpu_drm.h +28 -0
@@ -51,6 +51,7 @@ extern "C" {#define DRM_AMDGPU_GEM_OP 0x10#define DRM_AMDGPU_GEM_USERPTR 0x11#define DRM_AMDGPU_WAIT_FENCES 0x12 +#define DRM_AMDGPU_SEM 0x13#define DRM_IOCTL_AMDGPU_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_CREATE, union drm_amdgpu_gem_create)#define DRM_IOCTL_AMDGPU_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_MMAP, union drm_amdgpu_gem_mmap)
@@ -65,6 +66,7 @@ extern "C" {#define DRM_IOCTL_AMDGPU_GEM_OP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_OP, struct drm_amdgpu_gem_op)#define DRM_IOCTL_AMDGPU_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_USERPTR, struct drm_amdgpu_gem_userptr)#define DRM_IOCTL_AMDGPU_WAIT_FENCES DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_WAIT_FENCES, union drm_amdgpu_wait_fences) +#define DRM_IOCTL_AMDGPU_SEM DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_SEM, union drm_amdgpu_sem)#define AMDGPU_GEM_DOMAIN_CPU 0x1#define AMDGPU_GEM_DOMAIN_GTT 0x2
@@ -335,6 +337,26 @@ union drm_amdgpu_wait_fences {struct drm_amdgpu_wait_fences_out out; }; +#define AMDGPU_SEM_OP_CREATE_SEM 0 +#define AMDGPU_SEM_OP_IMPORT_SEM 1 +#define AMDGPU_SEM_OP_EXPORT_SEM 2 +#define AMDGPU_SEM_OP_DESTROY_SEM 3 + +struct drm_amdgpu_sem_in { +__u32 op; +__u32 handle; +}; + +struct drm_amdgpu_sem_out { +__u32 fd; +__u32 handle; +}; + +union drm_amdgpu_sem { +struct drm_amdgpu_sem_in in; +struct drm_amdgpu_sem_out out; +}; +#define AMDGPU_GEM_OP_GET_GEM_CREATE_INFO 0#define AMDGPU_GEM_OP_SET_PLACEMENT 1
@@ -390,6 +412,8 @@ struct drm_amdgpu_gem_va {#define AMDGPU_CHUNK_ID_IB 0x01#define AMDGPU_CHUNK_ID_FENCE 0x02#define AMDGPU_CHUNK_ID_DEPENDENCIES 0x03 +#define AMDGPU_CHUNK_ID_SEM_WAIT 0x04 +#define AMDGPU_CHUNK_ID_SEM_SIGNAL 0x05struct drm_amdgpu_cs_chunk {__u32 chunk_id;
@@ -454,6 +478,10 @@ struct drm_amdgpu_cs_chunk_fence {__u32 offset; }; +struct drm_amdgpu_cs_chunk_sem { +__u32 handle; +}; +struct drm_amdgpu_cs_chunk_data {union {struct drm_amdgpu_cs_chunk_ib ib_data;
Signature · 6 lines
2.7.4 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
Quoted 5 lines · Dave Airlie
This is a repost of the
file_syncsemaphore support.The main difference in this patch is patch1 does a lot better at handling NULL fences in some places. The poll code and ioctls should handle ending up with fence being NULL properly now.
btw on this I realized that sync_file_get_fence can already return NULL, so no problem really and no need for a dummy fence. Silly me :-) -Daniel
Signature · 7 lines
Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel