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

Commit 4eadfaf5 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Add Bind objects to dispatcher draw queue"

parents 7a9eaaea c71cda2d
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