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