diff options
author | Dave Airlie <airlied@redhat.com> | 2013-08-26 15:50:33 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-09-03 15:11:33 +1000 |
commit | 560146ce6d672030c9a075ba2f7911f898bfc892 (patch) | |
tree | 14f60771cfb918f19702d26db27550c46bb19634 | |
parent | 9e33d19b2aa864857266c3159a5f59c0844cc995 (diff) |
virgl: pass a list of bo handles to the kernel
this allows us to fence these buffer objects as being in use
for the command stream
-rw-r--r-- | drivers/gpu/drm/virgl/virgl_3d.c | 109 | ||||
-rw-r--r-- | include/uapi/drm/virgl_drm.h | 5 |
2 files changed, 92 insertions, 22 deletions
diff --git a/drivers/gpu/drm/virgl/virgl_3d.c b/drivers/gpu/drm/virgl/virgl_3d.c index 2cdeef374749..b2e0fd8edba7 100644 --- a/drivers/gpu/drm/virgl/virgl_3d.c +++ b/drivers/gpu/drm/virgl/virgl_3d.c @@ -4,7 +4,7 @@ #include <linux/virtio_pci.h> #include "virgl_drv.h" #include "virgl_object.h" - +#include "ttm/ttm_execbuf_util.h" /* virtio config->get_features() implementation */ static u32 vp_get_features(struct virtio_device *vdev) { @@ -536,6 +536,43 @@ int virgl_virtio_init(struct virgl_device *qdev) fail: return ret; } + +static int virgl_bo_list_validate(struct list_head *head) +{ + struct ttm_validate_buffer *buf; + struct ttm_buffer_object *bo; + struct virgl_bo *qobj; + int ret; + + ret = ttm_eu_reserve_buffers(head); + if (ret != 0) + return ret; + + list_for_each_entry(buf, head, head) { + bo = buf->bo; + qobj = container_of(bo, struct virgl_bo, tbo); + if (qobj->pin_count) + continue; + virgl_ttm_placement_from_domain(qobj, qobj->type); + ret = ttm_bo_validate(bo, &qobj->placement, false, false); + if (ret) + return ret; + } + return 0; +} + +static void virgl_unref_list(struct list_head *head) +{ + struct ttm_validate_buffer *buf; + struct ttm_buffer_object *bo; + struct virgl_bo *qobj; + list_for_each_entry(buf, head, head) { + bo = buf->bo; + qobj = container_of(bo, struct virgl_bo, tbo); + + drm_gem_object_unreference_unlocked(&qobj->gem_base); + } +} int virgl_execbuffer(struct drm_device *dev, struct drm_virgl_execbuffer *execbuffer, @@ -549,9 +586,48 @@ int virgl_execbuffer(struct drm_device *dev, void *optr; void *osyncobj; int ret; - + uint32_t *bo_handles = NULL; + struct list_head validate_list; + struct ttm_validate_buffer *buflist = NULL; + struct ttm_validate_buffer cmdbuffer; + int i; //printk("user cmd size %d\n", user_cmd.command_size); + memset(&cmdbuffer, 0, sizeof(struct ttm_validate_buffer)); + INIT_LIST_HEAD(&validate_list); + if (execbuffer->num_bo_handles) { + + bo_handles = drm_malloc_ab(execbuffer->num_bo_handles, sizeof(uint32_t)); + buflist = drm_calloc_large(execbuffer->num_bo_handles, sizeof(struct ttm_validate_buffer)); + if (!bo_handles || !buflist) { + drm_free_large(bo_handles); + drm_free_large(buflist); + return -ENOMEM; + } + + if (copy_from_user(bo_handles, (void __user *)(uintptr_t)execbuffer->bo_handles, execbuffer->num_bo_handles * sizeof(uint32_t))) { + ret = -EFAULT; + drm_free_large(bo_handles); + return ret; + } + + for (i = 0; i < execbuffer->num_bo_handles; i++) { + gobj = drm_gem_object_lookup(dev, + drm_file, bo_handles[i]); + if (!gobj) { + drm_free_large(bo_handles); + drm_free_large(buflist); + return -ENOENT; + } + + qobj = gem_to_virgl_bo(gobj); + buflist[i].bo = &qobj->tbo; + + list_add(&buflist[i].head, &validate_list); + } + drm_free_large(bo_handles); + } + ret = virgl_gem_object_create(qdev, execbuffer->size, 0, 0, false, true, &gobj); @@ -561,15 +637,12 @@ int virgl_execbuffer(struct drm_device *dev, qobj = gem_to_virgl_bo(gobj); - ret = virgl_bo_reserve(qobj, false); - if (ret) - goto out_free; + cmdbuffer.bo = &qobj->tbo; + list_add(&cmdbuffer.head, &validate_list); - virgl_ttm_placement_from_domain(qobj, qobj->type); - ret = ttm_bo_validate(&qobj->tbo, &qobj->placement, - true, false); + ret = virgl_bo_list_validate(&validate_list); if (ret) - goto out_unresv; + goto out_free; ret = virgl_bo_kmap(qobj, &optr); if (ret) @@ -600,25 +673,19 @@ int virgl_execbuffer(struct drm_device *dev, virgl_queue_cmd_buf(qdev, vbuf); } - spin_lock(&qobj->tbo.glob->lru_lock); - spin_lock(&qobj->tbo.bdev->fence_lock); - osyncobj = qobj->tbo.sync_obj; - qobj->tbo.sync_obj = qdev->mman.bdev.driver->sync_obj_ref(fence); + ttm_eu_fence_buffer_objects(&validate_list, fence); - spin_unlock(&qobj->tbo.bdev->fence_lock); - spin_unlock(&qobj->tbo.glob->lru_lock); - virgl_bo_unreserve(qobj); /* fence the command bo */ - drm_gem_object_unreference_unlocked(gobj); - if (osyncobj) - qdev->mman.bdev.driver->sync_obj_ref(osyncobj); + virgl_unref_list(&validate_list); + drm_free_large(buflist); return 0; out_kunmap: virgl_bo_kunmap(qobj); out_unresv: - virgl_bo_unreserve(qobj); + ttm_eu_backoff_reservation(&validate_list); out_free: - drm_gem_object_unreference_unlocked(gobj); + virgl_unref_list(&validate_list); + drm_free_large(buflist); return ret; } diff --git a/include/uapi/drm/virgl_drm.h b/include/uapi/drm/virgl_drm.h index 661f8b1c3591..723a4a86a356 100644 --- a/include/uapi/drm/virgl_drm.h +++ b/include/uapi/drm/virgl_drm.h @@ -59,7 +59,10 @@ struct drm_virgl_map { struct drm_virgl_execbuffer { uint32_t flags; /* for future use */ uint32_t size; - uint64_t __user command; /* void* */ + uint64_t command; /* void* */ + uint64_t bo_handles; + uint32_t num_bo_handles; + uint32_t pad; }; /* no params yet */ |