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