diff options
author | Dave Airlie <airlied@redhat.com> | 2013-09-02 17:00:24 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2013-09-03 15:11:36 +1000 |
commit | 62d0946cfc646a472c90ff601256e740f59082b8 (patch) | |
tree | 0ca25e2ffd23190e4791fdbf00a0ef72425920cb | |
parent | 0f513319b00459e9e66d13a4bad2659def380bce (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.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/virgl/virgl_drv.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/virgl/virgl_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/virgl/virgl_hw.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/virgl/virgl_ioctl.c | 84 |
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, |