Commit c906965d authored by Sinclair Yeh's avatar Sinclair Yeh

drm/vmwgfx: Add export fence to file descriptor support

Added code to link a fence to a out_fence_fd file descriptor and
thread out_fence_fd down to vmw_execbuf_copy_fence_user() so it can be
copied into the IOCTL reply and be passed back up the the user.

v2:
Make sure to sync and clean up in case of failure
Signed-off-by: default avatarSinclair Yeh <syeh@vmware.com>
Reviewed-by: default avatarDeepak Singh Rawat <drawat@vmware.com>
Reviewed-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
parent 58585116
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <drm/ttm/ttm_execbuf_util.h> #include <drm/ttm/ttm_execbuf_util.h>
#include <drm/ttm/ttm_module.h> #include <drm/ttm/ttm_module.h>
#include "vmwgfx_fence.h" #include "vmwgfx_fence.h"
#include <linux/sync_file.h>
#define VMWGFX_DRIVER_NAME "vmwgfx" #define VMWGFX_DRIVER_NAME "vmwgfx"
#define VMWGFX_DRIVER_DATE "20170607" #define VMWGFX_DRIVER_DATE "20170607"
...@@ -826,7 +827,8 @@ extern int vmw_execbuf_process(struct drm_file *file_priv, ...@@ -826,7 +827,8 @@ extern int vmw_execbuf_process(struct drm_file *file_priv,
uint32_t dx_context_handle, uint32_t dx_context_handle,
struct drm_vmw_fence_rep __user struct drm_vmw_fence_rep __user
*user_fence_rep, *user_fence_rep,
struct vmw_fence_obj **out_fence); struct vmw_fence_obj **out_fence,
uint32_t flags);
extern void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv, extern void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
struct vmw_fence_obj *fence); struct vmw_fence_obj *fence);
extern void vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv); extern void vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv);
...@@ -841,7 +843,9 @@ extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, ...@@ -841,7 +843,9 @@ extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
struct drm_vmw_fence_rep __user struct drm_vmw_fence_rep __user
*user_fence_rep, *user_fence_rep,
struct vmw_fence_obj *fence, struct vmw_fence_obj *fence,
uint32_t fence_handle); uint32_t fence_handle,
int32_t out_fence_fd,
struct sync_file *sync_file);
extern int vmw_validate_single_buffer(struct vmw_private *dev_priv, extern int vmw_validate_single_buffer(struct vmw_private *dev_priv,
struct ttm_buffer_object *bo, struct ttm_buffer_object *bo,
bool interruptible, bool interruptible,
......
...@@ -3830,6 +3830,8 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv, ...@@ -3830,6 +3830,8 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
* which the information should be copied. * which the information should be copied.
* @fence: Pointer to the fenc object. * @fence: Pointer to the fenc object.
* @fence_handle: User-space fence handle. * @fence_handle: User-space fence handle.
* @out_fence_fd: exported file descriptor for the fence. -1 if not used
* @sync_file: Only used to clean up in case of an error in this function.
* *
* This function copies fence information to user-space. If copying fails, * This function copies fence information to user-space. If copying fails,
* The user-space struct drm_vmw_fence_rep::error member is hopefully * The user-space struct drm_vmw_fence_rep::error member is hopefully
...@@ -3845,7 +3847,9 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, ...@@ -3845,7 +3847,9 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
int ret, int ret,
struct drm_vmw_fence_rep __user *user_fence_rep, struct drm_vmw_fence_rep __user *user_fence_rep,
struct vmw_fence_obj *fence, struct vmw_fence_obj *fence,
uint32_t fence_handle) uint32_t fence_handle,
int32_t out_fence_fd,
struct sync_file *sync_file)
{ {
struct drm_vmw_fence_rep fence_rep; struct drm_vmw_fence_rep fence_rep;
...@@ -3855,6 +3859,7 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, ...@@ -3855,6 +3859,7 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
memset(&fence_rep, 0, sizeof(fence_rep)); memset(&fence_rep, 0, sizeof(fence_rep));
fence_rep.error = ret; fence_rep.error = ret;
fence_rep.fd = out_fence_fd;
if (ret == 0) { if (ret == 0) {
BUG_ON(fence == NULL); BUG_ON(fence == NULL);
...@@ -3877,6 +3882,14 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv, ...@@ -3877,6 +3882,14 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
* and unreference the handle. * and unreference the handle.
*/ */
if (unlikely(ret != 0) && (fence_rep.error == 0)) { if (unlikely(ret != 0) && (fence_rep.error == 0)) {
if (sync_file)
fput(sync_file->file);
if (fence_rep.fd != -1) {
put_unused_fd(fence_rep.fd);
fence_rep.fd = -1;
}
ttm_ref_object_base_unref(vmw_fp->tfile, ttm_ref_object_base_unref(vmw_fp->tfile,
fence_handle, TTM_REF_USAGE); fence_handle, TTM_REF_USAGE);
DRM_ERROR("Fence copy error. Syncing.\n"); DRM_ERROR("Fence copy error. Syncing.\n");
...@@ -4052,7 +4065,8 @@ int vmw_execbuf_process(struct drm_file *file_priv, ...@@ -4052,7 +4065,8 @@ int vmw_execbuf_process(struct drm_file *file_priv,
uint64_t throttle_us, uint64_t throttle_us,
uint32_t dx_context_handle, uint32_t dx_context_handle,
struct drm_vmw_fence_rep __user *user_fence_rep, struct drm_vmw_fence_rep __user *user_fence_rep,
struct vmw_fence_obj **out_fence) struct vmw_fence_obj **out_fence,
uint32_t flags)
{ {
struct vmw_sw_context *sw_context = &dev_priv->ctx; struct vmw_sw_context *sw_context = &dev_priv->ctx;
struct vmw_fence_obj *fence = NULL; struct vmw_fence_obj *fence = NULL;
...@@ -4062,20 +4076,33 @@ int vmw_execbuf_process(struct drm_file *file_priv, ...@@ -4062,20 +4076,33 @@ int vmw_execbuf_process(struct drm_file *file_priv,
struct ww_acquire_ctx ticket; struct ww_acquire_ctx ticket;
uint32_t handle; uint32_t handle;
int ret; int ret;
int32_t out_fence_fd = -1;
struct sync_file *sync_file = NULL;
if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) {
out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
if (out_fence_fd < 0) {
DRM_ERROR("Failed to get a fence file descriptor.\n");
return out_fence_fd;
}
}
if (throttle_us) { if (throttle_us) {
ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue, ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue,
throttle_us); throttle_us);
if (ret) if (ret)
return ret; goto out_free_fence_fd;
} }
kernel_commands = vmw_execbuf_cmdbuf(dev_priv, user_commands, kernel_commands = vmw_execbuf_cmdbuf(dev_priv, user_commands,
kernel_commands, command_size, kernel_commands, command_size,
&header); &header);
if (IS_ERR(kernel_commands)) if (IS_ERR(kernel_commands)) {
return PTR_ERR(kernel_commands); ret = PTR_ERR(kernel_commands);
goto out_free_fence_fd;
}
ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex); ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
if (ret) { if (ret) {
...@@ -4211,8 +4238,32 @@ int vmw_execbuf_process(struct drm_file *file_priv, ...@@ -4211,8 +4238,32 @@ int vmw_execbuf_process(struct drm_file *file_priv,
__vmw_execbuf_release_pinned_bo(dev_priv, fence); __vmw_execbuf_release_pinned_bo(dev_priv, fence);
vmw_clear_validations(sw_context); vmw_clear_validations(sw_context);
/*
* If anything fails here, give up trying to export the fence
* and do a sync since the user mode will not be able to sync
* the fence itself. This ensures we are still functionally
* correct.
*/
if (flags & DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD) {
sync_file = sync_file_create(&fence->base);
if (!sync_file) {
DRM_ERROR("Unable to create sync file for fence\n");
put_unused_fd(out_fence_fd);
out_fence_fd = -1;
(void) vmw_fence_obj_wait(fence, false, false,
VMW_FENCE_WAIT_TIMEOUT);
} else {
/* Link the fence with the FD created earlier */
fd_install(out_fence_fd, sync_file->file);
}
}
vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret, vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), ret,
user_fence_rep, fence, handle); user_fence_rep, fence, handle,
out_fence_fd, sync_file);
/* Don't unreference when handing fence out */ /* Don't unreference when handing fence out */
if (unlikely(out_fence != NULL)) { if (unlikely(out_fence != NULL)) {
...@@ -4263,6 +4314,9 @@ int vmw_execbuf_process(struct drm_file *file_priv, ...@@ -4263,6 +4314,9 @@ int vmw_execbuf_process(struct drm_file *file_priv,
out_free_header: out_free_header:
if (header) if (header)
vmw_cmdbuf_header_free(header); vmw_cmdbuf_header_free(header);
out_free_fence_fd:
if (out_fence_fd >= 0)
put_unused_fd(out_fence_fd);
return ret; return ret;
} }
...@@ -4479,7 +4533,8 @@ int vmw_execbuf_ioctl(struct drm_device *dev, unsigned long data, ...@@ -4479,7 +4533,8 @@ int vmw_execbuf_ioctl(struct drm_device *dev, unsigned long data,
NULL, arg.command_size, arg.throttle_us, NULL, arg.command_size, arg.throttle_us,
arg.context_handle, arg.context_handle,
(void __user *)(unsigned long)arg.fence_rep, (void __user *)(unsigned long)arg.fence_rep,
NULL); NULL,
arg.flags);
ttm_read_unlock(&dev_priv->reservation_sem); ttm_read_unlock(&dev_priv->reservation_sem);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
......
...@@ -1150,7 +1150,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data, ...@@ -1150,7 +1150,7 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
} }
vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence, vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
handle); handle, -1, NULL);
vmw_fence_obj_unreference(&fence); vmw_fence_obj_unreference(&fence);
return 0; return 0;
out_no_create: out_no_create:
......
...@@ -2494,7 +2494,7 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, ...@@ -2494,7 +2494,7 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv,
if (file_priv) if (file_priv)
vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv), vmw_execbuf_copy_fence_user(dev_priv, vmw_fpriv(file_priv),
ret, user_fence_rep, fence, ret, user_fence_rep, fence,
handle); handle, -1, NULL);
if (out_fence) if (out_fence)
*out_fence = fence; *out_fence = fence;
else else
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment