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

Commit a56ef037 authored by Jordan Crouse's avatar Jordan Crouse
Browse files

msm: kgsl: Add a sync fence timeout callback



Add a callback to get notification of timeouts on fences
that we own and use that to dump additional information.

Change-Id: Ic0dedbadec6af50cc8c741484a5547ae0ca92a83
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
parent e4e9b201
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2816,6 +2816,7 @@ static const struct kgsl_functable adreno_functable = {
	.drawctxt_create = adreno_drawctxt_create,
	.drawctxt_detach = adreno_drawctxt_detach,
	.drawctxt_destroy = adreno_drawctxt_destroy,
	.drawctxt_dump = adreno_drawctxt_dump,
	.setproperty = adreno_setproperty,
	.setproperty_compat = adreno_setproperty_compat,
	.drawctxt_sched = adreno_drawctxt_sched,
+43 −0
Original line number Diff line number Diff line
@@ -47,6 +47,49 @@ static int _check_context_timestamp(struct kgsl_device *device,
	return ret;
}

/**
 * adreno_drawctxt_dump() - dump information about a draw context
 * @device: KGSL device that owns the context
 * @context: KGSL context to dump information about
 *
 * Dump specific information about the context to the kernel log.  Used for
 * fence timeout callbacks
 */
void adreno_drawctxt_dump(struct kgsl_device *device,
		struct kgsl_context *context)
{
	unsigned int queue, start, retire;
	struct adreno_context *drawctxt = ADRENO_CONTEXT(context);

	mutex_lock(&drawctxt->mutex);

	kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_QUEUED, &queue);
	kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_CONSUMED, &start);
	kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED, &retire);

	dev_err(device->dev,
		"  context[%d]: queue=%d, start=%d, retire=%d\n",
		context->id, queue, start, retire);

	if (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) {
		struct kgsl_cmdbatch *cmdbatch =
			drawctxt->cmdqueue[drawctxt->cmdqueue_head];

		spin_lock(&cmdbatch->lock);

		if (!list_empty(&cmdbatch->synclist)) {
			dev_err(device->dev,
				"  context[%d] (ts=%d) Active sync points:\n",
				context->id, cmdbatch->timestamp);

			kgsl_dump_syncpoints(device, cmdbatch);
		}
		spin_unlock(&cmdbatch->lock);
	}

	mutex_unlock(&drawctxt->mutex);
}

/**
 * adreno_drawctxt_wait() - sleep until a timestamp expires
 * @adreno_dev: pointer to the adreno_device struct
+3 −0
Original line number Diff line number Diff line
@@ -113,4 +113,7 @@ int adreno_drawctxt_wait(struct adreno_device *adreno_dev,
void adreno_drawctxt_invalidate(struct kgsl_device *device,
		struct kgsl_context *context);

void adreno_drawctxt_dump(struct kgsl_device *device,
		struct kgsl_context *context);

#endif  /* __ADRENO_DRAWCTXT_H */
+54 −16
Original line number Diff line number Diff line
@@ -476,6 +476,33 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
	entry->priv = NULL;
}

/**
 * kgsl_context_dump() - dump information about a draw context
 * @device: KGSL device that owns the context
 * @context: KGSL context to dump information about
 *
 * Dump specific information about the context to the kernel log.  Used for
 * fence timeout callbacks
 */
void kgsl_context_dump(struct kgsl_context *context)
{
	struct kgsl_device *device;

	if (_kgsl_context_get(context) == 0)
		return;

	device = context->device;

	if (kgsl_context_detached(context)) {
		dev_err(device->dev, "  context[%d]: context detached\n",
			context->id);
	} else if (device->ftbl->drawctxt_dump != NULL)
		device->ftbl->drawctxt_dump(device, context);

	kgsl_context_put(context);
}
EXPORT_SYMBOL(kgsl_context_dump);

/**
 * kgsl_context_init() - helper to initialize kgsl_context members
 * @dev_priv: the owner of the context
@@ -1476,22 +1503,11 @@ out:
 * goes empty indicating that all the sync points have been met.
 */

static void _kgsl_cmdbatch_timer(unsigned long data)
void kgsl_dump_syncpoints(struct kgsl_device *device,
	struct kgsl_cmdbatch *cmdbatch)
{
	struct kgsl_cmdbatch *cmdbatch = (struct kgsl_cmdbatch *) data;
	struct kgsl_cmdbatch_sync_event *event;

	if (cmdbatch == NULL || cmdbatch->context == NULL)
		return;

	spin_lock(&cmdbatch->lock);
	if (list_empty(&cmdbatch->synclist))
		goto done;

	pr_err("kgsl: possible gpu syncpoint deadlock for context %d timestamp %d\n",
		cmdbatch->context->id, cmdbatch->timestamp);
	pr_err(" Active sync points:\n");

	/* Print all the pending sync objects */
	list_for_each_entry(event, &cmdbatch->synclist, node) {

@@ -1503,22 +1519,44 @@ static void _kgsl_cmdbatch_timer(unsigned long data)
				event->context, KGSL_TIMESTAMP_RETIRED,
				&retired);

			pr_err("  [timestamp] context %d timestamp %d (retired %d)\n",
			dev_err(device->dev,
				"  [timestamp] context %d timestamp %d (retired %d)\n",
				event->context->id, event->timestamp,
				retired);
			break;
		}
		case KGSL_CMD_SYNCPOINT_TYPE_FENCE:
			if (event->handle && event->handle->fence)
				pr_err("  fence: [%p] %s\n",
				dev_err(device->dev, "  fence: [%p] %s\n",
					event->handle->fence,
					event->handle->fence->name);
			else
				pr_err("  fence: invalid\n");
				dev_err(device->dev, "  fence: invalid\n");
			break;
		}
	}
}

static void _kgsl_cmdbatch_timer(unsigned long data)
{
	struct kgsl_device *device;
	struct kgsl_cmdbatch *cmdbatch = (struct kgsl_cmdbatch *) data;

	if (cmdbatch == NULL || cmdbatch->context == NULL)
		return;

	spin_lock(&cmdbatch->lock);
	if (list_empty(&cmdbatch->synclist))
		goto done;

	device = cmdbatch->context->device;

	dev_err(device->dev,
		"kgsl: possible gpu syncpoint deadlock for context %d timestamp %d\n",
		cmdbatch->context->id, cmdbatch->timestamp);
	dev_err(device->dev, " Active sync points:\n");

	kgsl_dump_syncpoints(device, cmdbatch);
done:
	spin_unlock(&cmdbatch->lock);
}
+6 −0
Original line number Diff line number Diff line
@@ -165,6 +165,8 @@ struct kgsl_functable {
						uint32_t *flags);
	int (*drawctxt_detach) (struct kgsl_context *context);
	void (*drawctxt_destroy) (struct kgsl_context *context);
	void (*drawctxt_dump) (struct kgsl_device *device,
		struct kgsl_context *context);
	long (*ioctl) (struct kgsl_device_private *dev_priv,
		unsigned int cmd, void *data);
	long (*compat_ioctl) (struct kgsl_device_private *dev_priv,
@@ -708,6 +710,8 @@ int kgsl_context_init(struct kgsl_device_private *, struct kgsl_context
		*context);
int kgsl_context_detach(struct kgsl_context *context);

void kgsl_context_dump(struct kgsl_context *context);

int kgsl_memfree_find_entry(pid_t pid, unsigned long *gpuaddr,
	unsigned long *size, unsigned int *flags);

@@ -841,6 +845,8 @@ static inline struct kgsl_context *kgsl_context_get_owner(
	return context;
}

void kgsl_dump_syncpoints(struct kgsl_device *device,
	struct kgsl_cmdbatch *cmdbatch);

void kgsl_cmdbatch_destroy(struct kgsl_cmdbatch *cmdbatch);

Loading