Commit 31875672 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'virtio-gpu-for-drm-next' of git://git.kraxel.org/linux into drm-next

Add 3D support to the virtio-gpu.

* 'virtio-gpu-for-drm-next' of git://git.kraxel.org/linux:
  virtio-gpu: add page flip support
  virtio-gpu: mark as a render gpu
  virtio-gpu: add basic prime support
  virtio-gpu: add 3d/virgl support
  virtio-gpu: don't free things on ttm_bo_init failure
  virtio-gpu: wait for cursor updates finish
  virtio-gpu: add & use virtio_gpu_queue_fenced_ctrl_buffer
  virtio-gpu: add virtio_gpu_queue_ctrl_buffer_locked
parents c76af02d d24796a4
...@@ -6,6 +6,7 @@ ccflags-y := -Iinclude/drm ...@@ -6,6 +6,7 @@ ccflags-y := -Iinclude/drm
virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_drm_bus.o virtgpu_gem.o \ virtio-gpu-y := virtgpu_drv.o virtgpu_kms.o virtgpu_drm_bus.o virtgpu_gem.o \
virtgpu_fb.o virtgpu_display.o virtgpu_vq.o virtgpu_ttm.o \ virtgpu_fb.o virtgpu_display.o virtgpu_vq.o virtgpu_ttm.o \
virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o virtgpu_fence.o virtgpu_object.o virtgpu_debugfs.o virtgpu_plane.o \
virtgpu_ioctl.o virtgpu_prime.o
obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio-gpu.o obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio-gpu.o
...@@ -90,6 +90,14 @@ static int virtio_gpu_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -90,6 +90,14 @@ static int virtio_gpu_crtc_cursor_set(struct drm_crtc *crtc,
cpu_to_le32(64), cpu_to_le32(64),
cpu_to_le32(64), cpu_to_le32(64),
0, 0, &fence); 0, 0, &fence);
ret = virtio_gpu_object_reserve(qobj, false);
if (!ret) {
reservation_object_add_excl_fence(qobj->tbo.resv,
&fence->f);
fence_put(&fence->f);
virtio_gpu_object_unreserve(qobj);
virtio_gpu_object_wait(qobj, false);
}
output->cursor.hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR); output->cursor.hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR);
output->cursor.resource_id = cpu_to_le32(qobj->hw_res_handle); output->cursor.resource_id = cpu_to_le32(qobj->hw_res_handle);
...@@ -117,6 +125,51 @@ static int virtio_gpu_crtc_cursor_move(struct drm_crtc *crtc, ...@@ -117,6 +125,51 @@ static int virtio_gpu_crtc_cursor_move(struct drm_crtc *crtc,
return 0; return 0;
} }
static int virtio_gpu_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t flags)
{
struct virtio_gpu_device *vgdev = crtc->dev->dev_private;
struct virtio_gpu_output *output =
container_of(crtc, struct virtio_gpu_output, crtc);
struct drm_plane *plane = crtc->primary;
struct virtio_gpu_framebuffer *vgfb;
struct virtio_gpu_object *bo;
unsigned long irqflags;
uint32_t handle;
plane->fb = fb;
vgfb = to_virtio_gpu_framebuffer(plane->fb);
bo = gem_to_virtio_gpu_obj(vgfb->obj);
handle = bo->hw_res_handle;
DRM_DEBUG("handle 0x%x%s, crtc %dx%d\n", handle,
bo->dumb ? ", dumb" : "",
crtc->mode.hdisplay, crtc->mode.vdisplay);
if (bo->dumb) {
virtio_gpu_cmd_transfer_to_host_2d
(vgdev, handle, 0,
cpu_to_le32(crtc->mode.hdisplay),
cpu_to_le32(crtc->mode.vdisplay),
0, 0, NULL);
}
virtio_gpu_cmd_set_scanout(vgdev, output->index, handle,
crtc->mode.hdisplay,
crtc->mode.vdisplay, 0, 0);
virtio_gpu_cmd_resource_flush(vgdev, handle, 0, 0,
crtc->mode.hdisplay,
crtc->mode.vdisplay);
if (event) {
spin_lock_irqsave(&crtc->dev->event_lock, irqflags);
drm_send_vblank_event(crtc->dev, -1, event);
spin_unlock_irqrestore(&crtc->dev->event_lock, irqflags);
}
return 0;
}
static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = { static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = {
.cursor_set2 = virtio_gpu_crtc_cursor_set, .cursor_set2 = virtio_gpu_crtc_cursor_set,
.cursor_move = virtio_gpu_crtc_cursor_move, .cursor_move = virtio_gpu_crtc_cursor_move,
...@@ -124,9 +177,7 @@ static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = { ...@@ -124,9 +177,7 @@ static const struct drm_crtc_funcs virtio_gpu_crtc_funcs = {
.set_config = drm_atomic_helper_set_config, .set_config = drm_atomic_helper_set_config,
.destroy = drm_crtc_cleanup, .destroy = drm_crtc_cleanup,
#if 0 /* not (yet) working without vblank support according to docs */ .page_flip = virtio_gpu_page_flip,
.page_flip = drm_atomic_helper_page_flip,
#endif
.reset = drm_atomic_helper_crtc_reset, .reset = drm_atomic_helper_crtc_reset,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
......
...@@ -73,6 +73,14 @@ static struct virtio_device_id id_table[] = { ...@@ -73,6 +73,14 @@ static struct virtio_device_id id_table[] = {
}; };
static unsigned int features[] = { static unsigned int features[] = {
#ifdef __LITTLE_ENDIAN
/*
* Gallium command stream send by virgl is native endian.
* Because of that we only support little endian guests on
* little endian hosts.
*/
VIRTIO_GPU_F_VIRGL,
#endif
}; };
static struct virtio_driver virtio_gpu_driver = { static struct virtio_driver virtio_gpu_driver = {
.feature_table = features, .feature_table = features,
...@@ -110,10 +118,12 @@ static const struct file_operations virtio_gpu_driver_fops = { ...@@ -110,10 +118,12 @@ static const struct file_operations virtio_gpu_driver_fops = {
static struct drm_driver driver = { static struct drm_driver driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM, .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER,
.set_busid = drm_virtio_set_busid, .set_busid = drm_virtio_set_busid,
.load = virtio_gpu_driver_load, .load = virtio_gpu_driver_load,
.unload = virtio_gpu_driver_unload, .unload = virtio_gpu_driver_unload,
.open = virtio_gpu_driver_open,
.postclose = virtio_gpu_driver_postclose,
.dumb_create = virtio_gpu_mode_dumb_create, .dumb_create = virtio_gpu_mode_dumb_create,
.dumb_map_offset = virtio_gpu_mode_dumb_mmap, .dumb_map_offset = virtio_gpu_mode_dumb_mmap,
...@@ -123,10 +133,26 @@ static struct drm_driver driver = { ...@@ -123,10 +133,26 @@ static struct drm_driver driver = {
.debugfs_init = virtio_gpu_debugfs_init, .debugfs_init = virtio_gpu_debugfs_init,
.debugfs_cleanup = virtio_gpu_debugfs_takedown, .debugfs_cleanup = virtio_gpu_debugfs_takedown,
#endif #endif
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_pin = virtgpu_gem_prime_pin,
.gem_prime_unpin = virtgpu_gem_prime_unpin,
.gem_prime_get_sg_table = virtgpu_gem_prime_get_sg_table,
.gem_prime_import_sg_table = virtgpu_gem_prime_import_sg_table,
.gem_prime_vmap = virtgpu_gem_prime_vmap,
.gem_prime_vunmap = virtgpu_gem_prime_vunmap,
.gem_prime_mmap = virtgpu_gem_prime_mmap,
.gem_free_object = virtio_gpu_gem_free_object, .gem_free_object = virtio_gpu_gem_free_object,
.gem_open_object = virtio_gpu_gem_object_open,
.gem_close_object = virtio_gpu_gem_object_close,
.fops = &virtio_gpu_driver_fops, .fops = &virtio_gpu_driver_fops,
.ioctls = virtio_gpu_ioctls,
.num_ioctls = DRM_VIRTIO_NUM_IOCTLS,
.name = DRIVER_NAME, .name = DRIVER_NAME,
.desc = DRIVER_DESC, .desc = DRIVER_DESC,
.date = DRIVER_DATE, .date = DRIVER_DATE,
......
...@@ -146,6 +146,21 @@ struct virtio_gpu_queue { ...@@ -146,6 +146,21 @@ struct virtio_gpu_queue {
struct work_struct dequeue_work; struct work_struct dequeue_work;
}; };
struct virtio_gpu_drv_capset {
uint32_t id;
uint32_t max_version;
uint32_t max_size;
};
struct virtio_gpu_drv_cap_cache {
struct list_head head;
void *caps_cache;
uint32_t id;
uint32_t version;
uint32_t size;
atomic_t is_valid;
};
struct virtio_gpu_device { struct virtio_gpu_device {
struct device *dev; struct device *dev;
struct drm_device *ddev; struct drm_device *ddev;
...@@ -179,7 +194,13 @@ struct virtio_gpu_device { ...@@ -179,7 +194,13 @@ struct virtio_gpu_device {
struct idr ctx_id_idr; struct idr ctx_id_idr;
spinlock_t ctx_id_idr_lock; spinlock_t ctx_id_idr_lock;
bool has_virgl_3d;
struct work_struct config_changed_work; struct work_struct config_changed_work;
struct virtio_gpu_drv_capset *capsets;
uint32_t num_capsets;
struct list_head cap_cache;
}; };
struct virtio_gpu_fpriv { struct virtio_gpu_fpriv {
...@@ -193,6 +214,8 @@ extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS]; ...@@ -193,6 +214,8 @@ extern struct drm_ioctl_desc virtio_gpu_ioctls[DRM_VIRTIO_NUM_IOCTLS];
/* virtio_kms.c */ /* virtio_kms.c */
int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags); int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags);
int virtio_gpu_driver_unload(struct drm_device *dev); int virtio_gpu_driver_unload(struct drm_device *dev);
int virtio_gpu_driver_open(struct drm_device *dev, struct drm_file *file);
void virtio_gpu_driver_postclose(struct drm_device *dev, struct drm_file *file);
/* virtio_gem.c */ /* virtio_gem.c */
void virtio_gpu_gem_free_object(struct drm_gem_object *gem_obj); void virtio_gpu_gem_free_object(struct drm_gem_object *gem_obj);
...@@ -203,6 +226,10 @@ int virtio_gpu_gem_create(struct drm_file *file, ...@@ -203,6 +226,10 @@ int virtio_gpu_gem_create(struct drm_file *file,
uint64_t size, uint64_t size,
struct drm_gem_object **obj_p, struct drm_gem_object **obj_p,
uint32_t *handle_p); uint32_t *handle_p);
int virtio_gpu_gem_object_open(struct drm_gem_object *obj,
struct drm_file *file);
void virtio_gpu_gem_object_close(struct drm_gem_object *obj,
struct drm_file *file);
struct virtio_gpu_object *virtio_gpu_alloc_object(struct drm_device *dev, struct virtio_gpu_object *virtio_gpu_alloc_object(struct drm_device *dev,
size_t size, bool kernel, size_t size, bool kernel,
bool pinned); bool pinned);
...@@ -260,10 +287,43 @@ void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev, ...@@ -260,10 +287,43 @@ void virtio_gpu_cursor_ping(struct virtio_gpu_device *vgdev,
int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev); int virtio_gpu_cmd_get_display_info(struct virtio_gpu_device *vgdev);
void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev, void virtio_gpu_cmd_resource_inval_backing(struct virtio_gpu_device *vgdev,
uint32_t resource_id); uint32_t resource_id);
int virtio_gpu_cmd_get_capset_info(struct virtio_gpu_device *vgdev, int idx);
int virtio_gpu_cmd_get_capset(struct virtio_gpu_device *vgdev,
int idx, int version,
struct virtio_gpu_drv_cap_cache **cache_p);
void virtio_gpu_cmd_context_create(struct virtio_gpu_device *vgdev, uint32_t id,
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,
uint32_t ctx_id,
uint32_t resource_id);
void virtio_gpu_cmd_context_detach_resource(struct virtio_gpu_device *vgdev,
uint32_t ctx_id,
uint32_t resource_id);
void virtio_gpu_cmd_submit(struct virtio_gpu_device *vgdev,
void *data, uint32_t data_size,
uint32_t ctx_id, struct virtio_gpu_fence **fence);
void virtio_gpu_cmd_transfer_from_host_3d(struct virtio_gpu_device *vgdev,
uint32_t resource_id, uint32_t ctx_id,
uint64_t offset, uint32_t level,
struct virtio_gpu_box *box,
struct virtio_gpu_fence **fence);
void virtio_gpu_cmd_transfer_to_host_3d(struct virtio_gpu_device *vgdev,
uint32_t resource_id, uint32_t ctx_id,
uint64_t offset, uint32_t level,
struct virtio_gpu_box *box,
struct virtio_gpu_fence **fence);
void
virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
struct virtio_gpu_resource_create_3d *rc_3d,
struct virtio_gpu_fence **fence);
void virtio_gpu_ctrl_ack(struct virtqueue *vq); void virtio_gpu_ctrl_ack(struct virtqueue *vq);
void virtio_gpu_cursor_ack(struct virtqueue *vq); void virtio_gpu_cursor_ack(struct virtqueue *vq);
void virtio_gpu_fence_ack(struct virtqueue *vq);
void virtio_gpu_dequeue_ctrl_func(struct work_struct *work); void virtio_gpu_dequeue_ctrl_func(struct work_struct *work);
void virtio_gpu_dequeue_cursor_func(struct work_struct *work); void virtio_gpu_dequeue_cursor_func(struct work_struct *work);
void virtio_gpu_dequeue_fence_func(struct work_struct *work);
/* virtio_gpu_display.c */ /* virtio_gpu_display.c */
int virtio_gpu_framebuffer_init(struct drm_device *dev, int virtio_gpu_framebuffer_init(struct drm_device *dev,
...@@ -299,6 +359,18 @@ int virtio_gpu_object_get_sg_table(struct virtio_gpu_device *qdev, ...@@ -299,6 +359,18 @@ int virtio_gpu_object_get_sg_table(struct virtio_gpu_device *qdev,
void virtio_gpu_object_free_sg_table(struct virtio_gpu_object *bo); void virtio_gpu_object_free_sg_table(struct virtio_gpu_object *bo);
int virtio_gpu_object_wait(struct virtio_gpu_object *bo, bool no_wait); int virtio_gpu_object_wait(struct virtio_gpu_object *bo, bool no_wait);
/* virtgpu_prime.c */
int virtgpu_gem_prime_pin(struct drm_gem_object *obj);
void virtgpu_gem_prime_unpin(struct drm_gem_object *obj);
struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj);
struct drm_gem_object *virtgpu_gem_prime_import_sg_table(
struct drm_device *dev, struct dma_buf_attachment *attach,
struct sg_table *sgt);
void *virtgpu_gem_prime_vmap(struct drm_gem_object *obj);
void virtgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
int virtgpu_gem_prime_mmap(struct drm_gem_object *obj,
struct vm_area_struct *vma);
static inline struct virtio_gpu_object* static inline struct virtio_gpu_object*
virtio_gpu_object_ref(struct virtio_gpu_object *bo) virtio_gpu_object_ref(struct virtio_gpu_object *bo)
{ {
......
...@@ -81,7 +81,7 @@ int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev, ...@@ -81,7 +81,7 @@ int virtio_gpu_fence_emit(struct virtio_gpu_device *vgdev,
struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv; struct virtio_gpu_fence_driver *drv = &vgdev->fence_drv;
unsigned long irq_flags; unsigned long irq_flags;
*fence = kmalloc(sizeof(struct virtio_gpu_fence), GFP_KERNEL); *fence = kmalloc(sizeof(struct virtio_gpu_fence), GFP_ATOMIC);
if ((*fence) == NULL) if ((*fence) == NULL)
return -ENOMEM; return -ENOMEM;
......
...@@ -138,3 +138,44 @@ int virtio_gpu_mode_dumb_mmap(struct drm_file *file_priv, ...@@ -138,3 +138,44 @@ int virtio_gpu_mode_dumb_mmap(struct drm_file *file_priv,
drm_gem_object_unreference_unlocked(gobj); drm_gem_object_unreference_unlocked(gobj);
return 0; return 0;
} }
int virtio_gpu_gem_object_open(struct drm_gem_object *obj,
struct drm_file *file)
{
struct virtio_gpu_device *vgdev = obj->dev->dev_private;
struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
struct virtio_gpu_object *qobj = gem_to_virtio_gpu_obj(obj);
int r;
if (!vgdev->has_virgl_3d)
return 0;
r = virtio_gpu_object_reserve(qobj, false);
if (r)
return r;
virtio_gpu_cmd_context_attach_resource(vgdev, vfpriv->ctx_id,
qobj->hw_res_handle);
virtio_gpu_object_unreserve(qobj);
return 0;
}
void virtio_gpu_gem_object_close(struct drm_gem_object *obj,
struct drm_file *file)
{
struct virtio_gpu_device *vgdev = obj->dev->dev_private;
struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
struct virtio_gpu_object *qobj = gem_to_virtio_gpu_obj(obj);
int r;
if (!vgdev->has_virgl_3d)
return;
r = virtio_gpu_object_reserve(qobj, false);
if (r)
return;
virtio_gpu_cmd_context_detach_resource(vgdev, vfpriv->ctx_id,
qobj->hw_res_handle);
virtio_gpu_object_unreserve(qobj);
}
This diff is collapsed.
...@@ -52,6 +52,41 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work) ...@@ -52,6 +52,41 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
events_clear, &events_clear); 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, static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq,
void (*work_func)(struct work_struct *work)) void (*work_func)(struct work_struct *work))
{ {
...@@ -60,6 +95,36 @@ static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq, ...@@ -60,6 +95,36 @@ static void virtio_gpu_init_vq(struct virtio_gpu_queue *vgvq,
INIT_WORK(&vgvq->dequeue_work, work_func); 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) int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
{ {
static vq_callback_t *callbacks[] = { static vq_callback_t *callbacks[] = {
...@@ -70,7 +135,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -70,7 +135,7 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
struct virtio_gpu_device *vgdev; struct virtio_gpu_device *vgdev;
/* this will expand later */ /* this will expand later */
struct virtqueue *vqs[2]; struct virtqueue *vqs[2];
u32 num_scanouts; u32 num_scanouts, num_capsets;
int ret; int ret;
if (!virtio_has_feature(dev->virtdev, VIRTIO_F_VERSION_1)) 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) ...@@ -96,9 +161,15 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&vgdev->fence_drv.lock); spin_lock_init(&vgdev->fence_drv.lock);
INIT_LIST_HEAD(&vgdev->fence_drv.fences); INIT_LIST_HEAD(&vgdev->fence_drv.fences);
INIT_LIST_HEAD(&vgdev->cap_cache);
INIT_WORK(&vgdev->config_changed_work, INIT_WORK(&vgdev->config_changed_work,
virtio_gpu_config_changed_work_func); 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, ret = vgdev->vdev->config->find_vqs(vgdev->vdev, 2, vqs,
callbacks, names); callbacks, names);
if (ret) { if (ret) {
...@@ -129,6 +200,11 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -129,6 +200,11 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
ret = -EINVAL; ret = -EINVAL;
goto err_scanouts; 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); ret = virtio_gpu_modeset_init(vgdev);
if (ret) if (ret)
...@@ -137,6 +213,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -137,6 +213,8 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
virtio_device_ready(vgdev->vdev); virtio_device_ready(vgdev->vdev);
vgdev->vqs_ready = true; vgdev->vqs_ready = true;
if (num_capsets)
virtio_gpu_get_capsets(vgdev, num_capsets);
virtio_gpu_cmd_get_display_info(vgdev); virtio_gpu_cmd_get_display_info(vgdev);
wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending, wait_event_timeout(vgdev->resp_wq, !vgdev->display_info_pending,
5 * HZ); 5 * HZ);
...@@ -157,6 +235,16 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags) ...@@ -157,6 +235,16 @@ int virtio_gpu_driver_load(struct drm_device *dev, unsigned long flags)
return ret; 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) int virtio_gpu_driver_unload(struct drm_device *dev)
{ {
struct virtio_gpu_device *vgdev = dev->dev_private; struct virtio_gpu_device *vgdev = dev->dev_private;
...@@ -170,6 +258,49 @@ int virtio_gpu_driver_unload(struct drm_device *dev) ...@@ -170,6 +258,49 @@ int virtio_gpu_driver_unload(struct drm_device *dev)
virtio_gpu_modeset_fini(vgdev); virtio_gpu_modeset_fini(vgdev);
virtio_gpu_ttm_fini(vgdev); virtio_gpu_ttm_fini(vgdev);
virtio_gpu_free_vbufs(vgdev); virtio_gpu_free_vbufs(vgdev);
virtio_gpu_cleanup_cap_cache(vgdev);
kfree(vgdev->capsets);
kfree(vgdev); kfree(vgdev);
return 0; 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;
}
...@@ -82,24 +82,19 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev, ...@@ -82,24 +82,19 @@ int virtio_gpu_object_create(struct virtio_gpu_device *vgdev,
size = roundup(size, PAGE_SIZE); size = roundup(size, PAGE_SIZE);
ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size); ret = drm_gem_object_init(vgdev->ddev, &bo->gem_base, size);
if (ret != 0) if (ret != 0)
goto err_gem_init; return ret;
bo->dumb = false; bo->dumb = false;
virtio_gpu_init_ttm_placement(bo, pinned); virtio_gpu_init_ttm_placement(bo, pinned);
ret = ttm_bo_init(&vgdev->mman.bdev, &bo->tbo, size, type, ret = ttm_bo_init(&vgdev->mman.bdev, &bo->tbo, size, type,
&bo->placement, 0, !kernel, NULL, acc_size, &bo->placement, 0, !kernel, NULL, acc_size,
NULL, NULL, &virtio_gpu_ttm_bo_destroy); NULL, NULL, &virtio_gpu_ttm_bo_destroy);
/* ttm_bo_init failure will call the destroy */
if (ret != 0) if (ret != 0)
goto err_ttm_init; return ret;
*bo_ptr = bo; *bo_ptr = bo;
return 0; return 0;
err_ttm_init:
drm_gem_object_release(&bo->gem_base);
err_gem_init:
kfree(bo);
return ret;
} }
int virtio_gpu_object_kmap(struct virtio_gpu_object *bo, void **ptr) int virtio_gpu_object_kmap(struct virtio_gpu_object *bo, void **ptr)
......
/*
* Copyright 2014 Canonical
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Andreas Pokorny
*/
#include "virtgpu_drv.h"
/* Empty Implementations as there should not be any other driver for a virtual
* device that might share buffers with virtgpu */
int virtgpu_gem_prime_pin(struct drm_gem_object *obj)
{
WARN_ONCE(1, "not implemented");
return -ENODEV;
}
void virtgpu_gem_prime_unpin(struct drm_gem_object *obj)
{
WARN_ONCE(1, "not implemented");
}
struct sg_table *virtgpu_gem_prime_get_sg_table(struct drm_gem_object *obj)
{
WARN_ONCE(1, "not implemented");
return ERR_PTR(-ENODEV);
}
struct drm_gem_object *virtgpu_gem_prime_import_sg_table(
struct drm_device *dev, struct dma_buf_attachment *attach,
struct sg_table *table)
{
WARN_ONCE(1, "not implemented");
return ERR_PTR(-ENODEV);
}
void *virtgpu_gem_prime_vmap(struct drm_gem_object *obj)
{
WARN_ONCE(1, "not implemented");
return ERR_PTR(-ENODEV);
}
void virtgpu_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
{
WARN_ONCE(1, "not implemented");
}
int virtgpu_gem_prime_mmap(struct drm_gem_object *obj,
struct vm_area_struct *area)
{
return -ENODEV;
}
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <ttm/ttm_module.h> #include <ttm/ttm_module.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm.h> #include <drm/drm.h>
#include <drm/virtgpu_drm.h>
#include "virtgpu_drv.h" #include "virtgpu_drv.h"
#include <linux/delay.h> #include <linux/delay.h>
......
This diff is collapsed.
...@@ -17,3 +17,4 @@ header-y += tegra_drm.h ...@@ -17,3 +17,4 @@ header-y += tegra_drm.h
header-y += via_drm.h header-y += via_drm.h
header-y += vmwgfx_drm.h header-y += vmwgfx_drm.h
header-y += msm_drm.h header-y += msm_drm.h
header-y += virtgpu_drm.h
/*
* Copyright 2013 Red Hat
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef VIRTGPU_DRM_H
#define VIRTGPU_DRM_H
#include <stddef.h>
#include "drm/drm.h"
/* Please note that modifications to all structs defined here are
* subject to backwards-compatibility constraints.
*
* Do not use pointers, use uint64_t instead for 32 bit / 64 bit user/kernel
* compatibility Keep fields aligned to their size
*/
#define DRM_VIRTGPU_MAP 0x01
#define DRM_VIRTGPU_EXECBUFFER 0x02
#define DRM_VIRTGPU_GETPARAM 0x03
#define DRM_VIRTGPU_RESOURCE_CREATE 0x04
#define DRM_VIRTGPU_RESOURCE_INFO 0x05
#define DRM_VIRTGPU_TRANSFER_FROM_HOST 0x06
#define DRM_VIRTGPU_TRANSFER_TO_HOST 0x07
#define DRM_VIRTGPU_WAIT 0x08
#define DRM_VIRTGPU_GET_CAPS 0x09
struct drm_virtgpu_map {
uint64_t offset; /* use for mmap system call */
uint32_t handle;
uint32_t pad;
};
struct drm_virtgpu_execbuffer {
uint32_t flags; /* for future use */
uint32_t size;
uint64_t command; /* void* */
uint64_t bo_handles;
uint32_t num_bo_handles;
uint32_t pad;
};
#define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */
struct drm_virtgpu_getparam {
uint64_t param;
uint64_t value;
};
/* NO_BO flags? NO resource flag? */
/* resource flag for y_0_top */
struct drm_virtgpu_resource_create {
uint32_t target;
uint32_t format;
uint32_t bind;
uint32_t width;
uint32_t height;
uint32_t depth;
uint32_t array_size;
uint32_t last_level;
uint32_t nr_samples;
uint32_t flags;
uint32_t bo_handle; /* if this is set - recreate a new resource attached to this bo ? */
uint32_t res_handle; /* returned by kernel */
uint32_t size; /* validate transfer in the host */
uint32_t stride; /* validate transfer in the host */
};
struct drm_virtgpu_resource_info {
uint32_t bo_handle;
uint32_t res_handle;
uint32_t size;
uint32_t stride;
};
struct drm_virtgpu_3d_box {
uint32_t x;
uint32_t y;
uint32_t z;
uint32_t w;
uint32_t h;
uint32_t d;
};
struct drm_virtgpu_3d_transfer_to_host {
uint32_t bo_handle;
struct drm_virtgpu_3d_box box;
uint32_t level;
uint32_t offset;
};
struct drm_virtgpu_3d_transfer_from_host {
uint32_t bo_handle;
struct drm_virtgpu_3d_box box;
uint32_t level;
uint32_t offset;
};
#define VIRTGPU_WAIT_NOWAIT 1 /* like it */
struct drm_virtgpu_3d_wait {
uint32_t handle; /* 0 is an invalid handle */
uint32_t flags;
};
struct drm_virtgpu_get_caps {
uint32_t cap_set_id;
uint32_t cap_set_ver;
uint64_t addr;
uint32_t size;
uint32_t pad;
};
#define DRM_IOCTL_VIRTGPU_MAP \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct drm_virtgpu_map)
#define DRM_IOCTL_VIRTGPU_EXECBUFFER \
DRM_IOW(DRM_COMMAND_BASE + DRM_VIRTGPU_EXECBUFFER,\
struct drm_virtgpu_execbuffer)
#define DRM_IOCTL_VIRTGPU_GETPARAM \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GETPARAM,\
struct drm_virtgpu_getparam)
#define DRM_IOCTL_VIRTGPU_RESOURCE_CREATE \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_CREATE, \
struct drm_virtgpu_resource_create)
#define DRM_IOCTL_VIRTGPU_RESOURCE_INFO \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_INFO, \
struct drm_virtgpu_resource_info)
#define DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_TRANSFER_FROM_HOST, \
struct drm_virtgpu_3d_transfer_from_host)
#define DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_TRANSFER_TO_HOST, \
struct drm_virtgpu_3d_transfer_to_host)
#define DRM_IOCTL_VIRTGPU_WAIT \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_WAIT, \
struct drm_virtgpu_3d_wait)
#define DRM_IOCTL_VIRTGPU_GET_CAPS \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GET_CAPS, \
struct drm_virtgpu_get_caps)
#endif
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
#include <linux/types.h> #include <linux/types.h>
#define VIRTIO_GPU_F_VIRGL 0
enum virtio_gpu_ctrl_type { enum virtio_gpu_ctrl_type {
VIRTIO_GPU_UNDEFINED = 0, VIRTIO_GPU_UNDEFINED = 0,
...@@ -52,6 +54,18 @@ enum virtio_gpu_ctrl_type { ...@@ -52,6 +54,18 @@ enum virtio_gpu_ctrl_type {
VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
VIRTIO_GPU_CMD_GET_CAPSET_INFO,
VIRTIO_GPU_CMD_GET_CAPSET,
/* 3d commands */
VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
VIRTIO_GPU_CMD_CTX_DESTROY,
VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
VIRTIO_GPU_CMD_SUBMIT_3D,
/* cursor commands */ /* cursor commands */
VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300, VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
...@@ -60,6 +74,8 @@ enum virtio_gpu_ctrl_type { ...@@ -60,6 +74,8 @@ enum virtio_gpu_ctrl_type {
/* success responses */ /* success responses */
VIRTIO_GPU_RESP_OK_NODATA = 0x1100, VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
VIRTIO_GPU_RESP_OK_DISPLAY_INFO, VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
VIRTIO_GPU_RESP_OK_CAPSET_INFO,
VIRTIO_GPU_RESP_OK_CAPSET,
/* error responses */ /* error responses */
VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200, VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
...@@ -180,13 +196,107 @@ struct virtio_gpu_resp_display_info { ...@@ -180,13 +196,107 @@ struct virtio_gpu_resp_display_info {
} pmodes[VIRTIO_GPU_MAX_SCANOUTS]; } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
}; };
/* data passed in the control vq, 3d related */
struct virtio_gpu_box {
__le32 x, y, z;
__le32 w, h, d;
};
/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */
struct virtio_gpu_transfer_host_3d {
struct virtio_gpu_ctrl_hdr hdr;
struct virtio_gpu_box box;
__le64 offset;
__le32 resource_id;
__le32 level;
__le32 stride;
__le32 layer_stride;
};
/* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */
#define VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP (1 << 0)
struct virtio_gpu_resource_create_3d {
struct virtio_gpu_ctrl_hdr hdr;
__le32 resource_id;
__le32 target;
__le32 format;
__le32 bind;
__le32 width;
__le32 height;
__le32 depth;
__le32 array_size;
__le32 last_level;
__le32 nr_samples;
__le32 flags;
__le32 padding;
};
/* VIRTIO_GPU_CMD_CTX_CREATE */
struct virtio_gpu_ctx_create {
struct virtio_gpu_ctrl_hdr hdr;
__le32 nlen;
__le32 padding;
char debug_name[64];
};
/* VIRTIO_GPU_CMD_CTX_DESTROY */
struct virtio_gpu_ctx_destroy {
struct virtio_gpu_ctrl_hdr hdr;
};
/* VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE */
struct virtio_gpu_ctx_resource {
struct virtio_gpu_ctrl_hdr hdr;
__le32 resource_id;
__le32 padding;
};
/* VIRTIO_GPU_CMD_SUBMIT_3D */
struct virtio_gpu_cmd_submit {
struct virtio_gpu_ctrl_hdr hdr;
__le32 size;
__le32 padding;
};
#define VIRTIO_GPU_CAPSET_VIRGL 1
/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
struct virtio_gpu_get_capset_info {
struct virtio_gpu_ctrl_hdr hdr;
__le32 capset_index;
__le32 padding;
};
/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */
struct virtio_gpu_resp_capset_info {
struct virtio_gpu_ctrl_hdr hdr;
__le32 capset_id;
__le32 capset_max_version;
__le32 capset_max_size;
__le32 padding;
};
/* VIRTIO_GPU_CMD_GET_CAPSET */
struct virtio_gpu_get_capset {
struct virtio_gpu_ctrl_hdr hdr;
__le32 capset_id;
__le32 capset_version;
};
/* VIRTIO_GPU_RESP_OK_CAPSET */
struct virtio_gpu_resp_capset {
struct virtio_gpu_ctrl_hdr hdr;
uint8_t capset_data[];
};
#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0) #define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
struct virtio_gpu_config { struct virtio_gpu_config {
__u32 events_read; __u32 events_read;
__u32 events_clear; __u32 events_clear;
__u32 num_scanouts; __u32 num_scanouts;
__u32 reserved; __u32 num_capsets;
}; };
/* simple formats for fbcon/X use */ /* simple formats for fbcon/X use */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment