diff options
Diffstat (limited to 'drivers/gpu/msm/kgsl_drawobj.c')
| -rw-r--r-- | drivers/gpu/msm/kgsl_drawobj.c | 187 |
1 files changed, 138 insertions, 49 deletions
diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c index 7840daa6a3e2..f8f0e7ccb0d3 100644 --- a/drivers/gpu/msm/kgsl_drawobj.c +++ b/drivers/gpu/msm/kgsl_drawobj.c @@ -37,10 +37,12 @@ #include "kgsl_compat.h" /* - * Define an kmem cache for the memobj structures since we allocate and free - * them so frequently + * Define an kmem cache for the memobj & sparseobj structures since we + * allocate and free them so frequently */ static struct kmem_cache *memobjs_cache; +static struct kmem_cache *sparseobjs_cache; + static void drawobj_destroy_object(struct kref *kref) { @@ -60,6 +62,9 @@ static void drawobj_destroy_object(struct kref *kref) case MARKEROBJ_TYPE: kfree(CMDOBJ(drawobj)); break; + case SPARSEOBJ_TYPE: + kfree(SPARSEOBJ(drawobj)); + break; } } @@ -211,6 +216,18 @@ static inline void memobj_list_free(struct list_head *list) } } +static void drawobj_destroy_sparse(struct kgsl_drawobj *drawobj) +{ + struct kgsl_sparseobj_node *mem, *tmpmem; + struct list_head *list = &SPARSEOBJ(drawobj)->sparselist; + + /* Free the sparse mem here */ + list_for_each_entry_safe(mem, tmpmem, list, node) { + list_del_init(&mem->node); + kmem_cache_free(sparseobjs_cache, mem); + } +} + static void drawobj_destroy_sync(struct kgsl_drawobj *drawobj) { struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj); @@ -297,6 +314,8 @@ void kgsl_drawobj_destroy(struct kgsl_drawobj *drawobj) drawobj_destroy_sync(drawobj); else if (drawobj->type & (CMDOBJ_TYPE | MARKEROBJ_TYPE)) drawobj_destroy_cmd(drawobj); + else if (drawobj->type == SPARSEOBJ_TYPE) + drawobj_destroy_sparse(drawobj); else return; @@ -610,16 +629,26 @@ int kgsl_drawobj_cmd_add_ibdesc(struct kgsl_device *device, return 0; } -static inline int drawobj_init(struct kgsl_device *device, - struct kgsl_context *context, struct kgsl_drawobj *drawobj, +static void *_drawobj_create(struct kgsl_device *device, + struct kgsl_context *context, unsigned int size, unsigned int type) { + void *obj = kzalloc(size, GFP_KERNEL); + struct kgsl_drawobj *drawobj; + + if (obj == NULL) + return ERR_PTR(-ENOMEM); + /* * Increase the reference count on the context so it doesn't disappear * during the lifetime of this object */ - if (!_kgsl_context_get(context)) - return -ENOENT; + if (!_kgsl_context_get(context)) { + kfree(obj); + return ERR_PTR(-ENOENT); + } + + drawobj = obj; kref_init(&drawobj->refcount); @@ -627,7 +656,28 @@ static inline int drawobj_init(struct kgsl_device *device, drawobj->context = context; drawobj->type = type; - return 0; + return obj; +} + +/** + * kgsl_drawobj_sparse_create() - Create a new sparse obj structure + * @device: Pointer to a KGSL device struct + * @context: Pointer to a KGSL context struct + * @flags: Flags for the sparse obj + * + * Allocate an new kgsl_drawobj_sparse structure + */ +struct kgsl_drawobj_sparse *kgsl_drawobj_sparse_create( + struct kgsl_device *device, + struct kgsl_context *context, unsigned int flags) +{ + struct kgsl_drawobj_sparse *sparseobj = _drawobj_create(device, + context, sizeof(*sparseobj), SPARSEOBJ_TYPE); + + if (!IS_ERR(sparseobj)) + INIT_LIST_HEAD(&sparseobj->sparselist); + + return sparseobj; } /** @@ -641,18 +691,13 @@ static inline int drawobj_init(struct kgsl_device *device, struct kgsl_drawobj_sync *kgsl_drawobj_sync_create(struct kgsl_device *device, struct kgsl_context *context) { - struct kgsl_drawobj_sync *syncobj = kzalloc(sizeof(*syncobj), - GFP_KERNEL); - if (syncobj == NULL) - return ERR_PTR(-ENOMEM); - - if (drawobj_init(device, context, DRAWOBJ(syncobj), SYNCOBJ_TYPE)) { - kfree(syncobj); - return ERR_PTR(-ENOENT); - } + struct kgsl_drawobj_sync *syncobj = _drawobj_create(device, + context, sizeof(*syncobj), SYNCOBJ_TYPE); /* Add a timer to help debug sync deadlocks */ - setup_timer(&syncobj->timer, syncobj_timer, (unsigned long) syncobj); + if (!IS_ERR(syncobj)) + setup_timer(&syncobj->timer, syncobj_timer, + (unsigned long) syncobj); return syncobj; } @@ -671,27 +716,13 @@ struct kgsl_drawobj_cmd *kgsl_drawobj_cmd_create(struct kgsl_device *device, struct kgsl_context *context, unsigned int flags, unsigned int type) { - struct kgsl_drawobj_cmd *cmdobj = kzalloc(sizeof(*cmdobj), GFP_KERNEL); - struct kgsl_drawobj *drawobj; - - if (cmdobj == NULL) - return ERR_PTR(-ENOMEM); - - type &= CMDOBJ_TYPE | MARKEROBJ_TYPE; - if (type == 0) { - kfree(cmdobj); - return ERR_PTR(-EINVAL); - } - - drawobj = DRAWOBJ(cmdobj); - - if (drawobj_init(device, context, drawobj, type)) { - kfree(cmdobj); - return ERR_PTR(-ENOENT); - } + struct kgsl_drawobj_cmd *cmdobj = _drawobj_create(device, + context, sizeof(*cmdobj), + (type & (CMDOBJ_TYPE | MARKEROBJ_TYPE))); - /* sanitize our flags for drawobj's */ - drawobj->flags = flags & (KGSL_DRAWOBJ_CTX_SWITCH + if (!IS_ERR(cmdobj)) { + /* sanitize our flags for drawobj's */ + cmdobj->base.flags = flags & (KGSL_DRAWOBJ_CTX_SWITCH | KGSL_DRAWOBJ_MARKER | KGSL_DRAWOBJ_END_OF_FRAME | KGSL_DRAWOBJ_PWR_CONSTRAINT @@ -699,8 +730,9 @@ struct kgsl_drawobj_cmd *kgsl_drawobj_cmd_create(struct kgsl_device *device, | KGSL_DRAWOBJ_PROFILING | KGSL_DRAWOBJ_PROFILING_KTIME); - INIT_LIST_HEAD(&cmdobj->cmdlist); - INIT_LIST_HEAD(&cmdobj->memlist); + INIT_LIST_HEAD(&cmdobj->cmdlist); + INIT_LIST_HEAD(&cmdobj->memlist); + } return cmdobj; } @@ -864,7 +896,7 @@ int kgsl_drawobj_sync_add_syncpoints(struct kgsl_device *device, return 0; } -static int drawobj_add_object(struct list_head *head, +static int kgsl_drawobj_add_memobject(struct list_head *head, struct kgsl_command_object *obj) { struct kgsl_memobj_node *mem; @@ -884,6 +916,62 @@ static int drawobj_add_object(struct list_head *head, return 0; } +static int kgsl_drawobj_add_sparseobject(struct list_head *head, + struct kgsl_sparse_binding_object *obj, unsigned int virt_id) +{ + struct kgsl_sparseobj_node *mem; + + mem = kmem_cache_alloc(sparseobjs_cache, GFP_KERNEL); + if (mem == NULL) + return -ENOMEM; + + mem->virt_id = virt_id; + mem->obj.id = obj->id; + mem->obj.virtoffset = obj->virtoffset; + mem->obj.physoffset = obj->physoffset; + mem->obj.size = obj->size; + mem->obj.flags = obj->flags; + + list_add_tail(&mem->node, head); + return 0; +} + +int kgsl_drawobj_sparse_add_sparselist(struct kgsl_device *device, + struct kgsl_drawobj_sparse *sparseobj, unsigned int id, + void __user *ptr, unsigned int size, unsigned int count) +{ + struct kgsl_sparse_binding_object obj; + int i, ret = 0; + + ret = _verify_input_list(count, ptr, size); + if (ret <= 0) + return ret; + + for (i = 0; i < count; i++) { + memset(&obj, 0, sizeof(obj)); + + ret = _copy_from_user(&obj, ptr, sizeof(obj), size); + if (ret) + return ret; + + if (!(obj.flags & (KGSL_SPARSE_BIND | KGSL_SPARSE_UNBIND))) + return -EINVAL; + + ret = kgsl_drawobj_add_sparseobject(&sparseobj->sparselist, + &obj, id); + if (ret) + return ret; + + ptr += sizeof(obj); + } + + sparseobj->size = size; + sparseobj->count = count; + + return 0; +} + + #define CMDLIST_FLAGS \ (KGSL_CMDLIST_IB | \ KGSL_CMDLIST_CTXTSWITCH_PREAMBLE | \ @@ -922,7 +1010,7 @@ int kgsl_drawobj_cmd_add_cmdlist(struct kgsl_device *device, return -EINVAL; } - ret = drawobj_add_object(&cmdobj->cmdlist, &obj); + ret = kgsl_drawobj_add_memobject(&cmdobj->cmdlist, &obj); if (ret) return ret; @@ -967,7 +1055,8 @@ int kgsl_drawobj_cmd_add_memlist(struct kgsl_device *device, add_profiling_buffer(device, cmdobj, obj.gpuaddr, obj.size, obj.id, obj.offset); else { - ret = drawobj_add_object(&cmdobj->memlist, &obj); + ret = kgsl_drawobj_add_memobject(&cmdobj->memlist, + &obj); if (ret) return ret; } @@ -1018,19 +1107,19 @@ int kgsl_drawobj_sync_add_synclist(struct kgsl_device *device, return 0; } -void kgsl_drawobj_exit(void) +void kgsl_drawobjs_cache_exit(void) { - if (memobjs_cache != NULL) - kmem_cache_destroy(memobjs_cache); + kmem_cache_destroy(memobjs_cache); + kmem_cache_destroy(sparseobjs_cache); } -int kgsl_drawobj_init(void) +int kgsl_drawobjs_cache_init(void) { memobjs_cache = KMEM_CACHE(kgsl_memobj_node, 0); - if (memobjs_cache == NULL) { - KGSL_CORE_ERR("failed to create memobjs_cache"); + sparseobjs_cache = KMEM_CACHE(kgsl_sparseobj_node, 0); + + if (!memobjs_cache || !sparseobjs_cache) return -ENOMEM; - } return 0; } |
