Skip to content

Commit

Permalink
vmwgfx: Break out execbuf command processing
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Thomas Hellstrom authored and Dave Airlie committed Oct 5, 2011
1 parent 6070e9f commit 922ade0
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 56 deletions.
9 changes: 9 additions & 0 deletions drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
136 changes: 80 additions & 56 deletions drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct vmw_sw_context *sw_context,
void *buf,
uint32_t size)
{
void *buf = sw_context->cmd_bounce;
int32_t cur_size = size;
int ret;

Expand Down Expand Up @@ -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;
void *cmd;
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);
ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
if (unlikely(ret != 0))
return ret;
return -ERESTARTSYS;

ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
if (unlikely(ret != 0)) {
ret = -ERESTARTSYS;
goto out_no_cmd_mutex;
}
if (kernel_commands == NULL) {
sw_context->kernel = false;

ret = vmw_resize_cmd_bounce(sw_context, arg->command_size);
if (unlikely(ret != 0))
goto out_unlock;
ret = vmw_resize_cmd_bounce(sw_context, command_size);
if (unlikely(ret != 0))
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 = -EFAULT;
DRM_ERROR("Failed copying commands.\n");
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;
Expand All @@ -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;

Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -873,17 +857,57 @@ 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:
ttm_eu_backoff_reservation(&sw_context->validate_nodes);
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;
}

0 comments on commit 922ade0

Please sign in to comment.