Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 922ade0d authored by Thomas Hellstrom's avatar Thomas Hellstrom Committed by Dave Airlie
Browse files

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: default avatarThomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: default avatarJakob Bornecrantz <jakob@vmware.com>
Reviewed-by: default avatarJakob Bornecrantz <jakob@vmware.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 6070e9fa
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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
+80 −56
Original line number Diff line number Diff line
@@ -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;

@@ -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);
		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);
				     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 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
	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;
}