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

Commit 5bf744cc authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Add timeline traces"

parents 7f766a68 3a9c5960
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -17,7 +17,8 @@ msm_kgsl_core-y = \
	kgsl_rgmu.o \
	kgsl_hfi.o \
	kgsl_pool.o \
	kgsl_reclaim.o
	kgsl_reclaim.o \
	kgsl_timeline.o

msm_kgsl_core-$(CONFIG_QCOM_KGSL_IOMMU) += kgsl_iommu.o
msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o
+14 −3
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2002,2008-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2002,2008-2021, The Linux Foundation. All rights reserved.
 */

#include <linux/debugfs.h>
@@ -147,11 +147,22 @@ static void sync_event_print(struct seq_file *s,
		break;
	}
	case KGSL_CMD_SYNCPOINT_TYPE_FENCE: {
		struct event_fence_info *info = sync_event ?
				sync_event->priv : NULL;
		int i;

		for (i = 0; i < sync_event->info.num_fences; i++)
		for (i = 0; info && i < info->num_fences; i++)
			seq_printf(s, "sync: %s",
				sync_event->info.fences[i].name);
				info->fences[i].name);
		break;
	}
	case KGSL_CMD_SYNCPOINT_TYPE_TIMELINE: {
		struct event_timeline_info *info = sync_event->priv;
		int j;

		for (j = 0; info && info[j].timeline; j++)
			seq_printf(s, "timeline: %d seqno: %d",
				info[j].timeline, info[j].seqno);
		break;
	}
	default:
+87 −42
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
 */

#include <linux/slab.h>
@@ -8,6 +8,7 @@
#include "adreno.h"
#include "adreno_trace.h"
#include "kgsl_gmu_core.h"
#include "kgsl_timeline.h"

#define DRAWQUEUE_NEXT(_i, _s) (((_i) + 1) % (_s))

@@ -276,6 +277,7 @@ static void _retire_timestamp(struct kgsl_drawobj *drawobj)
		KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp),
		drawobj->timestamp);

	drawctxt->submitted_timestamp = drawobj->timestamp;

	/* Retire pending GPU events for the object */
	kgsl_process_event_group(device, &context->events);
@@ -342,12 +344,14 @@ static void _retire_sparseobj(struct kgsl_drawobj_sparse *sparseobj,
	_retire_timestamp(DRAWOBJ(sparseobj));
}

static int _retire_markerobj(struct kgsl_drawobj_cmd *cmdobj,
static int dispatch_retire_markerobj(struct kgsl_drawobj *drawobj,
				struct adreno_context *drawctxt)
{
	struct kgsl_drawobj_cmd *cmdobj = CMDOBJ(drawobj);

	if (_marker_expired(cmdobj)) {
		_pop_drawobj(drawctxt);
		_retire_timestamp(DRAWOBJ(cmdobj));
		_retire_timestamp(drawobj);
		return 0;
	}

@@ -363,12 +367,14 @@ static int _retire_markerobj(struct kgsl_drawobj_cmd *cmdobj,
	return test_bit(CMDOBJ_SKIP, &cmdobj->priv) ? 1 : -EAGAIN;
}

static int _retire_syncobj(struct kgsl_drawobj_sync *syncobj,
static int dispatch_retire_syncobj(struct kgsl_drawobj *drawobj,
				struct adreno_context *drawctxt)
{
	struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj);

	if (!kgsl_drawobj_events_pending(syncobj)) {
		_pop_drawobj(drawctxt);
		kgsl_drawobj_destroy(DRAWOBJ(syncobj));
		kgsl_drawobj_destroy(drawobj);
		return 0;
	}

@@ -384,6 +390,22 @@ static int _retire_syncobj(struct kgsl_drawobj_sync *syncobj,
	return -EAGAIN;
}

static int drawqueue_retire_timelineobj(struct kgsl_drawobj *drawobj,
		struct adreno_context *drawctxt)
{
	struct kgsl_drawobj_timeline *timelineobj = TIMELINEOBJ(drawobj);
	int i;

	for (i = 0; i < timelineobj->count; i++)
		kgsl_timeline_signal(timelineobj->timelines[i].timeline,
			timelineobj->timelines[i].seqno);

	_pop_drawobj(drawctxt);
	_retire_timestamp(drawobj);

	return 0;
}

/*
 * Retires all expired marker and sync objs from the context
 * queue and returns one of the below
@@ -397,35 +419,40 @@ static struct kgsl_drawobj *_process_drawqueue_get_next_drawobj(
{
	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)) {
		int ret = 0;

		drawobj = drawctxt->drawqueue[i];

		if (drawobj == NULL)
		if (!drawobj)
			return NULL;

		if (drawobj->type == CMDOBJ_TYPE)
		switch (drawobj->type) {
		case CMDOBJ_TYPE:
			return drawobj;
		else if (drawobj->type == MARKEROBJ_TYPE) {
			ret = _retire_markerobj(CMDOBJ(drawobj), drawctxt);
		case MARKEROBJ_TYPE:
			ret = dispatch_retire_markerobj(drawobj, drawctxt);
			/* Special case where marker needs to be sent to GPU */
			if (ret == 1)
				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);
			break;
		case SYNCOBJ_TYPE:
			ret = dispatch_retire_syncobj(drawobj, drawctxt);
			break;
		case TIMELINEOBJ_TYPE:
			ret = drawqueue_retire_timelineobj(drawobj, drawctxt);
			break;
		default:
			ret = -EINVAL;
			break;
		}

		continue;
		if (ret)
			return ERR_PTR(ret);
	}

	return NULL;
@@ -696,7 +723,7 @@ static struct kgsl_drawobj_sparse *_get_next_sparseobj(
			return NULL;

		if (drawobj->type == SYNCOBJ_TYPE)
			ret = _retire_syncobj(SYNCOBJ(drawobj), drawctxt);
			ret = dispatch_retire_syncobj(drawobj, drawctxt);
		else if (drawobj->type == SPARSEOBJ_TYPE)
			return SPARSEOBJ(drawobj);
		else
@@ -1247,12 +1274,27 @@ static int _queue_sparseobj(struct adreno_device *adreno_dev,
	return 0;
}

static int drawctxt_queue_auxobj(struct adreno_device *adreno_dev,
		struct adreno_context *drawctxt, struct kgsl_drawobj *drawobj,
		u32 *timestamp, u32 user_ts)
{
	int ret;

	ret = get_timestamp(drawctxt, drawobj, timestamp, user_ts);
	if (ret)
		return ret;

	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,
static int drawctxt_queue_markerobj(struct adreno_device *adreno_dev,
	struct adreno_context *drawctxt, struct kgsl_drawobj *drawobj,
	uint32_t *timestamp, unsigned int user_ts)
{
	struct kgsl_drawobj *drawobj = DRAWOBJ(markerobj);
	struct kgsl_drawobj_cmd *markerobj = CMDOBJ(drawobj);
	int ret;

	ret = get_timestamp(drawctxt, drawobj, timestamp, user_ts);
@@ -1285,11 +1327,11 @@ static int _queue_markerobj(struct adreno_device *adreno_dev,
	return 0;
}

static int _queue_cmdobj(struct adreno_device *adreno_dev,
	struct adreno_context *drawctxt, struct kgsl_drawobj_cmd *cmdobj,
static int drawctxt_queue_cmdobj(struct adreno_device *adreno_dev,
	struct adreno_context *drawctxt, struct kgsl_drawobj *drawobj,
	uint32_t *timestamp, unsigned int user_ts)
{
	struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj);
	struct kgsl_drawobj_cmd *cmdobj = CMDOBJ(drawobj);
	unsigned int j;
	int ret;

@@ -1323,11 +1365,9 @@ static int _queue_cmdobj(struct adreno_device *adreno_dev,
	return 0;
}

static void _queue_syncobj(struct adreno_context *drawctxt,
	struct kgsl_drawobj_sync *syncobj, uint32_t *timestamp)
static void drawctxt_queue_syncobj(struct adreno_context *drawctxt,
	struct kgsl_drawobj *drawobj, uint32_t *timestamp)
{
	struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj);

	*timestamp = 0;
	drawobj->timestamp = 0;

@@ -1401,29 +1441,34 @@ int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv,

		switch (drawobj[i]->type) {
		case MARKEROBJ_TYPE:
			ret = _queue_markerobj(adreno_dev, drawctxt,
					CMDOBJ(drawobj[i]),
					timestamp, user_ts);
			if (ret == 1) {
			ret = drawctxt_queue_markerobj(adreno_dev, drawctxt,
				drawobj[i], timestamp, user_ts);
			if (ret)
				spin_unlock(&drawctxt->lock);

			if (ret == 1)
				goto done;
			} else if (ret) {
				spin_unlock(&drawctxt->lock);
			else if (ret)
				return ret;
			}
			break;
		case CMDOBJ_TYPE:
			ret = _queue_cmdobj(adreno_dev, drawctxt,
						CMDOBJ(drawobj[i]),
						timestamp, user_ts);
			ret = drawctxt_queue_cmdobj(adreno_dev, drawctxt,
				drawobj[i], timestamp, user_ts);
			if (ret) {
				spin_unlock(&drawctxt->lock);
				return ret;
			}
			break;
		case SYNCOBJ_TYPE:
			_queue_syncobj(drawctxt, SYNCOBJ(drawobj[i]),
						timestamp);
			drawctxt_queue_syncobj(drawctxt, drawobj[i], timestamp);
			break;
		case TIMELINEOBJ_TYPE:
			ret = drawctxt_queue_auxobj(adreno_dev,
				drawctxt, drawobj[i], timestamp, user_ts);
			if (ret) {
				spin_unlock(&drawctxt->lock);
				return ret;
			}
			break;
		case SPARSEOBJ_TYPE:
			ret = _queue_sparseobj(adreno_dev, drawctxt,
+127 −0
Original line number Diff line number Diff line
@@ -2107,6 +2107,129 @@ long kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv,
	return result;
}

long kgsl_ioctl_gpu_aux_command(struct kgsl_device_private *dev_priv,
		unsigned int cmd, void *data)
{
	struct kgsl_gpu_aux_command *param = data;
	struct kgsl_device *device = dev_priv->device;
	struct kgsl_context *context;
	struct kgsl_drawobj **drawobjs;
	struct kgsl_drawobj_sync *tsobj;
	void __user *cmdlist;
	u32 queued, count;
	int i, index = 0;
	long ret;
	struct kgsl_gpu_aux_command_generic generic;

	/* We support only one aux command */
	if (param->numcmds != 1)
		return -EINVAL;

	if (!(param->flags & KGSL_GPU_AUX_COMMAND_TIMELINE))
		return -EINVAL;

	context = kgsl_context_get_owner(dev_priv, param->context_id);
	if (!context)
		return -EINVAL;

	/*
	 * param->numcmds is always one and we have one additional drawobj
	 * for the timestamp sync if KGSL_GPU_AUX_COMMAND_SYNC flag is passed.
	 * On top of that we make an implicit sync object for the last queued
	 * timestamp on this context.
	 */
	count = (param->flags & KGSL_GPU_AUX_COMMAND_SYNC) ? 3 : 2;

	drawobjs = kvcalloc(count, sizeof(*drawobjs), GFP_KERNEL);

	if (!drawobjs) {
		kgsl_context_put(context);
		return -ENOMEM;
	}

	trace_kgsl_aux_command(context->id, param->numcmds, param->flags,
		param->timestamp);

	if (param->flags & KGSL_GPU_AUX_COMMAND_SYNC) {
		struct kgsl_drawobj_sync *syncobj =
			kgsl_drawobj_sync_create(device, context);

		if (IS_ERR(syncobj)) {
			ret = PTR_ERR(syncobj);
			goto err;
		}

		drawobjs[index++] = DRAWOBJ(syncobj);

		ret = kgsl_drawobj_sync_add_synclist(device, syncobj,
				u64_to_user_ptr(param->synclist),
				param->syncsize, param->numsyncs);
		if (ret)
			goto err;
	}

	kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_QUEUED, &queued);

	/*
	 * Make an implicit sync object for the last queued timestamp on this
	 * context
	 */
	tsobj = kgsl_drawobj_create_timestamp_syncobj(device,
		context, queued);

	if (IS_ERR(tsobj)) {
		ret = PTR_ERR(tsobj);
		goto err;
	}

	drawobjs[index++] = DRAWOBJ(tsobj);

	cmdlist = u64_to_user_ptr(param->cmdlist);

	/* Create a draw object for KGSL_GPU_AUX_COMMAND_TIMELINE */
	if (kgsl_copy_struct_from_user(&generic, sizeof(generic),
		cmdlist, param->cmdsize)) {
		ret = -EFAULT;
		goto err;
	}

	if (generic.type == KGSL_GPU_AUX_COMMAND_TIMELINE) {
		struct kgsl_drawobj_timeline *timelineobj;

		timelineobj = kgsl_drawobj_timeline_create(device,
			context);

		if (IS_ERR(timelineobj)) {
			ret = PTR_ERR(timelineobj);
			goto err;
		}

		drawobjs[index++] = DRAWOBJ(timelineobj);

		ret = kgsl_drawobj_add_timeline(dev_priv, timelineobj,
			u64_to_user_ptr(generic.priv), generic.size);
		if (ret)
			goto err;
	} else {
		ret = -EINVAL;
		goto err;
	}

	ret = device->ftbl->queue_cmds(dev_priv, context,
		drawobjs, index, &param->timestamp);

err:
	kgsl_context_put(context);

	if (ret && ret != -EPROTO) {
		for (i = 0; i < count; i++)
			kgsl_drawobj_destroy(drawobjs[i]);
	}

	kvfree(drawobjs);
	return ret;
}

long kgsl_ioctl_cmdstream_readtimestamp_ctxtid(struct kgsl_device_private
						*dev_priv, unsigned int cmd,
						void *data)
@@ -5222,6 +5345,9 @@ int kgsl_device_platform_probe(struct kgsl_device *device)
	if (status)
		goto error_close_mmu;

	idr_init(&device->timelines);
	spin_lock_init(&device->timelines_lock);

	/*
	 * The default request type PM_QOS_REQ_ALL_CORES is
	 * applicable to all CPU cores that are online and
@@ -5296,6 +5422,7 @@ void kgsl_device_platform_remove(struct kgsl_device *device)
		pm_qos_remove_request(&device->pwrctrl.l2pc_cpus_qos);

	idr_destroy(&device->context_idr);
	idr_destroy(&device->timelines);

	kgsl_mmu_close(device);

+14 −0
Original line number Diff line number Diff line
@@ -425,6 +425,20 @@ long kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv,
				unsigned int cmd, void *data);
long kgsl_ioctl_gpuobj_set_info(struct kgsl_device_private *dev_priv,
				unsigned int cmd, void *data);
long kgsl_ioctl_gpu_aux_command(struct kgsl_device_private *dev_priv,
		unsigned int cmd, void *data);
long kgsl_ioctl_timeline_create(struct kgsl_device_private *dev_priv,
		unsigned int cmd, void *data);
long kgsl_ioctl_timeline_wait(struct kgsl_device_private *dev_priv,
		unsigned int cmd, void *data);
long kgsl_ioctl_timeline_query(struct kgsl_device_private *dev_priv,
		unsigned int cmd, void *data);
long kgsl_ioctl_timeline_fence_get(struct kgsl_device_private *dev_priv,
		unsigned int cmd, void *data);
long kgsl_ioctl_timeline_signal(struct kgsl_device_private *dev_priv,
		unsigned int cmd, void *data);
long kgsl_ioctl_timeline_destroy(struct kgsl_device_private *dev_priv,
		unsigned int cmd, void *data);

long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data);
Loading