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

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

sync: Add a "details" callback for sync points



Allow drivers to add a callback for expanded details about a sync
point.  This provides for a much richer debug experience than can
be provided by the simpler callbacks.

Change-Id: Ic0dedbad19fddc2f9b753d886994247e8025d6dc
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
parent a316a2a6
Loading
Loading
Loading
Loading
+69 −44
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@
static void sync_fence_signal_pt(struct sync_pt *pt);
static int _sync_pt_has_signaled(struct sync_pt *pt);
static void sync_fence_free(struct kref *kref);
static void sync_dump(struct sync_fence *fence);

static LIST_HEAD(sync_timeline_list_head);
static DEFINE_SPINLOCK(sync_timeline_list_lock);
@@ -587,6 +586,73 @@ static bool sync_fence_check(struct sync_fence *fence)
	return fence->status != 0;
}

static const char *sync_status_str(int status)
{
	if (status > 0)
		return "signaled";
	else if (status == 0)
		return "active";
	else
		return "error";
}

static void sync_pt_log(struct sync_pt *pt)
{
	int status = pt->status;
	pr_cont("  %s_pt %s",
		   pt->parent->name,
		   sync_status_str(status));

	if (pt->status) {
		struct timeval tv = ktime_to_timeval(pt->timestamp);
		pr_cont("@%ld.%06ld", tv.tv_sec, tv.tv_usec);
	}

	if (pt->parent->ops->timeline_value_str &&
	    pt->parent->ops->pt_value_str) {
		char value[64];
		pt->parent->ops->pt_value_str(pt, value, sizeof(value));
		pr_cont(": %s", value);
		pt->parent->ops->timeline_value_str(pt->parent, value,
					    sizeof(value));
		pr_cont(" / %s", value);
	}

	pr_cont("\n");

	if (pt->parent->ops->pt_log)
		pt->parent->ops->pt_log(pt);
}

void sync_fence_log(struct sync_fence *fence)
{
	struct list_head *pos;
	unsigned long flags;

	pr_info("[%p] %s: %s\n", fence, fence->name,
		sync_status_str(fence->status));

	pr_info("waiters:\n");

	spin_lock_irqsave(&fence->waiter_list_lock, flags);
	list_for_each(pos, &fence->waiter_list_head) {
		struct sync_fence_waiter *waiter =
			container_of(pos, struct sync_fence_waiter,
				     waiter_list);

		pr_info(" %pF\n", waiter->callback);
	}
	spin_unlock_irqrestore(&fence->waiter_list_lock, flags);

	pr_info("syncpoints:\n");
	list_for_each(pos, &fence->pt_list_head) {
		struct sync_pt *pt =
			container_of(pos, struct sync_pt, pt_list);
		sync_pt_log(pt);
	}
}
EXPORT_SYMBOL(sync_fence_log);

int sync_fence_wait(struct sync_fence *fence, long timeout)
{
	int err = 0;
@@ -612,7 +678,7 @@ int sync_fence_wait(struct sync_fence *fence, long timeout)

	if (fence->status < 0) {
		pr_info("fence error %d on [%p]\n", fence->status, fence);
		sync_dump(fence);
		sync_fence_log(fence);
		return fence->status;
	}

@@ -620,7 +686,7 @@ int sync_fence_wait(struct sync_fence *fence, long timeout)
		if (timeout > 0) {
			pr_info("fence timeout on [%p] after %dms\n", fence,
				jiffies_to_msecs(timeout));
			sync_dump(fence);
			sync_fence_log(fence);
		}
		return -ETIME;
	}
@@ -842,16 +908,6 @@ static long sync_fence_ioctl(struct file *file, unsigned int cmd,
}

#ifdef CONFIG_DEBUG_FS
static const char *sync_status_str(int status)
{
	if (status > 0)
		return "signaled";
	else if (status == 0)
		return "active";
	else
		return "error";
}

static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence)
{
	int status = pt->status;
@@ -984,35 +1040,4 @@ static __init int sync_debugfs_init(void)
	return 0;
}
late_initcall(sync_debugfs_init);

#define DUMP_CHUNK 256
static char sync_dump_buf[64 * 1024];
static void sync_dump(struct sync_fence *fence)
{
	struct seq_file s = {
		.buf = sync_dump_buf,
		.size = sizeof(sync_dump_buf) - 1,
	};
	int i;

	seq_puts(&s, "fence:\n--------------\n");
	sync_print_fence(&s, fence);
	seq_puts(&s, "\n");

	for (i = 0; i < s.count; i += DUMP_CHUNK) {
		if ((s.count - i) > DUMP_CHUNK) {
			char c = s.buf[i + DUMP_CHUNK];
			s.buf[i + DUMP_CHUNK] = 0;
			pr_cont("%s", s.buf + i);
			s.buf[i + DUMP_CHUNK] = c;
		} else {
			s.buf[s.count] = 0;
			pr_cont("%s", s.buf + i);
		}
	}
}
#else
static void sync_dump(struct sync_fence *fence)
{
}
#endif
+12 −0
Original line number Diff line number Diff line
@@ -84,6 +84,9 @@ struct sync_timeline_ops {

	/* optional */
	void (*pt_value_str)(struct sync_pt *pt, char *str, int size);

	/* optional */
	void (*pt_log)(struct sync_pt *pt);
};

/**
@@ -342,6 +345,15 @@ int sync_fence_cancel_async(struct sync_fence *fence,
 */
int sync_fence_wait(struct sync_fence *fence, long timeout);

/**
 * sync_fence_log() - log the details of the fence in the kernel log
 * @fence:	fence to log
 *
 * Log the details of the fence and the associated sync points in the kernel
 * log.
 */
void sync_fence_log(struct sync_fence *fence);

#endif /* __KERNEL__ */

/**