diff mbox

[RFC,06/11] sync: add ioctl to get fence data

Message ID 1338939956-17312-7-git-send-email-konkers@android.com
State New
Headers show

Commit Message

Erik Gilling June 5, 2012, 11:45 p.m. UTC
The utility of this is two fold.  First, userspace clients of the sync
framework can collect data (such as timestamps) to profile the graphics
pipeline.  Second this lets user space libraries (such as GL) embed sync
data in command stream they are preparing for submission.

Signed-off-by: Erik Gilling <konkers@android.com>
---
 drivers/base/sync.c  |   81 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/sync.h |   57 +++++++++++++++++++++++++++++++++++
 2 files changed, 138 insertions(+), 0 deletions(-)
diff mbox

Patch

diff --git a/drivers/base/sync.c b/drivers/base/sync.c
index 49fcfc4..80749ec 100644
--- a/drivers/base/sync.c
+++ b/drivers/base/sync.c
@@ -551,6 +551,84 @@  err_put_fd:
 	return err;
 }
 
+static int sync_fill_pt_info(struct sync_pt *pt, void *data, int size)
+{
+	struct sync_pt_info *info = data;
+	int ret;
+
+	if (size < sizeof(struct sync_pt_info))
+		return -ENOMEM;
+
+	info->len = sizeof(struct sync_pt_info);
+
+	if (pt->parent->ops->fill_driver_data) {
+		ret = pt->parent->ops->fill_driver_data(pt, info->driver_data,
+							size - sizeof(*info));
+		if (ret < 0)
+			return ret;
+
+		info->len += ret;
+	}
+
+	strlcpy(info->obj_name, pt->parent->name, sizeof(info->obj_name));
+	strlcpy(info->driver_name, pt->parent->ops->driver_name,
+		sizeof(info->driver_name));
+	info->status = pt->status;
+	info->timestamp_ns = ktime_to_ns(pt->timestamp);
+
+	return info->len;
+}
+
+static long sync_fence_ioctl_fence_info(struct sync_fence *fence,
+					unsigned long arg)
+{
+	struct sync_fence_info_data *data;
+	struct list_head *pos;
+	__u32 size;
+	__u32 len = 0;
+	int ret;
+
+	if (copy_from_user(&size, (void __user *)arg, sizeof(size)))
+		return -EFAULT;
+
+	if (size < sizeof(struct sync_fence_info_data))
+		return -EINVAL;
+
+	if (size > 4096)
+		size = 4096;
+
+	data = kzalloc(size, GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	strlcpy(data->name, fence->name, sizeof(data->name));
+	data->status = fence->status;
+	len = sizeof(struct sync_fence_info_data);
+
+	list_for_each(pos, &fence->pt_list_head) {
+		struct sync_pt *pt =
+			container_of(pos, struct sync_pt, pt_list);
+
+		ret = sync_fill_pt_info(pt, (u8 *)data + len, size - len);
+
+		if (ret < 0)
+			goto out;
+
+		len += ret;
+	}
+
+	data->len = len;
+
+	if (copy_to_user((void __user *)arg, data, len))
+		ret = -EFAULT;
+	else
+		ret = 0;
+
+out:
+	kfree(data);
+
+	return ret;
+}
 
 static long sync_fence_ioctl(struct file *file, unsigned int cmd,
 			     unsigned long arg)
@@ -563,6 +641,9 @@  static long sync_fence_ioctl(struct file *file, unsigned int cmd,
 	case SYNC_IOC_MERGE:
 		return sync_fence_ioctl_merge(fence, arg);
 
+	case SYNC_IOC_FENCE_INFO:
+		return sync_fence_ioctl_fence_info(fence, arg);
+
 	default:
 		return -ENOTTY;
 	}
diff --git a/include/linux/sync.h b/include/linux/sync.h
index e1a20c4..6db0528 100644
--- a/include/linux/sync.h
+++ b/include/linux/sync.h
@@ -45,6 +45,10 @@  struct sync_fence;
  *			  should not print a newline
  * @print_pt:		print aditional debug information about sync_pt.
  *			  should not print a newline
+ * @fill_driver_data:	write implmentation specific driver data to data.
+ *			  should return an error if there is not enough room
+ *			  as specified by size.  This information is returned
+ *			  to userspace by SYNC_IOC_FENCE_INFO.
  */
 struct sync_timeline_ops {
 	const char *driver_name;
@@ -70,6 +74,9 @@  struct sync_timeline_ops {
 
 	/* optional */
 	void (*print_pt)(struct seq_file *s, struct sync_pt *sync_pt);
+
+	/* optional */
+	int (*fill_driver_data)(struct sync_pt *syncpt, void *data, int size);
 };
 
 /**
@@ -314,6 +321,42 @@  struct sync_merge_data {
 	__s32	fence; /* fd on newly created fence */
 };
 
+/**
+ * struct sync_pt_info - detailed sync_pt information
+ * @len:		length of sync_pt_info including any driver_data
+ * @obj_name:		name of parent sync_timeline
+ * @driver_name:	name of driver implmenting the parent
+ * @status:		status of the sync_pt 0:active 1:signaled <0:error
+ * @timestamp_ns:	timestamp of status change in nanoseconds
+ * @driver_data:	any driver dependant data
+ */
+struct sync_pt_info {
+	__u32	len;
+	char	obj_name[32];
+	char	driver_name[32];
+	__s32	status;
+	__u64	timestamp_ns;
+
+	__u8	driver_data[0];
+};
+
+/**
+ * struct sync_fence_info_data - data returned from fence info ioctl
+ * @len:	ioctl caller writes the size of the buffer its passing in.
+ *		ioctl returns length of sync_fence_data reutnred to userspace
+ *		including pt_info.
+ * @name:	name of fence
+ * @status:	status of fence. 1: signaled 0:active <0:error
+ * @pt_info:	a sync_pt_info struct for every sync_pt in the fence
+ */
+struct sync_fence_info_data {
+	__u32	len;
+	char	name[32];
+	__s32	status;
+
+	__u8	pt_info[0];
+};
+
 #define SYNC_IOC_MAGIC		'>'
 
 /**
@@ -332,4 +375,18 @@  struct sync_merge_data {
  */
 #define SYNC_IOC_MERGE		_IOWR(SYNC_IOC_MAGIC, 1, struct sync_merge_data)
 
+/**
+ * DOC: SYNC_IOC_FENCE_INFO - get detailed information on a fence
+ *
+ * Takes a struct sync_fence_info_data with extra space allocated for pt_info.
+ * Caller should write the size of the buffer into len.  On return, len is
+ * updated to reflect the total size of the sync_fence_info_data including
+ * pt_info.
+ *
+ * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
+ * To itterate over the sync_pt_infos, use the sync_pt_info.len field.
+ */
+#define SYNC_IOC_FENCE_INFO	_IOWR(SYNC_IOC_MAGIC, 2,\
+	struct sync_fence_info_data)
+
 #endif /* _LINUX_SYNC_H */