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: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Jakob Bornecrantz <jakob@vmware.com>
Reviewed-by: Jakob Bornecrantz <jakob@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Thomas Hellstrom 2011-10-04 20:13:17 +02:00 committed by Dave Airlie
parent 6070e9fa6d
commit 922ade0d16
2 changed files with 90 additions and 57 deletions

View File

@ -139,6 +139,7 @@ struct vmw_sw_context{
struct ida bo_list;
uint32_t last_cid;
bool cid_valid;
bool kernel; /**< is the called made from the kernel */
uint32_t last_sid;
uint32_t sid_translation;
bool sid_valid;
@ -449,6 +450,14 @@ extern int vmw_dma_quiescent(struct drm_device *dev);
extern int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
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

View File

@ -531,9 +531,9 @@ out_err:
static int vmw_cmd_check_all(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context,
void *buf,
uint32_t size)
{
void *buf = sw_context->cmd_bounce;
int32_t cur_size = size;
int ret;
@ -724,58 +724,44 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
return 0;
}
int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
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)
{
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_master *vmaster = vmw_master(file_priv->master);
struct drm_vmw_fence_rep fence_rep;
struct vmw_fence_obj *fence;
uint32_t handle;
/*
* 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;
void *cmd;
int ret;
ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
if (unlikely(ret != 0)) {
ret = -ERESTARTSYS;
goto out_no_cmd_mutex;
}
ret = vmw_resize_cmd_bounce(sw_context, arg->command_size);
if (unlikely(ret != 0))
goto out_unlock;
return -ERESTARTSYS;
user_cmd = (void __user *)(unsigned long)arg->commands;
ret = copy_from_user(sw_context->cmd_bounce,
user_cmd, arg->command_size);
if (kernel_commands == NULL) {
sw_context->kernel = false;
if (unlikely(ret != 0)) {
ret = -EFAULT;
DRM_ERROR("Failed copying commands.\n");
goto out_unlock;
}
ret = vmw_resize_cmd_bounce(sw_context, command_size);
if (unlikely(ret != 0))
goto out_unlock;
ret = copy_from_user(sw_context->cmd_bounce,
user_commands, command_size);
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->cid_valid = false;
@ -786,7 +772,8 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
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))
goto out_err;
@ -800,26 +787,24 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
vmw_apply_relocations(sw_context);
if (arg->throttle_us) {
if (throttle_us) {
ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue,
arg->throttle_us);
throttle_us);
if (unlikely(ret != 0))
goto out_throttle;
}
cmd = vmw_fifo_reserve(dev_priv, arg->command_size);
cmd = vmw_fifo_reserve(dev_priv, command_size);
if (unlikely(cmd == NULL)) {
DRM_ERROR("Failed reserving fifo space for commands.\n");
ret = -ENOMEM;
goto out_err;
goto out_throttle;
}
memcpy(cmd, sw_context->cmd_bounce, arg->command_size);
vmw_fifo_commit(dev_priv, arg->command_size);
memcpy(cmd, kernel_commands, 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,
&fence,
(user_fence_rep) ? &handle : NULL);
@ -836,7 +821,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
(void *) fence);
vmw_clear_validations(sw_context);
mutex_unlock(&dev_priv->cmdbuf_mutex);
if (user_fence_rep) {
fence_rep.error = ret;
@ -873,9 +857,9 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
if (likely(fence != NULL))
vmw_fence_obj_unreference(&fence);
vmw_kms_cursor_post_execbuf(dev_priv);
ttm_read_unlock(&vmaster->lock);
mutex_unlock(&dev_priv->cmdbuf_mutex);
return 0;
out_err:
vmw_free_relocations(sw_context);
out_throttle:
@ -883,7 +867,47 @@ out_throttle:
vmw_clear_validations(sw_context);
out_unlock:
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);
return ret;
}