提交 922ade0d 编写于 作者: T Thomas Hellstrom 提交者: Dave Airlie

vmwgfx: Break out execbuf command processing

This will make it easier to execute commands operating on user-space
resources but generated by the kernel.

JB: Added tracking if the sw_context was called from the kernel or userspace.
Signed-off-by: NThomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: NJakob Bornecrantz <jakob@vmware.com>
Reviewed-by: NJakob Bornecrantz <jakob@vmware.com>
Signed-off-by: NDave Airlie <airlied@redhat.com>
上级 6070e9fa
...@@ -139,6 +139,7 @@ struct vmw_sw_context{ ...@@ -139,6 +139,7 @@ struct vmw_sw_context{
struct ida bo_list; struct ida bo_list;
uint32_t last_cid; uint32_t last_cid;
bool cid_valid; bool cid_valid;
bool kernel; /**< is the called made from the kernel */
uint32_t last_sid; uint32_t last_sid;
uint32_t sid_translation; uint32_t sid_translation;
bool sid_valid; bool sid_valid;
...@@ -449,6 +450,14 @@ extern int vmw_dma_quiescent(struct drm_device *dev); ...@@ -449,6 +450,14 @@ extern int vmw_dma_quiescent(struct drm_device *dev);
extern int vmw_execbuf_ioctl(struct drm_device *dev, void *data, extern int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv); struct drm_file *file_priv);
extern int vmw_execbuf_process(struct drm_file *file_priv,
struct vmw_private *dev_priv,
void __user *user_commands,
void *kernel_commands,
uint32_t command_size,
uint64_t throttle_us,
struct drm_vmw_fence_rep __user
*user_fence_rep);
/** /**
* IRQs and wating - vmwgfx_irq.c * IRQs and wating - vmwgfx_irq.c
......
...@@ -531,9 +531,9 @@ static int vmw_cmd_check(struct vmw_private *dev_priv, ...@@ -531,9 +531,9 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
static int vmw_cmd_check_all(struct vmw_private *dev_priv, static int vmw_cmd_check_all(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context, struct vmw_sw_context *sw_context,
void *buf,
uint32_t size) uint32_t size)
{ {
void *buf = sw_context->cmd_bounce;
int32_t cur_size = size; int32_t cur_size = size;
int ret; int ret;
...@@ -724,58 +724,44 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv, ...@@ -724,58 +724,44 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
return 0; return 0;
} }
int vmw_execbuf_ioctl(struct drm_device *dev, void *data, int vmw_execbuf_process(struct drm_file *file_priv,
struct drm_file *file_priv) struct vmw_private *dev_priv,
void __user *user_commands,
void *kernel_commands,
uint32_t command_size,
uint64_t throttle_us,
struct drm_vmw_fence_rep __user *user_fence_rep)
{ {
struct vmw_private *dev_priv = vmw_priv(dev);
struct drm_vmw_execbuf_arg *arg = (struct drm_vmw_execbuf_arg *)data;
struct drm_vmw_fence_rep fence_rep;
struct drm_vmw_fence_rep __user *user_fence_rep;
int ret;
void *user_cmd;
void *cmd;
struct vmw_sw_context *sw_context = &dev_priv->ctx; struct vmw_sw_context *sw_context = &dev_priv->ctx;
struct vmw_master *vmaster = vmw_master(file_priv->master); struct drm_vmw_fence_rep fence_rep;
struct vmw_fence_obj *fence; struct vmw_fence_obj *fence;
uint32_t handle; uint32_t handle;
void *cmd;
int ret;
/* ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
* This will allow us to extend the ioctl argument while
* maintaining backwards compatibility:
* We take different code paths depending on the value of
* arg->version.
*/
if (unlikely(arg->version != DRM_VMW_EXECBUF_VERSION)) {
DRM_ERROR("Incorrect execbuf version.\n");
DRM_ERROR("You're running outdated experimental "
"vmwgfx user-space drivers.");
return -EINVAL;
}
ret = ttm_read_lock(&vmaster->lock, true);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
return ret; return -ERESTARTSYS;
ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex); if (kernel_commands == NULL) {
if (unlikely(ret != 0)) { sw_context->kernel = false;
ret = -ERESTARTSYS;
goto out_no_cmd_mutex;
}
ret = vmw_resize_cmd_bounce(sw_context, arg->command_size); ret = vmw_resize_cmd_bounce(sw_context, command_size);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out_unlock; goto out_unlock;
user_cmd = (void __user *)(unsigned long)arg->commands;
ret = copy_from_user(sw_context->cmd_bounce,
user_cmd, arg->command_size);
if (unlikely(ret != 0)) { ret = copy_from_user(sw_context->cmd_bounce,
ret = -EFAULT; user_commands, command_size);
DRM_ERROR("Failed copying commands.\n");
goto out_unlock; if (unlikely(ret != 0)) {
} ret = -EFAULT;
DRM_ERROR("Failed copying commands.\n");
goto out_unlock;
}
kernel_commands = sw_context->cmd_bounce;
} else
sw_context->kernel = true;
sw_context->tfile = vmw_fpriv(file_priv)->tfile; sw_context->tfile = vmw_fpriv(file_priv)->tfile;
sw_context->cid_valid = false; sw_context->cid_valid = false;
...@@ -786,7 +772,8 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ...@@ -786,7 +772,8 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
INIT_LIST_HEAD(&sw_context->validate_nodes); INIT_LIST_HEAD(&sw_context->validate_nodes);
ret = vmw_cmd_check_all(dev_priv, sw_context, arg->command_size); ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands,
command_size);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out_err; goto out_err;
...@@ -800,26 +787,24 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ...@@ -800,26 +787,24 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
vmw_apply_relocations(sw_context); vmw_apply_relocations(sw_context);
if (arg->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,
arg->throttle_us); throttle_us);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out_throttle; goto out_throttle;
} }
cmd = vmw_fifo_reserve(dev_priv, arg->command_size); cmd = vmw_fifo_reserve(dev_priv, command_size);
if (unlikely(cmd == NULL)) { if (unlikely(cmd == NULL)) {
DRM_ERROR("Failed reserving fifo space for commands.\n"); DRM_ERROR("Failed reserving fifo space for commands.\n");
ret = -ENOMEM; ret = -ENOMEM;
goto out_err; goto out_throttle;
} }
memcpy(cmd, sw_context->cmd_bounce, arg->command_size); memcpy(cmd, kernel_commands, command_size);
vmw_fifo_commit(dev_priv, arg->command_size); vmw_fifo_commit(dev_priv, command_size);
user_fence_rep = (struct drm_vmw_fence_rep __user *)
(unsigned long)arg->fence_rep;
ret = vmw_execbuf_fence_commands(file_priv, dev_priv, ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
&fence, &fence,
(user_fence_rep) ? &handle : NULL); (user_fence_rep) ? &handle : NULL);
...@@ -836,7 +821,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ...@@ -836,7 +821,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
(void *) fence); (void *) fence);
vmw_clear_validations(sw_context); vmw_clear_validations(sw_context);
mutex_unlock(&dev_priv->cmdbuf_mutex);
if (user_fence_rep) { if (user_fence_rep) {
fence_rep.error = ret; fence_rep.error = ret;
...@@ -873,9 +857,9 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ...@@ -873,9 +857,9 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
if (likely(fence != NULL)) if (likely(fence != NULL))
vmw_fence_obj_unreference(&fence); vmw_fence_obj_unreference(&fence);
vmw_kms_cursor_post_execbuf(dev_priv); mutex_unlock(&dev_priv->cmdbuf_mutex);
ttm_read_unlock(&vmaster->lock);
return 0; return 0;
out_err: out_err:
vmw_free_relocations(sw_context); vmw_free_relocations(sw_context);
out_throttle: out_throttle:
...@@ -883,7 +867,47 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ...@@ -883,7 +867,47 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
vmw_clear_validations(sw_context); vmw_clear_validations(sw_context);
out_unlock: out_unlock:
mutex_unlock(&dev_priv->cmdbuf_mutex); mutex_unlock(&dev_priv->cmdbuf_mutex);
out_no_cmd_mutex: return ret;
}
int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct vmw_private *dev_priv = vmw_priv(dev);
struct drm_vmw_execbuf_arg *arg = (struct drm_vmw_execbuf_arg *)data;
struct vmw_master *vmaster = vmw_master(file_priv->master);
int ret;
/*
* This will allow us to extend the ioctl argument while
* maintaining backwards compatibility:
* We take different code paths depending on the value of
* arg->version.
*/
if (unlikely(arg->version != DRM_VMW_EXECBUF_VERSION)) {
DRM_ERROR("Incorrect execbuf version.\n");
DRM_ERROR("You're running outdated experimental "
"vmwgfx user-space drivers.");
return -EINVAL;
}
ret = ttm_read_lock(&vmaster->lock, true);
if (unlikely(ret != 0))
return ret;
ret = vmw_execbuf_process(file_priv, dev_priv,
(void __user *)(unsigned long)arg->commands,
NULL, arg->command_size, arg->throttle_us,
(void __user *)(unsigned long)arg->fence_rep);
if (unlikely(ret != 0))
goto out_unlock;
vmw_kms_cursor_post_execbuf(dev_priv);
out_unlock:
ttm_read_unlock(&vmaster->lock); ttm_read_unlock(&vmaster->lock);
return ret; return ret;
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册