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

Commit 423042f4 authored by Bryan O'Donoghue's avatar Bryan O'Donoghue Committed by Greg Kroah-Hartman
Browse files

greybus: timesync: Add debugfs entry to display frame-ping in ktime



This patch makes a debugfs entry in
/sys/kernel/debug/greybus/X-svc/frame-ktime that generates a TimeSync ping
event to the system and then subsequently presents that data to user-space
as a ktime/timespec clock-monotonic value rather than as a raw frame-time,
to aid humans in debugging and understanding frame-time and to provide an
example of the converting a frame-time to timespec/ktime to other
developers.

Signed-off-by: default avatarBryan O'Donoghue <bryan.odonoghue@linaro.org>
Acked-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 00fdbae1
Loading
Loading
Loading
Loading
+102 −12
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ struct gb_timesync_svc {
	struct mutex mutex;	/* Per SVC mutex for regular synchronization */

	struct dentry *frame_time_dentry;
	struct dentry *frame_ktime_dentry;
	struct workqueue_struct *work_queue;
	wait_queue_head_t wait_queue;
	struct delayed_work delayed_work;
@@ -506,6 +507,7 @@ static int gb_timesync_to_timespec(struct gb_timesync_svc *timesync_svc,
	bool add;
	int ret = 0;

	memset(ts, 0x00, sizeof(*ts));
	mutex_lock(&timesync_svc->mutex);
	spin_lock_irqsave(&timesync_svc->spinlock, flags);

@@ -575,7 +577,6 @@ static size_t gb_timesync_log_frame_time(struct gb_timesync_svc *timesync_svc,
	size_t off;

	/* AP/SVC */
	memset(buf, 0x00, buflen);
	off = snprintf(buf, buflen, "timesync: ping-time ap=%llu %s=%llu ",
		       timesync_svc->ap_ping_frame_time, dev_name(&svc->dev),
		       timesync_svc->svc_ping_frame_time);
@@ -604,6 +605,65 @@ static size_t gb_timesync_log_frame_time(struct gb_timesync_svc *timesync_svc,
	return off;
}

static size_t gb_timesync_log_frame_ktime(struct gb_timesync_svc *timesync_svc,
					  char *buf, size_t buflen)
{
	struct gb_svc *svc = timesync_svc->svc;
	struct gb_host_device *hd;
	struct gb_timesync_interface *timesync_interface;
	struct gb_interface *interface;
	struct timespec ts;
	unsigned int len;
	size_t off;

	/* AP */
	gb_timesync_to_timespec(timesync_svc, timesync_svc->ap_ping_frame_time,
				&ts);
	off = snprintf(buf, buflen, "timesync: ping-time ap=%lu.%lu ",
		       ts.tv_sec, ts.tv_nsec);
	len = buflen - off;
	if (len >= buflen)
		goto done;

	/* SVC */
	gb_timesync_to_timespec(timesync_svc, timesync_svc->svc_ping_frame_time,
				&ts);
	off += snprintf(&buf[off], len, "%s=%lu.%lu ", dev_name(&svc->dev),
			ts.tv_sec, ts.tv_nsec);
	len = buflen - off;
	if (len >= buflen)
		goto done;

	/* APB/GPB */
	hd = timesync_svc->timesync_hd->hd;
	gb_timesync_to_timespec(timesync_svc,
				timesync_svc->timesync_hd->ping_frame_time,
				&ts);
	off += snprintf(&buf[off], len, "%s=%lu.%lu ",
			dev_name(&hd->dev),
			ts.tv_sec, ts.tv_nsec);
	len = buflen - off;
	if (len >= buflen)
		goto done;

	list_for_each_entry(timesync_interface,
			    &timesync_svc->interface_list, list) {
		interface = timesync_interface->interface;
		gb_timesync_to_timespec(timesync_svc,
					timesync_interface->ping_frame_time,
					&ts);
		off += snprintf(&buf[off], len, "%s=%lu.%lu ",
				dev_name(&interface->dev),
				ts.tv_sec, ts.tv_nsec);
		len = buflen - off;
		if (len >= buflen)
			goto done;
	}
	off += snprintf(&buf[off], len, "\n");
done:
	return off;
}

/*
 * Send an SVC initiated wake 'ping' to each TimeSync participant.
 * Get the FrameTime from each participant associated with the wake
@@ -840,11 +900,11 @@ void gb_timesync_schedule_asynchronous(struct gb_interface *interface)
}
EXPORT_SYMBOL_GPL(gb_timesync_schedule_asynchronous);

static ssize_t gb_timesync_ping_read(struct file *file, char __user *buf,
				     size_t len, loff_t *offset)
static ssize_t gb_timesync_ping_read(struct file *file, char __user *ubuf,
				     size_t len, loff_t *offset, bool ktime)
{
	struct gb_timesync_svc *timesync_svc = file->f_inode->i_private;
	char *pbuf;
	char *buf;
	ssize_t ret = 0;

	mutex_lock(&gb_timesync_svc_list_mutex);
@@ -861,23 +921,44 @@ static ssize_t gb_timesync_ping_read(struct file *file, char __user *buf,
	if (ret)
		goto done;

	pbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
	if (!pbuf) {
	buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
	if (!buf) {
		ret = -ENOMEM;
		goto done;
	}

	ret = gb_timesync_log_frame_time(timesync_svc, pbuf, PAGE_SIZE);
	if (ktime)
		ret = gb_timesync_log_frame_ktime(timesync_svc, buf, PAGE_SIZE);
	else
		ret = gb_timesync_log_frame_time(timesync_svc, buf, PAGE_SIZE);
	if (ret > 0)
		ret = simple_read_from_buffer(buf, len, offset, pbuf, ret);
	kfree(pbuf);
		ret = simple_read_from_buffer(ubuf, len, offset, buf, ret);
	kfree(buf);
done:
	mutex_unlock(&gb_timesync_svc_list_mutex);
	return ret;
}

static const struct file_operations gb_timesync_debugfs_ops = {
	.read		= gb_timesync_ping_read,
static ssize_t gb_timesync_ping_read_frame_time(struct file *file,
						char __user *buf,
						size_t len, loff_t *offset)
{
	return gb_timesync_ping_read(file, buf, len, offset, false);
}

static ssize_t gb_timesync_ping_read_frame_ktime(struct file *file,
						 char __user *buf,
						 size_t len, loff_t *offset)
{
	return gb_timesync_ping_read(file, buf, len, offset, true);
}

static const struct file_operations gb_timesync_debugfs_frame_time_ops = {
	.read		= gb_timesync_ping_read_frame_time,
};

static const struct file_operations gb_timesync_debugfs_frame_ktime_ops = {
	.read		= gb_timesync_ping_read_frame_ktime,
};

static int gb_timesync_hd_add(struct gb_timesync_svc *timesync_svc,
@@ -935,13 +1016,21 @@ int gb_timesync_svc_add(struct gb_svc *svc)
	timesync_svc->frame_time_offset = 0;
	timesync_svc->capture_ping = false;
	gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_INACTIVE);

	timesync_svc->frame_time_dentry =
		debugfs_create_file("frame-time", S_IRUGO, svc->debugfs_dentry,
				    timesync_svc, &gb_timesync_debugfs_ops);
				    timesync_svc,
				    &gb_timesync_debugfs_frame_time_ops);
	timesync_svc->frame_ktime_dentry =
		debugfs_create_file("frame-ktime", S_IRUGO, svc->debugfs_dentry,
				    timesync_svc,
				    &gb_timesync_debugfs_frame_ktime_ops);

	list_add(&timesync_svc->list, &gb_timesync_svc_list);
	ret = gb_timesync_hd_add(timesync_svc, svc->hd);
	if (ret) {
		list_del(&timesync_svc->list);
		debugfs_remove(timesync_svc->frame_ktime_dentry);
		debugfs_remove(timesync_svc->frame_time_dentry);
		destroy_workqueue(timesync_svc->work_queue);
		kfree(timesync_svc);
@@ -982,6 +1071,7 @@ void gb_timesync_svc_remove(struct gb_svc *svc)
		kfree(timesync_interface);
	}
	gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_INVALID);
	debugfs_remove(timesync_svc->frame_ktime_dentry);
	debugfs_remove(timesync_svc->frame_time_dentry);
	cancel_delayed_work_sync(&timesync_svc->delayed_work);
	destroy_workqueue(timesync_svc->work_queue);