msm: kgsl: Add Bind objects to dispatcher draw queue
kgsl_ioctl_gpu_sparse_command() is added to for user to specify list of binds/unbinds for a memory entry and syncpoints they depend on. If user specifies both create a sync object for syncpoints and bind object for binds/unbinds and add them to dispatcher draw queue. Sync object should be inserted before the bind object in the draw queue. Once the bind object reaches the head of draw queue the corresponding binds/unbinds are performed. kgsl_ioctl_gpu_sparse_command() only accepts commands from context created with flag KGSL_CONTEXT_SPARSE, commands from all other context types will return an error. Change-Id: Ib0a2361f854ae01d0d8090cdd48cfa96308daf93 Signed-off-by: Tarun Karra <tkarra@codeaurora.org>
This commit is contained in:
parent
368fecd7df
commit
c71cda2d10
10 changed files with 497 additions and 57 deletions
|
@ -359,6 +359,13 @@ static inline void _pop_drawobj(struct adreno_context *drawctxt)
|
|||
drawctxt->queued--;
|
||||
}
|
||||
|
||||
static void _retire_sparseobj(struct kgsl_drawobj_sparse *sparseobj,
|
||||
struct adreno_context *drawctxt)
|
||||
{
|
||||
kgsl_sparse_bind(drawctxt->base.proc_priv, sparseobj);
|
||||
_retire_timestamp(DRAWOBJ(sparseobj));
|
||||
}
|
||||
|
||||
static int _retire_markerobj(struct kgsl_drawobj_cmd *cmdobj,
|
||||
struct adreno_context *drawctxt)
|
||||
{
|
||||
|
@ -436,6 +443,8 @@ static struct kgsl_drawobj *_process_drawqueue_get_next_drawobj(
|
|||
return drawobj;
|
||||
} else if (drawobj->type == SYNCOBJ_TYPE)
|
||||
ret = _retire_syncobj(SYNCOBJ(drawobj), drawctxt);
|
||||
else
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (ret == -EAGAIN)
|
||||
return ERR_PTR(-EAGAIN);
|
||||
|
@ -670,6 +679,76 @@ static int sendcmd(struct adreno_device *adreno_dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Retires all sync objs from the sparse context
|
||||
* queue and returns one of the below
|
||||
* a) next sparseobj
|
||||
* b) -EAGAIN for syncobj with syncpoints pending
|
||||
* c) -EINVAL for unexpected drawobj
|
||||
* d) NULL for no sparseobj
|
||||
*/
|
||||
static struct kgsl_drawobj_sparse *_get_next_sparseobj(
|
||||
struct adreno_context *drawctxt)
|
||||
{
|
||||
struct kgsl_drawobj *drawobj;
|
||||
unsigned int i = drawctxt->drawqueue_head;
|
||||
int ret = 0;
|
||||
|
||||
if (drawctxt->drawqueue_head == drawctxt->drawqueue_tail)
|
||||
return NULL;
|
||||
|
||||
for (i = drawctxt->drawqueue_head; i != drawctxt->drawqueue_tail;
|
||||
i = DRAWQUEUE_NEXT(i, ADRENO_CONTEXT_DRAWQUEUE_SIZE)) {
|
||||
|
||||
drawobj = drawctxt->drawqueue[i];
|
||||
|
||||
if (drawobj == NULL)
|
||||
return NULL;
|
||||
|
||||
if (drawobj->type == SYNCOBJ_TYPE)
|
||||
ret = _retire_syncobj(SYNCOBJ(drawobj), drawctxt);
|
||||
else if (drawobj->type == SPARSEOBJ_TYPE)
|
||||
return SPARSEOBJ(drawobj);
|
||||
else
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (ret == -EAGAIN)
|
||||
return ERR_PTR(-EAGAIN);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _process_drawqueue_sparse(
|
||||
struct adreno_context *drawctxt)
|
||||
{
|
||||
struct kgsl_drawobj_sparse *sparseobj;
|
||||
int ret = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ADRENO_CONTEXT_DRAWQUEUE_SIZE; i++) {
|
||||
|
||||
spin_lock(&drawctxt->lock);
|
||||
sparseobj = _get_next_sparseobj(drawctxt);
|
||||
if (IS_ERR_OR_NULL(sparseobj)) {
|
||||
if (IS_ERR(sparseobj))
|
||||
ret = PTR_ERR(sparseobj);
|
||||
spin_unlock(&drawctxt->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
_pop_drawobj(drawctxt);
|
||||
spin_unlock(&drawctxt->lock);
|
||||
|
||||
_retire_sparseobj(sparseobj, drawctxt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dispatcher_context_sendcmds() - Send commands from a context to the GPU
|
||||
* @adreno_dev: Pointer to the adreno device struct
|
||||
|
@ -689,6 +768,9 @@ static int dispatcher_context_sendcmds(struct adreno_device *adreno_dev,
|
|||
int inflight = _drawqueue_inflight(dispatch_q);
|
||||
unsigned int timestamp;
|
||||
|
||||
if (drawctxt->base.flags & KGSL_CONTEXT_SPARSE)
|
||||
return _process_drawqueue_sparse(drawctxt);
|
||||
|
||||
if (dispatch_q->inflight >= inflight) {
|
||||
spin_lock(&drawctxt->lock);
|
||||
_process_drawqueue_get_next_drawobj(drawctxt);
|
||||
|
@ -1124,6 +1206,31 @@ static void _queue_drawobj(struct adreno_context *drawctxt,
|
|||
trace_adreno_cmdbatch_queued(drawobj, drawctxt->queued);
|
||||
}
|
||||
|
||||
static int _queue_sparseobj(struct adreno_device *adreno_dev,
|
||||
struct adreno_context *drawctxt, struct kgsl_drawobj_sparse *sparseobj,
|
||||
uint32_t *timestamp, unsigned int user_ts)
|
||||
{
|
||||
struct kgsl_drawobj *drawobj = DRAWOBJ(sparseobj);
|
||||
int ret;
|
||||
|
||||
ret = get_timestamp(drawctxt, drawobj, timestamp, user_ts);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* See if we can fastpath this thing - if nothing is
|
||||
* queued bind/unbind without queueing the context
|
||||
*/
|
||||
if (!drawctxt->queued)
|
||||
return 1;
|
||||
|
||||
drawctxt->queued_timestamp = *timestamp;
|
||||
_queue_drawobj(drawctxt, drawobj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int _queue_markerobj(struct adreno_device *adreno_dev,
|
||||
struct adreno_context *drawctxt, struct kgsl_drawobj_cmd *markerobj,
|
||||
uint32_t *timestamp, unsigned int user_ts)
|
||||
|
@ -1141,7 +1248,6 @@ static int _queue_markerobj(struct adreno_device *adreno_dev,
|
|||
*/
|
||||
if (!drawctxt->queued && kgsl_check_timestamp(drawobj->device,
|
||||
drawobj->context, drawctxt->queued_timestamp)) {
|
||||
trace_adreno_cmdbatch_queued(drawobj, drawctxt->queued);
|
||||
_retire_timestamp(drawobj);
|
||||
return 1;
|
||||
}
|
||||
|
@ -1212,7 +1318,7 @@ static void _queue_syncobj(struct adreno_context *drawctxt,
|
|||
}
|
||||
|
||||
/**
|
||||
* adreno_dispactcher_queue_drawobj() - Queue a new draw object in the context
|
||||
* adreno_dispactcher_queue_cmds() - Queue a new draw object in the context
|
||||
* @dev_priv: Pointer to the device private struct
|
||||
* @context: Pointer to the kgsl draw context
|
||||
* @drawobj: Pointer to the array of drawobj's being submitted
|
||||
|
@ -1234,6 +1340,9 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv,
|
|||
int ret;
|
||||
unsigned int i, user_ts;
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
ret = _check_context_state(&drawctxt->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1283,6 +1392,20 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv,
|
|||
_queue_syncobj(drawctxt, SYNCOBJ(drawobj[i]),
|
||||
timestamp);
|
||||
break;
|
||||
case SPARSEOBJ_TYPE:
|
||||
ret = _queue_sparseobj(adreno_dev, drawctxt,
|
||||
SPARSEOBJ(drawobj[i]),
|
||||
timestamp, user_ts);
|
||||
if (ret == 1) {
|
||||
spin_unlock(&drawctxt->lock);
|
||||
_retire_sparseobj(SPARSEOBJ(drawobj[i]),
|
||||
drawctxt);
|
||||
return 0;
|
||||
} else if (ret) {
|
||||
spin_unlock(&drawctxt->lock);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
spin_unlock(&drawctxt->lock);
|
||||
return -EINVAL;
|
||||
|
|
|
@ -351,7 +351,8 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
|
|||
KGSL_CONTEXT_IFH_NOP |
|
||||
KGSL_CONTEXT_SECURE |
|
||||
KGSL_CONTEXT_PREEMPT_STYLE_MASK |
|
||||
KGSL_CONTEXT_NO_SNAPSHOT);
|
||||
KGSL_CONTEXT_NO_SNAPSHOT |
|
||||
KGSL_CONTEXT_SPARSE);
|
||||
|
||||
/* Check for errors before trying to initialize */
|
||||
|
||||
|
|
|
@ -1439,6 +1439,17 @@ long kgsl_ioctl_device_waittimestamp_ctxtid(
|
|||
return result;
|
||||
}
|
||||
|
||||
static inline bool _check_context_is_sparse(struct kgsl_context *context,
|
||||
uint64_t flags)
|
||||
{
|
||||
if ((context->flags & KGSL_CONTEXT_SPARSE) ||
|
||||
(flags & KGSL_DRAWOBJ_SPARSE))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data)
|
||||
{
|
||||
|
@ -1463,6 +1474,11 @@ long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
|
|||
if (context == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (_check_context_is_sparse(context, param->flags)) {
|
||||
kgsl_context_put(context);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmdobj = kgsl_drawobj_cmd_create(device, context, param->flags,
|
||||
CMDOBJ_TYPE);
|
||||
if (IS_ERR(cmdobj)) {
|
||||
|
@ -1558,6 +1574,11 @@ long kgsl_ioctl_submit_commands(struct kgsl_device_private *dev_priv,
|
|||
if (context == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (_check_context_is_sparse(context, param->flags)) {
|
||||
kgsl_context_put(context);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type & SYNCOBJ_TYPE) {
|
||||
struct kgsl_drawobj_sync *syncobj =
|
||||
kgsl_drawobj_sync_create(device, context);
|
||||
|
@ -1632,6 +1653,11 @@ long kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv,
|
|||
if (context == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (_check_context_is_sparse(context, param->flags)) {
|
||||
kgsl_context_put(context);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type & SYNCOBJ_TYPE) {
|
||||
struct kgsl_drawobj_sync *syncobj =
|
||||
kgsl_drawobj_sync_create(device, context);
|
||||
|
@ -3742,6 +3768,128 @@ long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv,
|
|||
return ret;
|
||||
}
|
||||
|
||||
long kgsl_ioctl_gpu_sparse_command(struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data)
|
||||
{
|
||||
struct kgsl_gpu_sparse_command *param = data;
|
||||
struct kgsl_device *device = dev_priv->device;
|
||||
struct kgsl_context *context;
|
||||
struct kgsl_drawobj *drawobj[2];
|
||||
struct kgsl_drawobj_sparse *sparseobj;
|
||||
long result;
|
||||
unsigned int i = 0;
|
||||
|
||||
/* Make sure sparse and syncpoint count isn't too big */
|
||||
if (param->numsparse > KGSL_MAX_SPARSE ||
|
||||
param->numsyncs > KGSL_MAX_SYNCPOINTS)
|
||||
return -EINVAL;
|
||||
|
||||
/* Make sure there is atleast one sparse or sync */
|
||||
if (param->numsparse == 0 && param->numsyncs == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Only Sparse commands are supported in this ioctl */
|
||||
if (!(param->flags & KGSL_DRAWOBJ_SPARSE) || (param->flags &
|
||||
(KGSL_DRAWOBJ_SUBMIT_IB_LIST | KGSL_DRAWOBJ_MARKER
|
||||
| KGSL_DRAWOBJ_SYNC)))
|
||||
return -EINVAL;
|
||||
|
||||
context = kgsl_context_get_owner(dev_priv, param->context_id);
|
||||
if (context == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/* Restrict bind commands to bind context */
|
||||
if (!(context->flags & KGSL_CONTEXT_SPARSE)) {
|
||||
kgsl_context_put(context);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (param->numsyncs) {
|
||||
struct kgsl_drawobj_sync *syncobj = kgsl_drawobj_sync_create(
|
||||
device, context);
|
||||
if (IS_ERR(syncobj)) {
|
||||
result = PTR_ERR(syncobj);
|
||||
goto done;
|
||||
}
|
||||
|
||||
drawobj[i++] = DRAWOBJ(syncobj);
|
||||
result = kgsl_drawobj_sync_add_synclist(device, syncobj,
|
||||
to_user_ptr(param->synclist),
|
||||
param->syncsize, param->numsyncs);
|
||||
if (result)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (param->numsparse) {
|
||||
sparseobj = kgsl_drawobj_sparse_create(device, context,
|
||||
param->flags);
|
||||
if (IS_ERR(sparseobj)) {
|
||||
result = PTR_ERR(sparseobj);
|
||||
goto done;
|
||||
}
|
||||
|
||||
sparseobj->id = param->id;
|
||||
drawobj[i++] = DRAWOBJ(sparseobj);
|
||||
result = kgsl_drawobj_sparse_add_sparselist(device, sparseobj,
|
||||
param->id, to_user_ptr(param->sparselist),
|
||||
param->sparsesize, param->numsparse);
|
||||
if (result)
|
||||
goto done;
|
||||
}
|
||||
|
||||
result = dev_priv->device->ftbl->queue_cmds(dev_priv, context,
|
||||
drawobj, i, ¶m->timestamp);
|
||||
|
||||
done:
|
||||
/*
|
||||
* -EPROTO is a "success" error - it just tells the user that the
|
||||
* context had previously faulted
|
||||
*/
|
||||
if (result && result != -EPROTO)
|
||||
while (i--)
|
||||
kgsl_drawobj_destroy(drawobj[i]);
|
||||
|
||||
kgsl_context_put(context);
|
||||
return result;
|
||||
}
|
||||
|
||||
void kgsl_sparse_bind(struct kgsl_process_private *private,
|
||||
struct kgsl_drawobj_sparse *sparseobj)
|
||||
{
|
||||
struct kgsl_sparseobj_node *sparse_node;
|
||||
struct kgsl_mem_entry *virt_entry = NULL;
|
||||
long ret = 0;
|
||||
char *name;
|
||||
|
||||
virt_entry = kgsl_sharedmem_find_id_flags(private, sparseobj->id,
|
||||
KGSL_MEMFLAGS_SPARSE_VIRT);
|
||||
if (virt_entry == NULL)
|
||||
return;
|
||||
|
||||
list_for_each_entry(sparse_node, &sparseobj->sparselist, node) {
|
||||
if (sparse_node->obj.flags & KGSL_SPARSE_BIND) {
|
||||
ret = sparse_bind_range(private, &sparse_node->obj,
|
||||
virt_entry);
|
||||
name = "bind";
|
||||
} else {
|
||||
ret = sparse_unbind_range(&sparse_node->obj,
|
||||
virt_entry);
|
||||
name = "unbind";
|
||||
}
|
||||
|
||||
if (ret)
|
||||
KGSL_CORE_ERR("kgsl: Unable to '%s' ret %ld virt_id %d, phys_id %d, virt_offset %16.16llX, phys_offset %16.16llX, size %16.16llX, flags %16.16llX\n",
|
||||
name, ret, sparse_node->virt_id,
|
||||
sparse_node->obj.id,
|
||||
sparse_node->obj.virtoffset,
|
||||
sparse_node->obj.physoffset,
|
||||
sparse_node->obj.size, sparse_node->obj.flags);
|
||||
}
|
||||
|
||||
kgsl_mem_entry_put(virt_entry);
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_sparse_bind);
|
||||
|
||||
long kgsl_ioctl_gpuobj_info(struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data)
|
||||
{
|
||||
|
@ -4656,7 +4804,7 @@ static void kgsl_core_exit(void)
|
|||
kgsl_driver.class = NULL;
|
||||
}
|
||||
|
||||
kgsl_drawobj_exit();
|
||||
kgsl_drawobjs_cache_exit();
|
||||
|
||||
kgsl_memfree_exit();
|
||||
unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX);
|
||||
|
@ -4732,7 +4880,7 @@ static int __init kgsl_core_init(void)
|
|||
|
||||
kgsl_events_init();
|
||||
|
||||
result = kgsl_drawobj_init();
|
||||
result = kgsl_drawobjs_cache_init();
|
||||
if (result)
|
||||
goto err;
|
||||
|
||||
|
|
|
@ -100,6 +100,7 @@ static inline void KGSL_STATS_ADD(uint64_t size, atomic_long_t *stat,
|
|||
|
||||
#define KGSL_MAX_NUMIBS 100000
|
||||
#define KGSL_MAX_SYNCPOINTS 32
|
||||
#define KGSL_MAX_SPARSE 1000
|
||||
|
||||
struct kgsl_device;
|
||||
struct kgsl_context;
|
||||
|
@ -432,6 +433,8 @@ long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv,
|
|||
unsigned int cmd, void *data);
|
||||
long kgsl_ioctl_sparse_unbind(struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data);
|
||||
long kgsl_ioctl_gpu_sparse_command(struct kgsl_device_private *dev_priv,
|
||||
unsigned int cmd, void *data);
|
||||
|
||||
void kgsl_mem_entry_destroy(struct kref *kref);
|
||||
|
||||
|
|
|
@ -382,6 +382,8 @@ static const struct kgsl_ioctl kgsl_compat_ioctl_funcs[] = {
|
|||
kgsl_ioctl_sparse_virt_free),
|
||||
KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND,
|
||||
kgsl_ioctl_sparse_bind),
|
||||
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPU_SPARSE_COMMAND,
|
||||
kgsl_ioctl_gpu_sparse_command),
|
||||
};
|
||||
|
||||
long kgsl_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
|
||||
|
|
|
@ -203,6 +203,18 @@ struct kgsl_memobj_node {
|
|||
unsigned long priv;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct kgsl_sparseobj_node - Sparse object descriptor
|
||||
* @node: Local list node for the sparse cmdbatch
|
||||
* @virt_id: Virtual ID to bind/unbind
|
||||
* @obj: struct kgsl_sparse_binding_object
|
||||
*/
|
||||
struct kgsl_sparseobj_node {
|
||||
struct list_head node;
|
||||
unsigned int virt_id;
|
||||
struct kgsl_sparse_binding_object obj;
|
||||
};
|
||||
|
||||
struct kgsl_device {
|
||||
struct device *dev;
|
||||
const char *name;
|
||||
|
@ -639,6 +651,9 @@ long kgsl_ioctl_copy_in(unsigned int kernel_cmd, unsigned int user_cmd,
|
|||
long kgsl_ioctl_copy_out(unsigned int kernel_cmd, unsigned int user_cmd,
|
||||
unsigned long, unsigned char *ptr);
|
||||
|
||||
void kgsl_sparse_bind(struct kgsl_process_private *private,
|
||||
struct kgsl_drawobj_sparse *sparse);
|
||||
|
||||
/**
|
||||
* kgsl_context_put() - Release context reference count
|
||||
* @context: Pointer to the KGSL context to be released
|
||||
|
|
|
@ -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;
|
||||
struct kgsl_drawobj_cmd *cmdobj = _drawobj_create(device,
|
||||
context, sizeof(*cmdobj),
|
||||
(type & (CMDOBJ_TYPE | MARKEROBJ_TYPE)));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
container_of(obj, struct kgsl_drawobj_sync, base)
|
||||
#define CMDOBJ(obj) \
|
||||
container_of(obj, struct kgsl_drawobj_cmd, base)
|
||||
#define SPARSEOBJ(obj) \
|
||||
container_of(obj, struct kgsl_drawobj_sparse, base)
|
||||
|
||||
#define CMDOBJ_TYPE BIT(0)
|
||||
#define MARKEROBJ_TYPE BIT(1)
|
||||
#define SYNCOBJ_TYPE BIT(2)
|
||||
#define SPARSEOBJ_TYPE BIT(3)
|
||||
|
||||
/**
|
||||
* struct kgsl_drawobj - KGSL drawobj descriptor
|
||||
|
@ -45,7 +48,7 @@ struct kgsl_drawobj {
|
|||
* struct kgsl_drawobj_cmd - KGSL command obj, This covers marker
|
||||
* cmds also since markers are special form of cmds that do not
|
||||
* need their cmds to be executed.
|
||||
* @base: Base kgsl_drawobj
|
||||
* @base: Base kgsl_drawobj, this needs to be the first entry
|
||||
* @priv: Internal flags
|
||||
* @global_ts: The ringbuffer timestamp corresponding to this
|
||||
* command obj
|
||||
|
@ -123,6 +126,22 @@ struct kgsl_drawobj_sync_event {
|
|||
struct kgsl_device *device;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct kgsl_drawobj_sparse - KGSl sparse obj descriptor
|
||||
* @base: Base kgsl_obj, this needs to be the first entry
|
||||
* @id: virtual id of the bind/unbind
|
||||
* @sparselist: list of binds/unbinds
|
||||
* @size: Size of kgsl_sparse_bind_object
|
||||
* @count: Number of elements in list
|
||||
*/
|
||||
struct kgsl_drawobj_sparse {
|
||||
struct kgsl_drawobj base;
|
||||
unsigned int id;
|
||||
struct list_head sparselist;
|
||||
unsigned int size;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
#define KGSL_DRAWOBJ_FLAGS \
|
||||
{ KGSL_DRAWOBJ_MARKER, "MARKER" }, \
|
||||
{ KGSL_DRAWOBJ_CTX_SWITCH, "CTX_SWITCH" }, \
|
||||
|
@ -172,9 +191,15 @@ int kgsl_drawobj_sync_add_synclist(struct kgsl_device *device,
|
|||
int kgsl_drawobj_sync_add_sync(struct kgsl_device *device,
|
||||
struct kgsl_drawobj_sync *syncobj,
|
||||
struct kgsl_cmd_syncpoint *sync);
|
||||
struct kgsl_drawobj_sparse *kgsl_drawobj_sparse_create(
|
||||
struct kgsl_device *device,
|
||||
struct kgsl_context *context, unsigned int flags);
|
||||
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);
|
||||
|
||||
int kgsl_drawobj_init(void);
|
||||
void kgsl_drawobj_exit(void);
|
||||
int kgsl_drawobjs_cache_init(void);
|
||||
void kgsl_drawobjs_cache_exit(void);
|
||||
|
||||
void kgsl_dump_syncpoints(struct kgsl_device *device,
|
||||
struct kgsl_drawobj_sync *syncobj);
|
||||
|
|
|
@ -100,6 +100,8 @@ static const struct kgsl_ioctl kgsl_ioctl_funcs[] = {
|
|||
kgsl_ioctl_sparse_virt_free),
|
||||
KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND,
|
||||
kgsl_ioctl_sparse_bind),
|
||||
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPU_SPARSE_COMMAND,
|
||||
kgsl_ioctl_gpu_sparse_command),
|
||||
};
|
||||
|
||||
long kgsl_ioctl_copy_in(unsigned int kernel_cmd, unsigned int user_cmd,
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#define KGSL_CONTEXT_IFH_NOP 0x00010000
|
||||
#define KGSL_CONTEXT_SECURE 0x00020000
|
||||
#define KGSL_CONTEXT_NO_SNAPSHOT 0x00040000
|
||||
#define KGSL_CONTEXT_SPARSE 0x00080000
|
||||
|
||||
#define KGSL_CONTEXT_PREEMPT_STYLE_MASK 0x0E000000
|
||||
#define KGSL_CONTEXT_PREEMPT_STYLE_SHIFT 25
|
||||
|
@ -89,6 +90,7 @@
|
|||
#define KGSL_CMDBATCH_END_OF_FRAME KGSL_CONTEXT_END_OF_FRAME /* 0x100 */
|
||||
#define KGSL_CMDBATCH_SYNC KGSL_CONTEXT_SYNC /* 0x400 */
|
||||
#define KGSL_CMDBATCH_PWR_CONSTRAINT KGSL_CONTEXT_PWR_CONSTRAINT /* 0x800 */
|
||||
#define KGSL_CMDBATCH_SPARSE 0x1000 /* 0x1000 */
|
||||
|
||||
/*
|
||||
* Reserve bits [16:19] and bits [28:31] for possible bits shared between
|
||||
|
@ -1556,4 +1558,34 @@ struct kgsl_sparse_bind {
|
|||
#define IOCTL_KGSL_SPARSE_BIND \
|
||||
_IOW(KGSL_IOC_TYPE, 0x54, struct kgsl_sparse_bind)
|
||||
|
||||
/**
|
||||
* struct kgsl_gpu_sparse_command - Argument for
|
||||
* IOCTL_KGSL_GPU_SPARSE_COMMAND
|
||||
* @flags: Current flags for the object
|
||||
* @sparselist: List of kgsl_sparse_binding_object to bind/unbind
|
||||
* @synclist: List of kgsl_command_syncpoints
|
||||
* @sparsesize: Size of kgsl_sparse_binding_object
|
||||
* @numsparse: Number of elements in list
|
||||
* @sync_size: Size of kgsl_command_syncpoint structure
|
||||
* @numsyncs: Number of kgsl_command_syncpoints in syncpoint list
|
||||
* @context_id: Context ID submitting the kgsl_gpu_command
|
||||
* @timestamp: Timestamp for the submitted commands
|
||||
* @id: Virtual ID to bind/unbind
|
||||
*/
|
||||
struct kgsl_gpu_sparse_command {
|
||||
uint64_t flags;
|
||||
uint64_t __user sparselist;
|
||||
uint64_t __user synclist;
|
||||
unsigned int sparsesize;
|
||||
unsigned int numsparse;
|
||||
unsigned int syncsize;
|
||||
unsigned int numsyncs;
|
||||
unsigned int context_id;
|
||||
unsigned int timestamp;
|
||||
unsigned int id;
|
||||
};
|
||||
|
||||
#define IOCTL_KGSL_GPU_SPARSE_COMMAND \
|
||||
_IOWR(KGSL_IOC_TYPE, 0x55, struct kgsl_gpu_sparse_command)
|
||||
|
||||
#endif /* _UAPI_MSM_KGSL_H */
|
||||
|
|
Loading…
Add table
Reference in a new issue