OSDN Git Service

drm/virtio: implement context init: support init ioctl
authorAnthoine Bourgeois <anthoine.bourgeois@gmail.com>
Tue, 21 Sep 2021 23:20:17 +0000 (16:20 -0700)
committerGerd Hoffmann <kraxel@redhat.com>
Wed, 29 Sep 2021 07:22:30 +0000 (09:22 +0200)
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>
drivers/gpu/drm/virtio/virtgpu_drv.h
drivers/gpu/drm/virtio/virtgpu_ioctl.c
drivers/gpu/drm/virtio/virtgpu_vq.c

index 5e1958a..9996abf 100644 (file)
@@ -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,
index 5c1ad15..f5281d1 100644 (file)
                                    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),
 };
index 93a41d0..db77415 100644 (file)
@@ -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);