1 /*
2  * Copyright © 2016 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  * Authors:
24  *    Robert Foss <robert.foss@collabora.com>
25  */
26 
27 #ifdef HAVE_LIBGEN_H
28 #include <libgen.h>
29 #endif
30 #include <fcntl.h>
31 #include <poll.h>
32 #include <stdbool.h>
33 #include <stdint.h>
34 #include <sys/ioctl.h>
35 
36 #include <linux/sync_file.h>
37 
38 #include "igt_debugfs.h"
39 #include "igt_kmod.h"
40 #include "sw_sync.h"
41 #include "drmtest.h"
42 #include "ioctl_wrappers.h"
43 
44 /**
45  * SECTION:sw_sync
46  * @short_description: Software sync (fencing) support library
47  * @title: SW Sync
48  * @include: sw_sync.h
49  */
50 
51 struct int_sync_create_fence_data {
52 	__u32	value;
53 	char	name[32];
54 	__s32	fence;
55 };
56 
57 #define INT_SYNC_IOC_MAGIC 'W'
58 #define INT_SYNC_IOC_CREATE_FENCE	_IOWR(INT_SYNC_IOC_MAGIC, 0, struct int_sync_create_fence_data)
59 #define INT_SYNC_IOC_INC		_IOW(INT_SYNC_IOC_MAGIC, 1, __u32)
60 
kernel_sw_sync_path(char * path,int length)61 static bool kernel_sw_sync_path(char *path, int length)
62 {
63 	snprintf(path, length, "%s", "/dev/sw_sync");
64 	if (access(path, R_OK | W_OK) == 0)
65 		return true;
66 
67 	snprintf(path, length, "%s", "/sys/kernel/debug/sync/sw_sync");
68 	if (access(path, R_OK | W_OK) == 0)
69 		return true;
70 
71 	snprintf(path, length, "%s/sw_sync", igt_debugfs_mount());
72 	if (access(path, R_OK | W_OK) == 0)
73 		return true;
74 
75 	return false;
76 }
77 
sw_sync_fd_is_valid(int fd)78 static bool sw_sync_fd_is_valid(int fd)
79 {
80 	int status;
81 
82 	if (fd < 0)
83 		return false;
84 
85 	status = fcntl(fd, F_GETFD, 0);
86 	return status >= 0;
87 }
88 
sw_sync_timeline_create(void)89 int sw_sync_timeline_create(void)
90 {
91 	char buf[128];
92 	int fd;
93 
94 	igt_assert_f(kernel_sw_sync_path(buf, sizeof(buf)),
95 	    "Unable to find valid path for sw_sync\n");
96 
97 	fd = open(buf, O_RDWR);
98 	igt_assert_f(sw_sync_fd_is_valid(fd), "Created invalid timeline\n");
99 
100 	return fd;
101 }
102 
__sw_sync_timeline_create_fence(int fd,uint32_t seqno)103 int __sw_sync_timeline_create_fence(int fd, uint32_t seqno)
104 {
105 	struct int_sync_create_fence_data data = { .value = seqno};
106 
107 	if (igt_ioctl(fd, INT_SYNC_IOC_CREATE_FENCE, &data))
108 		return -errno;
109 
110 	return data.fence;
111 }
112 
sw_sync_timeline_create_fence(int fd,uint32_t seqno)113 int sw_sync_timeline_create_fence(int fd, uint32_t seqno)
114 {
115 	int fence = __sw_sync_timeline_create_fence(fd, seqno);
116 
117 	igt_assert_f(sw_sync_fd_is_valid(fence), "Created invalid fence\n");
118 
119 	return fence;
120 }
121 
sw_sync_timeline_inc(int fd,uint32_t count)122 void sw_sync_timeline_inc(int fd, uint32_t count)
123 {
124 	do_ioctl(fd, INT_SYNC_IOC_INC, &count);
125 }
126 
sync_fence_merge(int fd1,int fd2)127 int sync_fence_merge(int fd1, int fd2)
128 {
129 	struct sync_merge_data data = { .fd2 = fd2};
130 
131 	if (ioctl(fd1, SYNC_IOC_MERGE, &data))
132 		return -errno;
133 
134 	return data.fence;
135 }
136 
sync_fence_wait(int fd,int timeout)137 int sync_fence_wait(int fd, int timeout)
138 {
139 	struct pollfd fds = { fd, POLLIN };
140 	int ret;
141 
142 	do {
143 		ret = poll(&fds, 1, timeout);
144 		if (ret > 0) {
145 			if (fds.revents & (POLLERR | POLLNVAL))
146 				return -EINVAL;
147 
148 			return 0;
149 		} else if (ret == 0) {
150 			return -ETIME;
151 		} else  {
152 			ret = -errno;
153 			if (ret == -EINTR || ret == -EAGAIN)
154 				continue;
155 			return ret;
156 		}
157 	} while (1);
158 }
159 
sync_fence_count(int fd)160 int sync_fence_count(int fd)
161 {
162 	struct sync_file_info info = {};
163 
164 	if (ioctl(fd, SYNC_IOC_FILE_INFO, &info))
165 		return -errno;
166 
167 	return info.num_fences;
168 }
169 
__sync_fence_count_status(int fd,int status)170 static int __sync_fence_count_status(int fd, int status)
171 {
172 	struct sync_file_info info = {};
173 	struct sync_fence_info *fence_info;
174 	int count;
175 	int i;
176 
177 	if (ioctl(fd, SYNC_IOC_FILE_INFO, &info))
178 		return -errno;
179 
180 	fence_info = calloc(info.num_fences, sizeof(*fence_info));
181 	if (!fence_info)
182 		return -ENOMEM;
183 
184 	info.sync_fence_info = to_user_pointer(fence_info);
185 	if (ioctl(fd, SYNC_IOC_FILE_INFO, &info)) {
186 		count = -errno;
187 	} else {
188 		count = 0;
189 		for (i = 0 ; i < info.num_fences ; i++)
190 			if (fence_info[i].status == status)
191 				count++;
192 	}
193 
194 	free(fence_info);
195 
196 	return count;
197 }
198 
sync_fence_count_status(int fd,int status)199 int sync_fence_count_status(int fd, int status)
200 {
201 	int count = __sync_fence_count_status(fd, status);
202 	igt_assert_f(count >= 0, "No fences with supplied status found\n");
203 
204 	return count;
205 }
206 
sync_fence_status(int fence)207 int sync_fence_status(int fence)
208 {
209 	struct sync_file_info info = { };
210 
211 	if (ioctl(fence, SYNC_IOC_FILE_INFO, &info))
212 		return -errno;
213 
214 	return info.status;
215 }
216 
modprobe(const char * driver)217 static void modprobe(const char *driver)
218 {
219 	igt_kmod_load(driver, NULL);
220 }
221 
kernel_has_sw_sync(void)222 static bool kernel_has_sw_sync(void)
223 {
224 	char buf[128];
225 
226 	modprobe("sw_sync");
227 
228 	return kernel_sw_sync_path(buf, sizeof(buf));
229 }
230 
igt_require_sw_sync(void)231 void igt_require_sw_sync(void)
232 {
233 	igt_require(kernel_has_sw_sync());
234 }
235