Commit 4fb530e5 authored by Anthoine Bourgeois's avatar Anthoine Bourgeois Committed by Gerd Hoffmann
Browse files

drm/virtio: implement context init: support init ioctl



This implements the context initialization ioctl.  A list of params
is passed in by userspace, and kernel driver validates them.  The
only currently supported param is VIRTGPU_CONTEXT_PARAM_CAPSET_ID.

If the context has already been initialized, -EEXIST is returned.
This happens after Linux userspace does dumb_create + followed by
opening the Mesa virgl driver with the same virtgpu instance.

However, for most applications, 3D contexts will be explicitly
initialized when the feature is available.

Signed-off-by: default avatarAnthoine Bourgeois <anthoine.bourgeois@gmail.com>
Acked-by: default avatarLingfeng Yang <lfy@google.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20210921232024.817-6-gurchetansingh@chromium.org


Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent 6198770a
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -259,12 +259,13 @@ struct virtio_gpu_device {

struct virtio_gpu_fpriv {
	uint32_t ctx_id;
	uint32_t context_init;
	bool context_created;
	struct mutex context_lock;
};

/* virtgpu_ioctl.c */
#define DRM_VIRTIO_NUM_IOCTLS 11
#define DRM_VIRTIO_NUM_IOCTLS 12
extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS];
void virtio_gpu_create_context(struct drm_device *dev, struct drm_file *file);

@@ -342,7 +343,8 @@ int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
			      struct virtio_gpu_drv_cap_cache **cache_p);
int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev);
void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
				   uint32_t nlen, const char *name);
				   uint32_t context_init, uint32_t nlen,
				   const char *name);
void virtio_gpu_cmd_context_destroy(struct virtio_gpu_device *vgdev,
				    uint32_t id);
void virtio_gpu_cmd_context_attach_resource(struct virtio_gpu_device *vgdev,
+91 −5
Original line number Diff line number Diff line
@@ -38,20 +38,30 @@
				    VIRTGPU_BLOB_FLAG_USE_SHAREABLE | \
				    VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE)

/* Must be called with &virtio_gpu_fpriv.struct_mutex held. */
static void virtio_gpu_create_context_locked(struct virtio_gpu_device *vgdev,
					     struct virtio_gpu_fpriv *vfpriv)
{
	char dbgname[TASK_COMM_LEN];

	get_task_comm(dbgname, current);
	virtio_gpu_cmd_context_create(vgdev, vfpriv->ctx_id,
				      vfpriv->context_init, strlen(dbgname),
				      dbgname);

	vfpriv->context_created = true;
}

void virtio_gpu_create_context(struct drm_device *dev, struct drm_file *file)
{
	struct virtio_gpu_device *vgdev = dev->dev_private;
	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
	char dbgname[TASK_COMM_LEN];

	mutex_lock(&vfpriv->context_lock);
	if (vfpriv->context_created)
		goto out_unlock;

	get_task_comm(dbgname, current);
	virtio_gpu_cmd_context_create(vgdev, vfpriv->ctx_id,
				      strlen(dbgname), dbgname);
	vfpriv->context_created = true;
	virtio_gpu_create_context_locked(vgdev, vfpriv);

out_unlock:
	mutex_unlock(&vfpriv->context_lock);
@@ -662,6 +672,79 @@ static int virtio_gpu_resource_create_blob_ioctl(struct drm_device *dev,
	return 0;
}

static int virtio_gpu_context_init_ioctl(struct drm_device *dev,
					 void *data, struct drm_file *file)
{
	int ret = 0;
	uint32_t num_params, i, param, value;
	size_t len;
	struct drm_virtgpu_context_set_param *ctx_set_params = NULL;
	struct virtio_gpu_device *vgdev = dev->dev_private;
	struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
	struct drm_virtgpu_context_init *args = data;

	num_params = args->num_params;
	len = num_params * sizeof(struct drm_virtgpu_context_set_param);

	if (!vgdev->has_context_init || !vgdev->has_virgl_3d)
		return -EINVAL;

	/* Number of unique parameters supported at this time. */
	if (num_params > 1)
		return -EINVAL;

	ctx_set_params = memdup_user(u64_to_user_ptr(args->ctx_set_params),
				     len);

	if (IS_ERR(ctx_set_params))
		return PTR_ERR(ctx_set_params);

	mutex_lock(&vfpriv->context_lock);
	if (vfpriv->context_created) {
		ret = -EEXIST;
		goto out_unlock;
	}

	for (i = 0; i < num_params; i++) {
		param = ctx_set_params[i].param;
		value = ctx_set_params[i].value;

		switch (param) {
		case VIRTGPU_CONTEXT_PARAM_CAPSET_ID:
			if (value > MAX_CAPSET_ID) {
				ret = -EINVAL;
				goto out_unlock;
			}

			if ((vgdev->capset_id_mask & (1 << value)) == 0) {
				ret = -EINVAL;
				goto out_unlock;
			}

			/* Context capset ID already set */
			if (vfpriv->context_init &
			    VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK) {
				ret = -EINVAL;
				goto out_unlock;
			}

			vfpriv->context_init |= value;
			break;
		default:
			ret = -EINVAL;
			goto out_unlock;
		}
	}

	virtio_gpu_create_context_locked(vgdev, vfpriv);
	virtio_gpu_notify(vgdev);

out_unlock:
	mutex_unlock(&vfpriv->context_lock);
	kfree(ctx_set_params);
	return ret;
}

struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = {
	DRM_IOCTL_DEF_DRV(VIRTGPU_MAP, virtio_gpu_map_ioctl,
			  DRM_RENDER_ALLOW),
@@ -698,4 +781,7 @@ struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS] = {
	DRM_IOCTL_DEF_DRV(VIRTGPU_RESOURCE_CREATE_BLOB,
			  virtio_gpu_resource_create_blob_ioctl,
			  DRM_RENDER_ALLOW),

	DRM_IOCTL_DEF_DRV(VIRTGPU_CONTEXT_INIT, virtio_gpu_context_init_ioctl,
			  DRM_RENDER_ALLOW),
};
+3 −1
Original line number Diff line number Diff line
@@ -911,7 +911,8 @@ int virtio_gpu_cmd_get_edids(struct virtio_gpu_device *vgdev)
}

void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
				   uint32_t nlen, const char *name)
				   uint32_t context_init, uint32_t nlen,
				   const char *name)
{
	struct virtio_gpu_ctx_create *cmd_p;
	struct virtio_gpu_vbuffer *vbuf;
@@ -922,6 +923,7 @@ void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
	cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_CTX_CREATE);
	cmd_p->hdr.ctx_id = cpu_to_le32(id);
	cmd_p->nlen = cpu_to_le32(nlen);
	cmd_p->context_init = cpu_to_le32(context_init);
	strncpy(cmd_p->debug_name, name, sizeof(cmd_p->debug_name) - 1);
	cmd_p->debug_name[sizeof(cmd_p->debug_name) - 1] = 0;
	virtio_gpu_queue_ctrl_buffer(vgdev, vbuf);