summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2013-09-02 17:00:24 +1000
committerDave Airlie <airlied@redhat.com>2013-09-03 15:11:36 +1000
commit62d0946cfc646a472c90ff601256e740f59082b8 (patch)
tree0ca25e2ffd23190e4791fdbf00a0ef72425920cb
parent0f513319b00459e9e66d13a4bad2659def380bce (diff)
try alternate sg creation scheme
this reduces CPU usage and make bring us back inside virtio limits
-rw-r--r--drivers/gpu/drm/virgl/virgl_3d.c12
-rw-r--r--drivers/gpu/drm/virgl/virgl_drv.c5
-rw-r--r--drivers/gpu/drm/virgl/virgl_drv.h5
-rw-r--r--drivers/gpu/drm/virgl/virgl_hw.h8
-rw-r--r--drivers/gpu/drm/virgl/virgl_ioctl.c84
5 files changed, 104 insertions, 10 deletions
diff --git a/drivers/gpu/drm/virgl/virgl_3d.c b/drivers/gpu/drm/virgl/virgl_3d.c
index 0533639fa9e8..43b973b59d1f 100644
--- a/drivers/gpu/drm/virgl/virgl_3d.c
+++ b/drivers/gpu/drm/virgl/virgl_3d.c
@@ -260,9 +260,13 @@ struct virgl_vbuffer *allocate_vbuf(struct virgl_device *qdev,
int size, bool inout, u32 *base_offset, u32 max_bo_len)
{
struct virgl_vbuffer *vbuf;
- int sgpages = bo ? bo->tbo.num_pages : 0;
+ int sgpages = 0;
int ret;
+ if (bo)
+ if (!bo->is_res_bound)
+ sgpages = bo->tbo.num_pages;
+
sgpages++;
vbuf = kmalloc(sizeof(*vbuf) + sizeof(struct scatterlist) * sgpages + size, GFP_KERNEL);
@@ -274,7 +278,7 @@ struct virgl_vbuffer *allocate_vbuf(struct virgl_device *qdev,
vbuf->sgpages = sgpages;
vbuf->size = size;
- if (bo) {
+ if (bo && !bo->is_res_bound) {
struct scatterlist *sg;
unsigned int i;
uint32_t offset = 0;
@@ -537,7 +541,7 @@ fail:
return ret;
}
-static int virgl_bo_list_validate(struct list_head *head)
+int virgl_bo_list_validate(struct list_head *head)
{
struct ttm_validate_buffer *buf;
struct ttm_buffer_object *bo;
@@ -561,7 +565,7 @@ static int virgl_bo_list_validate(struct list_head *head)
return 0;
}
-static void virgl_unref_list(struct list_head *head)
+void virgl_unref_list(struct list_head *head)
{
struct ttm_validate_buffer *buf;
struct ttm_buffer_object *bo;
diff --git a/drivers/gpu/drm/virgl/virgl_drv.c b/drivers/gpu/drm/virgl/virgl_drv.c
index b329f036c19f..fa7945a0e41f 100644
--- a/drivers/gpu/drm/virgl/virgl_drv.c
+++ b/drivers/gpu/drm/virgl/virgl_drv.c
@@ -49,6 +49,11 @@ int virgl_modeset = -1;
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
module_param_named(modeset, virgl_modeset, int, 0400);
+int virgl_create_sg = 0;
+
+MODULE_PARM_DESC(sgc, "Use new SG creation feature");
+module_param_named(sgc, virgl_create_sg, int, 0400);
+
static struct drm_driver virgl_driver;
static struct pci_driver virgl_pci_driver;
diff --git a/drivers/gpu/drm/virgl/virgl_drv.h b/drivers/gpu/drm/virgl/virgl_drv.h
index a49a24ccf10b..6e7e5c55956f 100644
--- a/drivers/gpu/drm/virgl/virgl_drv.h
+++ b/drivers/gpu/drm/virgl/virgl_drv.h
@@ -77,6 +77,7 @@ struct virgl_bo {
uint32_t res_handle; /* used for backing dumb objects */
bool dumb;
uint32_t stride;
+ bool is_res_bound;
};
#define gem_to_virgl_bo(gobj) container_of((gobj), struct virgl_bo, gem_base)
@@ -231,6 +232,7 @@ struct virgl_fpriv {
extern struct drm_ioctl_desc virgl_ioctls[];
extern int virgl_max_ioctl;
+extern int virgl_create_sg;
int virgl_driver_load(struct drm_device *dev, unsigned long flags);
int virgl_driver_unload(struct drm_device *dev);
@@ -399,4 +401,7 @@ int virgl_enable_vblank(struct drm_device *dev, int crtc);
void virgl_disable_vblank(struct drm_device *dev, int crtc);
int virgl_get_caps(struct virgl_device *vdev);
+
+int virgl_bo_list_validate(struct list_head *head);
+void virgl_unref_list(struct list_head *head);
#endif
diff --git a/drivers/gpu/drm/virgl/virgl_hw.h b/drivers/gpu/drm/virgl/virgl_hw.h
index 63a9c5cd2171..a6088323a1a4 100644
--- a/drivers/gpu/drm/virgl/virgl_hw.h
+++ b/drivers/gpu/drm/virgl/virgl_hw.h
@@ -74,7 +74,7 @@ struct virgl_resource_create {
uint32_t array_size;
uint32_t last_level;
uint32_t nr_samples;
- uint32_t pad;
+ uint32_t nr_sg_entries;
};
struct virgl_resource_unref {
@@ -120,6 +120,12 @@ struct virgl_cmd_get_cap {
#define VIRGL_COMMAND_EMIT_FENCE (1 << 0)
+struct virgl_iov_entry {
+ VIRGLPHYSICAL addr;
+ uint32_t length;
+ uint32_t pad;
+};
+
struct virgl_command {
uint32_t type;
uint32_t flags;
diff --git a/drivers/gpu/drm/virgl/virgl_ioctl.c b/drivers/gpu/drm/virgl/virgl_ioctl.c
index c72ff98e1c9c..8932883bbca6 100644
--- a/drivers/gpu/drm/virgl/virgl_ioctl.c
+++ b/drivers/gpu/drm/virgl/virgl_ioctl.c
@@ -25,6 +25,7 @@
#include "virgl_drv.h"
#include "virgl_object.h"
+#include "ttm/ttm_execbuf_util.h"
static void convert_to_hw_box(struct virgl_box *dst,
const struct drm_virgl_3d_box *src)
@@ -101,8 +102,19 @@ static int virgl_resource_create_ioctl(struct drm_device *dev, void *data,
int ret;
uint32_t res_id;
struct virgl_bo *qobj;
- uint32_t handle;
- uint32_t size;
+ uint32_t handle = 0;
+ uint32_t size, pg_size;
+ struct virgl_bo *pg_bo = NULL;
+ void *optr;
+ int si;
+ struct scatterlist *sg;
+ struct list_head validate_list;
+ struct ttm_validate_buffer mainbuf, page_info_buf;
+ struct virgl_fence *fence;
+
+ INIT_LIST_HEAD(&validate_list);
+ memset(&mainbuf, 0, sizeof(struct ttm_validate_buffer));
+ memset(&page_info_buf, 0, sizeof(struct ttm_validate_buffer));
ret = virgl_resource_id_get(qdev, &res_id);
if (ret)
@@ -110,16 +122,58 @@ static int virgl_resource_create_ioctl(struct drm_device *dev, void *data,
size = rc->size;
+ /* allocate a single page size object */
+ if (size == 0)
+ size = PAGE_SIZE;
+
ret = virgl_gem_object_create_with_handle(qdev, file_priv,
0,
size,
&qobj, &handle);
+ if (ret)
+ goto fail_id;
+
+ /* use a gem reference since unref list undoes them */
+ drm_gem_object_reference(&qobj->gem_base);
+ mainbuf.bo = &qobj->tbo;
+ list_add(&mainbuf.head, &validate_list);
+
+ if (virgl_create_sg == 1) {
+ ret = virgl_bo_get_sg_table(qdev, qobj);
+ if (ret)
+ goto fail_obj;
+
+ pg_size = sizeof(struct virgl_iov_entry) * qobj->sgt->nents;
+
+ ret = virgl_bo_create(qdev, pg_size, true, 0, &pg_bo);
+ if (ret)
+ goto fail_unref;
+
+ drm_gem_object_reference(&pg_bo->gem_base);
+ page_info_buf.bo = &pg_bo->tbo;
+ list_add(&page_info_buf.head, &validate_list);
+ }
+
+ ret = virgl_bo_list_validate(&validate_list);
if (ret) {
- virgl_resource_id_put(qdev, res_id);
- return ret;
+ printk("failed to validate\n");
+ goto fail_unref;
}
- cmd_p = virgl_alloc_cmd(qdev, NULL, false, NULL, 0, &vbuf);
+ if (virgl_create_sg == 1) {
+ ret = virgl_bo_kmap(pg_bo, &optr);
+ for_each_sg(qobj->sgt->sgl, sg, qobj->sgt->nents, si) {
+ struct virgl_iov_entry *iov = ((struct virgl_iov_entry *)optr) + si;
+ iov->addr = sg_phys(sg);
+ iov->length = sg->length;
+ iov->pad = 0;
+ }
+ virgl_bo_kunmap(pg_bo);
+
+ qobj->is_res_bound = true;
+ }
+
+ cmd_p = virgl_alloc_cmd(qdev, pg_bo, false, NULL, 0, &vbuf);
memset(cmd_p, 0, sizeof(*cmd_p));
cmd_p->type = VIRGL_CMD_CREATE_RESOURCE;
cmd_p->u.res_create.handle = res_id;
@@ -132,15 +186,35 @@ static int virgl_resource_create_ioctl(struct drm_device *dev, void *data,
cmd_p->u.res_create.array_size = rc->array_size;
cmd_p->u.res_create.last_level = rc->last_level;
cmd_p->u.res_create.nr_samples = rc->nr_samples;
+ cmd_p->u.res_create.nr_sg_entries = qobj->sgt ? qobj->sgt->nents : 0;
+
+ ret = virgl_fence_emit(qdev, cmd_p, &fence);
virgl_queue_cmd_buf(qdev, vbuf);
+ ttm_eu_fence_buffer_objects(&validate_list, fence);
+
qobj->res_handle = res_id;
qobj->stride = rc->stride;
rc->res_handle = res_id; /* similiar to a VM address */
rc->bo_handle = handle;
+ virgl_unref_list(&validate_list);
+ if (virgl_create_sg == 1)
+ virgl_bo_unref(&pg_bo);
+
return 0;
+fail_unref:
+ virgl_unref_list(&validate_list);
+fail_pg_obj:
+ if (virgl_create_sg == 1)
+ if (pg_bo)
+ virgl_bo_unref(&pg_bo);
+fail_obj:
+ drm_gem_object_handle_unreference_unlocked(&qobj->gem_base);
+fail_id:
+ virgl_resource_id_put(qdev, res_id);
+ return ret;
}
static int virgl_resource_info_ioctl(struct drm_device *dev, void *data,