virtio-gpu: add 3d/virgl support
Add the bits needed for opengl rendering support: query capabilities, new virtio commands, drm ioctls. Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
@@ -52,6 +52,41 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
|
||||
events_clear, &events_clear);
|
||||
}
|
||||
|
||||
static void virtio_gpu_ctx_id_get(struct virtio_gpu_device *vgdev,
|
||||
uint32_t *resid)
|
||||
{
|
||||
int handle;
|
||||
|
||||
idr_preload(GFP_KERNEL);
|
||||
spin_lock(&vgdev->ctx_id_idr_lock);
|
||||
handle = idr_alloc(&vgdev->ctx_id_idr, NULL, 1, 0, 0);
|
||||
spin_unlock(&vgdev->ctx_id_idr_lock);
|
||||
idr_preload_end();
|
||||
*resid = handle;
|
||||
}
|
||||
|
||||
static void virtio_gpu_ctx_id_put(struct virtio_gpu_device *vgdev, uint32_t id)
|
||||
{
|
||||
spin_lock(&vgdev->ctx_id_idr_lock);
|
||||
idr_remove(&vgdev->ctx_id_idr, id);
|
||||
spin_unlock(&vgdev->ctx_id_idr_lock);
|
||||
}
|
||||
|
||||
static void virtio_gpu_context_create(struct virtio_gpu_device *vgdev,
|
||||
uint32_t nlen, const char *name,
|
||||
uint32_t *ctx_id)
|
||||
{
|
||||
virtio_gpu_ctx_id_get(vgdev, ctx_id);
|
||||
virtio_gpu_cmd_context_create(vgdev, *ctx_id, nlen, name);
|
||||
}
|
||||
|
||||
static void virtio_gpu_context_destroy(struct virtio_gpu_device *vgdev,
|
||||
uint32_t ctx_id)
|
||||
{
|
||||
virtio_gpu_cmd_context_destroy(vgdev, ctx_id);
|
||||
virtio_gpu_ctx_id_put(vgdev, ctx_id);
|
||||
}
|
||||
|
||||
static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq,
|
||||
void (*work_func)(struct work_struct *work))
|
||||
{
|
||||
@@ -60,6 +95,36 @@ static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq,
|
||||
INIT_WORK(&vgvq->dequeue_work, work_func);
|
||||
}
|
||||
|
||||
static void virtio_gpu_get_capsets(struct virtio_gpu_device *vgdev,
|
||||
int num_capsets)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
vgdev->capsets = kcalloc(num_capsets,
|
||||
sizeof(struct virtio_gpu_drv_capset),
|
||||
GFP_KERNEL);
|
||||
if (!vgdev->capsets) {
|
||||
DRM_ERROR("failed to allocate cap sets\n");
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < num_capsets; i++) {
|
||||
virtio_gpu_cmd_get_capset_info(vgdev, i);
|
||||
ret = wait_event_timeout(vgdev->resp_wq,
|
||||
vgdev->capsets[i].id > 0, 5 * HZ);
|
||||
if (ret == 0) {
|
||||
DRM_ERROR("timed out waiting for cap set %d\n", i);
|
||||
kfree(vgdev->capsets);
|
||||
vgdev->capsets = NULL;
|
||||
return;
|
||||
}
|
||||
DRM_INFO("cap set %d: id %d, max-version %d, max-size %d\n",
|
||||
i, vgdev->capsets[i].id,
|
||||
vgdev->capsets[i].max_version,
|
||||
vgdev->capsets[i].max_size);
|
||||
}
|
||||
vgdev->num_capsets = num_capsets;
|
||||
}
|
||||
|
||||
int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
{
|
||||
static vq_callback_t *callbacks[] = {
|
||||
@@ -70,7 +135,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
struct virtio_gpu_device *vgdev;
|
||||
/* this will expand later */
|
||||
struct virtqueue *vqs[2];
|
||||
u32 num_scanouts;
|
||||
u32 num_scanouts, num_capsets;
|
||||
int ret;
|
||||
|
||||
if (!virtio_has_feature(dev->virtdev, VIRTIO_F_VERSION_1))
|
||||
@@ -96,9 +161,15 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
|
||||
spin_lock_init(&vgdev->fence_drv.lock);
|
||||
INIT_LIST_HEAD(&vgdev->fence_drv.fences);
|
||||
INIT_LIST_HEAD(&vgdev->cap_cache);
|
||||
INIT_WORK(&vgdev->config_changed_work,
|
||||
virtio_gpu_config_changed_work_func);
|
||||
|
||||
if (virtio_has_feature(vgdev->vdev, VIRTIO_GPU_F_VIRGL))
|
||||
vgdev->has_virgl_3d = true;
|
||||
DRM_INFO("virgl 3d acceleration %s\n",
|
||||
vgdev->has_virgl_3d ? "enabled" : "not available");
|
||||
|
||||
ret = vgdev->vdev->config->find_vqs(vgdev->vdev, 2, vqs,
|
||||
callbacks, names);
|
||||
if (ret) {
|
||||
@@ -129,6 +200,11 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
ret = -EINVAL;
|
||||
goto err_scanouts;
|
||||
}
|
||||
DRM_INFO("number of scanouts: %d\n", num_scanouts);
|
||||
|
||||
virtio_cread(vgdev->vdev, struct virtio_gpu_config,
|
||||
num_capsets, &num_capsets);
|
||||
DRM_INFO("number of cap sets: %d\n", num_capsets);
|
||||
|
||||
ret = virtio_gpu_modeset_init(vgdev);
|
||||
if (ret)
|
||||
@@ -137,6 +213,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
virtio_device_ready(vgdev->vdev);
|
||||
vgdev->vqs_ready = true;
|
||||
|
||||
if (num_capsets)
|
||||
virtio_gpu_get_capsets(vgdev, num_capsets);
|
||||
virtio_gpu_cmd_get_display_info(vgdev);
|
||||
wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending,
|
||||
5 * HZ);
|
||||
@@ -157,6 +235,16 @@ err_vqs:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void virtio_gpu_cleanup_cap_cache(struct virtio_gpu_device *vgdev)
|
||||
{
|
||||
struct virtio_gpu_drv_cap_cache *cache_ent, *tmp;
|
||||
|
||||
list_for_each_entry_safe(cache_ent, tmp, &vgdev->cap_cache, head) {
|
||||
kfree(cache_ent->caps_cache);
|
||||
kfree(cache_ent);
|
||||
}
|
||||
}
|
||||
|
||||
int virtio_gpu_driver_unload(struct drm_device *dev)
|
||||
{
|
||||
struct virtio_gpu_device *vgdev = dev->dev_private;
|
||||
@@ -170,6 +258,49 @@ int virtio_gpu_driver_unload(struct drm_device *dev)
|
||||
virtio_gpu_modeset_fini(vgdev);
|
||||
virtio_gpu_ttm_fini(vgdev);
|
||||
virtio_gpu_free_vbufs(vgdev);
|
||||
virtio_gpu_cleanup_cap_cache(vgdev);
|
||||
kfree(vgdev->capsets);
|
||||
kfree(vgdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct virtio_gpu_device *vgdev = dev->dev_private;
|
||||
struct virtio_gpu_fpriv *vfpriv;
|
||||
uint32_t id;
|
||||
char dbgname[64], tmpname[TASK_COMM_LEN];
|
||||
|
||||
/* can't create contexts without 3d renderer */
|
||||
if (!vgdev->has_virgl_3d)
|
||||
return 0;
|
||||
|
||||
get_task_comm(tmpname, current);
|
||||
snprintf(dbgname, sizeof(dbgname), "%s", tmpname);
|
||||
dbgname[63] = 0;
|
||||
/* allocate a virt GPU context for this opener */
|
||||
vfpriv = kzalloc(sizeof(*vfpriv), GFP_KERNEL);
|
||||
if (!vfpriv)
|
||||
return -ENOMEM;
|
||||
|
||||
virtio_gpu_context_create(vgdev, strlen(dbgname), dbgname, &id);
|
||||
|
||||
vfpriv->ctx_id = id;
|
||||
file->driver_priv = vfpriv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct virtio_gpu_device *vgdev = dev->dev_private;
|
||||
struct virtio_gpu_fpriv *vfpriv;
|
||||
|
||||
if (!vgdev->has_virgl_3d)
|
||||
return;
|
||||
|
||||
vfpriv = file->driver_priv;
|
||||
|
||||
virtio_gpu_context_destroy(vgdev, vfpriv->ctx_id);
|
||||
kfree(vfpriv);
|
||||
file->driver_priv = NULL;
|
||||
}
|
||||
|
Reference in New Issue
Block a user