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: Anthoine Bourgeois <anthoine.bourgeois@gmail.com>
Acked-by: Lingfeng Yang <lfy@google.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20210921232024.817-6-gurchetansingh@chromium.org
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Anthoine Bourgeois
2021-09-21 16:20:17 -07:00
committed by Gerd Hoffmann
parent 6198770a1f
commit 4fb530e5ca
3 changed files with 98 additions and 8 deletions

View File

@@ -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),
};