summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2013-08-26 15:50:33 +1000
committerDave Airlie <airlied@redhat.com>2013-09-03 15:11:33 +1000
commit560146ce6d672030c9a075ba2f7911f898bfc892 (patch)
tree14f60771cfb918f19702d26db27550c46bb19634
parent9e33d19b2aa864857266c3159a5f59c0844cc995 (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.c109
-rw-r--r--include/uapi/drm/virgl_drm.h5
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 */