vmwgfx: Break out execbuf command processing
authorThomas Hellstrom <thellstrom@vmware.com>
Tue, 4 Oct 2011 18:13:17 +0000 (20:13 +0200)
committerDave Airlie <airlied@redhat.com>
Wed, 5 Oct 2011 09:17:11 +0000 (10:17 +0100)
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>
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c

index 564a815..edd1e83 100644 (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
index cc8c08b..542c852 100644 (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;
+       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;
 }