From: Thomas Hellstrom Date: Tue, 4 Oct 2011 18:13:17 +0000 (+0200) Subject: vmwgfx: Break out execbuf command processing X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=922ade0d16d24be2040be7d55dbb734af779a1dd;p=linux-beck.git 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 Signed-off-by: Jakob Bornecrantz Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie --- diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 564a81582111..edd1e8362f3b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -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 diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index cc8c08b35102..542c852f8eb5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -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; + 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; @@ -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; }