Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c71cda2d authored by Tarun Karra's avatar Tarun Karra Committed by Gerrit - the friendly Code Review server
Browse files

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: default avatarTarun Karra <tkarra@codeaurora.org>
parent 368fecd7
Loading
Loading
Loading
Loading
+125 −2
Original line number Diff line number Diff line
@@ -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;
+2 −1
Original line number Diff line number Diff line
@@ -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 */

+150 −2
Original line number Diff line number Diff line
@@ -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, &param->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;

+3 −0
Original line number Diff line number Diff line
@@ -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);

+2 −0
Original line number Diff line number Diff line
@@ -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)
Loading