blob: 9b36dd85c1928bff23fa0249186505241f3f65b5 [file] [log] [blame]
Robert Foss95286be2016-12-07 15:07:34 -05001/*
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
Daniel Vetter00215dd2017-09-05 14:36:05 +020027#ifdef HAVE_LIBGEN_H
Robert Foss95286be2016-12-07 15:07:34 -050028#include <libgen.h>
29#endif
30#include <fcntl.h>
31#include <poll.h>
32#include <stdbool.h>
33#include <stdint.h>
Robert Foss95286be2016-12-07 15:07:34 -050034#include <sys/ioctl.h>
35
36#include "igt_debugfs.h"
Chris Wilsone7729912017-03-25 13:05:38 +000037#include "igt_kmod.h"
Robert Foss95286be2016-12-07 15:07:34 -050038#include "sw_sync.h"
39#include "drmtest.h"
40#include "ioctl_wrappers.h"
41
Paul Kocialkowski76bce772017-07-20 17:11:52 +030042/**
43 * SECTION:sw_sync
44 * @short_description: Software sync (fencing) support library
45 * @title: SW Sync
46 * @include: sw_sync.h
47 */
48
Chris Wilson63a2f5d2016-12-17 11:54:16 +000049struct int_sync_create_fence_data {
Robert Foss95286be2016-12-07 15:07:34 -050050 __u32 value;
51 char name[32];
52 __s32 fence;
53};
54
Chris Wilson63a2f5d2016-12-17 11:54:16 +000055#define INT_SYNC_IOC_MAGIC 'W'
56#define INT_SYNC_IOC_CREATE_FENCE _IOWR(INT_SYNC_IOC_MAGIC, 0, struct int_sync_create_fence_data)
57#define INT_SYNC_IOC_INC _IOW(INT_SYNC_IOC_MAGIC, 1, __u32)
Robert Foss95286be2016-12-07 15:07:34 -050058
Chris Wilson63a2f5d2016-12-17 11:54:16 +000059struct local_sync_merge_data {
60 char name[32];
61
62 __s32 fd2;
63 __s32 fence;
64
65 __u32 flags;
66 __u32 pad;
67};
68
69struct local_sync_fence_info {
70 char obj_name[32];
71 char driver_name[32];
72
73 __s32 status;
74 __u32 flags;
75
76 __u64 timestamp_ns;
77};
78
79struct local_sync_file_info {
80 char name[32];
81
82 __s32 status;
83 __u32 flags;
84 __u32 num_fences;
85 __u32 pad;
86
87 __u64 sync_fence_info;
88};
89
90#define UABI_SYNC_IOC_MAGIC '>'
91#define LOCAL_SYNC_IOC_MERGE _IOWR(UABI_SYNC_IOC_MAGIC, 3, struct local_sync_merge_data)
92#define LOCAL_SYNC_IOC_FILE_INFO _IOWR(UABI_SYNC_IOC_MAGIC, 4, struct local_sync_file_info)
Robert Foss95286be2016-12-07 15:07:34 -050093
94static bool kernel_sw_sync_path(char *path, int length)
95{
96 snprintf(path, length, "%s", "/dev/sw_sync");
Chris Wilson63a2f5d2016-12-17 11:54:16 +000097 if (access(path, R_OK | W_OK) == 0)
98 return true;
Robert Foss95286be2016-12-07 15:07:34 -050099
100 snprintf(path, length, "%s", "/sys/kernel/debug/sync/sw_sync");
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000101 if (access(path, R_OK | W_OK) == 0)
102 return true;
Robert Foss95286be2016-12-07 15:07:34 -0500103
104 snprintf(path, length, "%s/sw_sync", igt_debugfs_mount());
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000105 if (access(path, R_OK | W_OK) == 0)
106 return true;
Robert Foss95286be2016-12-07 15:07:34 -0500107
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000108 return false;
Robert Foss95286be2016-12-07 15:07:34 -0500109}
110
111static bool sw_sync_fd_is_valid(int fd)
112{
113 int status;
114
115 if (fd < 0)
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000116 return false;
Robert Foss95286be2016-12-07 15:07:34 -0500117
118 status = fcntl(fd, F_GETFD, 0);
119 return status >= 0;
120}
121
122int sw_sync_timeline_create(void)
123{
124 char buf[128];
125 int fd;
126
127 igt_assert_f(kernel_sw_sync_path(buf, sizeof(buf)),
128 "Unable to find valid path for sw_sync\n");
129
130 fd = open(buf, O_RDWR);
131 igt_assert_f(sw_sync_fd_is_valid(fd), "Created invalid timeline\n");
132
133 return fd;
134}
135
Chris Wilson03bc7392016-12-17 12:42:19 +0000136int __sw_sync_timeline_create_fence(int fd, uint32_t seqno)
Robert Foss95286be2016-12-07 15:07:34 -0500137{
Chris Wilson03bc7392016-12-17 12:42:19 +0000138 struct int_sync_create_fence_data data = { .value = seqno};
Robert Foss95286be2016-12-07 15:07:34 -0500139
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000140 if (igt_ioctl(fd, INT_SYNC_IOC_CREATE_FENCE, &data))
Robert Foss95286be2016-12-07 15:07:34 -0500141 return -errno;
142
143 return data.fence;
144}
145
Chris Wilson03bc7392016-12-17 12:42:19 +0000146int sw_sync_timeline_create_fence(int fd, uint32_t seqno)
Robert Foss95286be2016-12-07 15:07:34 -0500147{
Chris Wilson03bc7392016-12-17 12:42:19 +0000148 int fence = __sw_sync_timeline_create_fence(fd, seqno);
Robert Foss95286be2016-12-07 15:07:34 -0500149
150 igt_assert_f(sw_sync_fd_is_valid(fence), "Created invalid fence\n");
151
152 return fence;
153}
154
155void sw_sync_timeline_inc(int fd, uint32_t count)
156{
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000157 do_ioctl(fd, INT_SYNC_IOC_INC, &count);
Robert Foss95286be2016-12-07 15:07:34 -0500158}
159
Chris Wilson70f07002016-12-17 12:36:21 +0000160int sync_fence_merge(int fd1, int fd2)
Robert Foss95286be2016-12-07 15:07:34 -0500161{
Chris Wilson70f07002016-12-17 12:36:21 +0000162 struct local_sync_merge_data data = { .fd2 = fd2};
Robert Foss95286be2016-12-07 15:07:34 -0500163
Chris Wilson70f07002016-12-17 12:36:21 +0000164 if (ioctl(fd1, LOCAL_SYNC_IOC_MERGE, &data))
Robert Foss95286be2016-12-07 15:07:34 -0500165 return -errno;
166
167 return data.fence;
168}
169
Chris Wilson20fffe72016-12-17 12:27:14 +0000170int sync_fence_wait(int fd, int timeout)
Robert Foss95286be2016-12-07 15:07:34 -0500171{
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000172 struct pollfd fds = { fd, POLLIN };
Robert Foss95286be2016-12-07 15:07:34 -0500173 int ret;
174
Robert Foss95286be2016-12-07 15:07:34 -0500175 do {
Chris Wilson20fffe72016-12-17 12:27:14 +0000176 ret = poll(&fds, 1, timeout);
177 if (ret > 0) {
178 if (fds.revents & (POLLERR | POLLNVAL))
179 return -EINVAL;
Robert Foss95286be2016-12-07 15:07:34 -0500180
Chris Wilson20fffe72016-12-17 12:27:14 +0000181 return 0;
182 } else if (ret == 0) {
183 return -ETIME;
184 } else {
185 ret = -errno;
186 if (ret == -EINTR || ret == -EAGAIN)
187 continue;
188 return ret;
189 }
190 } while (1);
Robert Foss95286be2016-12-07 15:07:34 -0500191}
192
193int sync_fence_count(int fd)
194{
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000195 struct local_sync_file_info info = {};
Robert Foss95286be2016-12-07 15:07:34 -0500196
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000197 if (ioctl(fd, LOCAL_SYNC_IOC_FILE_INFO, &info))
Robert Foss95286be2016-12-07 15:07:34 -0500198 return -errno;
199
200 return info.num_fences;
201}
202
203static int __sync_fence_count_status(int fd, int status)
204{
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000205 struct local_sync_file_info info = {};
206 struct local_sync_fence_info *fence_info;
Robert Foss95286be2016-12-07 15:07:34 -0500207 int count;
208 int i;
209
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000210 if (ioctl(fd, LOCAL_SYNC_IOC_FILE_INFO, &info))
Robert Foss95286be2016-12-07 15:07:34 -0500211 return -errno;
212
213 fence_info = calloc(info.num_fences, sizeof(*fence_info));
214 if (!fence_info)
215 return -ENOMEM;
216
Chris Wilson39858a12017-01-02 11:05:21 +0000217 info.sync_fence_info = to_user_pointer(fence_info);
Chris Wilson63a2f5d2016-12-17 11:54:16 +0000218 if (ioctl(fd, LOCAL_SYNC_IOC_FILE_INFO, &info)) {
Robert Foss95286be2016-12-07 15:07:34 -0500219 count = -errno;
220 } else {
221 count = 0;
222 for (i = 0 ; i < info.num_fences ; i++)
223 if (fence_info[i].status == status)
224 count++;
225 }
226
227 free(fence_info);
228
229 return count;
230}
231
232int sync_fence_count_status(int fd, int status)
233{
234 int count = __sync_fence_count_status(fd, status);
235 igt_assert_f(count >= 0, "No fences with supplied status found\n");
236
237 return count;
238}
Robert Foss2c16b0b2016-12-07 15:07:50 -0500239
Chris Wilsona3f0d752017-01-03 14:57:25 +0000240int sync_fence_status(int fence)
241{
242 struct local_sync_fence_info fence_info;
243 struct local_sync_file_info file_info = {
244 .sync_fence_info = to_user_pointer(&fence_info),
245 .num_fences = 1,
246 };
247
248 if (ioctl(fence, LOCAL_SYNC_IOC_FILE_INFO, &file_info))
249 return -errno;
250
251 if (file_info.num_fences != 1)
252 return -EINVAL;
253
254 return fence_info.status;
255}
256
Chris Wilsone7729912017-03-25 13:05:38 +0000257static void modprobe(const char *driver)
258{
259 igt_kmod_load(driver, "");
260}
261
Robert Foss2c16b0b2016-12-07 15:07:50 -0500262static bool kernel_has_sw_sync(void)
263{
264 char buf[128];
265
Chris Wilsone7729912017-03-25 13:05:38 +0000266 modprobe("sw_sync");
Robert Foss2c16b0b2016-12-07 15:07:50 -0500267
268 return kernel_sw_sync_path(buf, sizeof(buf));
269}
270
271void igt_require_sw_sync(void)
272{
273 igt_require(kernel_has_sw_sync());
274}