1*053f45beSAndroid Build Coastguard Worker /*
2*053f45beSAndroid Build Coastguard Worker * sync / sw_sync abstraction
3*053f45beSAndroid Build Coastguard Worker * Copyright 2015-2016 Collabora Ltd.
4*053f45beSAndroid Build Coastguard Worker *
5*053f45beSAndroid Build Coastguard Worker * Based on the implementation from the Android Open Source Project,
6*053f45beSAndroid Build Coastguard Worker *
7*053f45beSAndroid Build Coastguard Worker * Copyright 2012 Google, Inc
8*053f45beSAndroid Build Coastguard Worker *
9*053f45beSAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
10*053f45beSAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
11*053f45beSAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
12*053f45beSAndroid Build Coastguard Worker * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13*053f45beSAndroid Build Coastguard Worker * and/or sell copies of the Software, and to permit persons to whom the
14*053f45beSAndroid Build Coastguard Worker * Software is furnished to do so, subject to the following conditions:
15*053f45beSAndroid Build Coastguard Worker *
16*053f45beSAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be included in
17*053f45beSAndroid Build Coastguard Worker * all copies or substantial portions of the Software.
18*053f45beSAndroid Build Coastguard Worker *
19*053f45beSAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20*053f45beSAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21*053f45beSAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22*053f45beSAndroid Build Coastguard Worker * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23*053f45beSAndroid Build Coastguard Worker * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24*053f45beSAndroid Build Coastguard Worker * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25*053f45beSAndroid Build Coastguard Worker * OTHER DEALINGS IN THE SOFTWARE.
26*053f45beSAndroid Build Coastguard Worker */
27*053f45beSAndroid Build Coastguard Worker
28*053f45beSAndroid Build Coastguard Worker #include <fcntl.h>
29*053f45beSAndroid Build Coastguard Worker #include <malloc.h>
30*053f45beSAndroid Build Coastguard Worker #include <poll.h>
31*053f45beSAndroid Build Coastguard Worker #include <stdint.h>
32*053f45beSAndroid Build Coastguard Worker #include <string.h>
33*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
34*053f45beSAndroid Build Coastguard Worker
35*053f45beSAndroid Build Coastguard Worker #include <sys/ioctl.h>
36*053f45beSAndroid Build Coastguard Worker #include <sys/stat.h>
37*053f45beSAndroid Build Coastguard Worker #include <sys/types.h>
38*053f45beSAndroid Build Coastguard Worker
39*053f45beSAndroid Build Coastguard Worker #include "sync.h"
40*053f45beSAndroid Build Coastguard Worker #include "sw_sync.h"
41*053f45beSAndroid Build Coastguard Worker
42*053f45beSAndroid Build Coastguard Worker #include <linux/sync_file.h>
43*053f45beSAndroid Build Coastguard Worker
44*053f45beSAndroid Build Coastguard Worker
45*053f45beSAndroid Build Coastguard Worker /* SW_SYNC ioctls */
46*053f45beSAndroid Build Coastguard Worker struct sw_sync_create_fence_data {
47*053f45beSAndroid Build Coastguard Worker __u32 value;
48*053f45beSAndroid Build Coastguard Worker char name[32];
49*053f45beSAndroid Build Coastguard Worker __s32 fence;
50*053f45beSAndroid Build Coastguard Worker };
51*053f45beSAndroid Build Coastguard Worker
52*053f45beSAndroid Build Coastguard Worker #define SW_SYNC_IOC_MAGIC 'W'
53*053f45beSAndroid Build Coastguard Worker #define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
54*053f45beSAndroid Build Coastguard Worker struct sw_sync_create_fence_data)
55*053f45beSAndroid Build Coastguard Worker #define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
56*053f45beSAndroid Build Coastguard Worker
57*053f45beSAndroid Build Coastguard Worker
sync_wait(int fd,int timeout)58*053f45beSAndroid Build Coastguard Worker int sync_wait(int fd, int timeout)
59*053f45beSAndroid Build Coastguard Worker {
60*053f45beSAndroid Build Coastguard Worker struct pollfd fds;
61*053f45beSAndroid Build Coastguard Worker
62*053f45beSAndroid Build Coastguard Worker fds.fd = fd;
63*053f45beSAndroid Build Coastguard Worker fds.events = POLLIN | POLLERR;
64*053f45beSAndroid Build Coastguard Worker
65*053f45beSAndroid Build Coastguard Worker return poll(&fds, 1, timeout);
66*053f45beSAndroid Build Coastguard Worker }
67*053f45beSAndroid Build Coastguard Worker
sync_merge(const char * name,int fd1,int fd2)68*053f45beSAndroid Build Coastguard Worker int sync_merge(const char *name, int fd1, int fd2)
69*053f45beSAndroid Build Coastguard Worker {
70*053f45beSAndroid Build Coastguard Worker struct sync_merge_data data = {};
71*053f45beSAndroid Build Coastguard Worker int err;
72*053f45beSAndroid Build Coastguard Worker
73*053f45beSAndroid Build Coastguard Worker data.fd2 = fd2;
74*053f45beSAndroid Build Coastguard Worker strncpy(data.name, name, sizeof(data.name) - 1);
75*053f45beSAndroid Build Coastguard Worker data.name[sizeof(data.name) - 1] = '\0';
76*053f45beSAndroid Build Coastguard Worker
77*053f45beSAndroid Build Coastguard Worker err = ioctl(fd1, SYNC_IOC_MERGE, &data);
78*053f45beSAndroid Build Coastguard Worker if (err < 0)
79*053f45beSAndroid Build Coastguard Worker return err;
80*053f45beSAndroid Build Coastguard Worker
81*053f45beSAndroid Build Coastguard Worker return data.fence;
82*053f45beSAndroid Build Coastguard Worker }
83*053f45beSAndroid Build Coastguard Worker
sync_file_info(int fd)84*053f45beSAndroid Build Coastguard Worker static struct sync_file_info *sync_file_info(int fd)
85*053f45beSAndroid Build Coastguard Worker {
86*053f45beSAndroid Build Coastguard Worker struct sync_file_info *info;
87*053f45beSAndroid Build Coastguard Worker struct sync_fence_info *fence_info;
88*053f45beSAndroid Build Coastguard Worker int err, num_fences;
89*053f45beSAndroid Build Coastguard Worker
90*053f45beSAndroid Build Coastguard Worker info = calloc(1, sizeof(*info));
91*053f45beSAndroid Build Coastguard Worker if (info == NULL)
92*053f45beSAndroid Build Coastguard Worker return NULL;
93*053f45beSAndroid Build Coastguard Worker
94*053f45beSAndroid Build Coastguard Worker err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
95*053f45beSAndroid Build Coastguard Worker if (err < 0) {
96*053f45beSAndroid Build Coastguard Worker free(info);
97*053f45beSAndroid Build Coastguard Worker return NULL;
98*053f45beSAndroid Build Coastguard Worker }
99*053f45beSAndroid Build Coastguard Worker
100*053f45beSAndroid Build Coastguard Worker num_fences = info->num_fences;
101*053f45beSAndroid Build Coastguard Worker
102*053f45beSAndroid Build Coastguard Worker if (num_fences) {
103*053f45beSAndroid Build Coastguard Worker info->flags = 0;
104*053f45beSAndroid Build Coastguard Worker info->num_fences = num_fences;
105*053f45beSAndroid Build Coastguard Worker
106*053f45beSAndroid Build Coastguard Worker fence_info = calloc(num_fences, sizeof(*fence_info));
107*053f45beSAndroid Build Coastguard Worker if (!fence_info) {
108*053f45beSAndroid Build Coastguard Worker free(info);
109*053f45beSAndroid Build Coastguard Worker return NULL;
110*053f45beSAndroid Build Coastguard Worker }
111*053f45beSAndroid Build Coastguard Worker
112*053f45beSAndroid Build Coastguard Worker info->sync_fence_info = (uint64_t)(unsigned long)fence_info;
113*053f45beSAndroid Build Coastguard Worker
114*053f45beSAndroid Build Coastguard Worker err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
115*053f45beSAndroid Build Coastguard Worker if (err < 0) {
116*053f45beSAndroid Build Coastguard Worker free(fence_info);
117*053f45beSAndroid Build Coastguard Worker free(info);
118*053f45beSAndroid Build Coastguard Worker return NULL;
119*053f45beSAndroid Build Coastguard Worker }
120*053f45beSAndroid Build Coastguard Worker }
121*053f45beSAndroid Build Coastguard Worker
122*053f45beSAndroid Build Coastguard Worker return info;
123*053f45beSAndroid Build Coastguard Worker }
124*053f45beSAndroid Build Coastguard Worker
sync_file_info_free(struct sync_file_info * info)125*053f45beSAndroid Build Coastguard Worker static void sync_file_info_free(struct sync_file_info *info)
126*053f45beSAndroid Build Coastguard Worker {
127*053f45beSAndroid Build Coastguard Worker free((void *)(unsigned long)info->sync_fence_info);
128*053f45beSAndroid Build Coastguard Worker free(info);
129*053f45beSAndroid Build Coastguard Worker }
130*053f45beSAndroid Build Coastguard Worker
sync_fence_size(int fd)131*053f45beSAndroid Build Coastguard Worker int sync_fence_size(int fd)
132*053f45beSAndroid Build Coastguard Worker {
133*053f45beSAndroid Build Coastguard Worker int count;
134*053f45beSAndroid Build Coastguard Worker struct sync_file_info *info = sync_file_info(fd);
135*053f45beSAndroid Build Coastguard Worker
136*053f45beSAndroid Build Coastguard Worker if (!info)
137*053f45beSAndroid Build Coastguard Worker return 0;
138*053f45beSAndroid Build Coastguard Worker
139*053f45beSAndroid Build Coastguard Worker count = info->num_fences;
140*053f45beSAndroid Build Coastguard Worker
141*053f45beSAndroid Build Coastguard Worker sync_file_info_free(info);
142*053f45beSAndroid Build Coastguard Worker
143*053f45beSAndroid Build Coastguard Worker return count;
144*053f45beSAndroid Build Coastguard Worker }
145*053f45beSAndroid Build Coastguard Worker
sync_fence_count_with_status(int fd,int status)146*053f45beSAndroid Build Coastguard Worker int sync_fence_count_with_status(int fd, int status)
147*053f45beSAndroid Build Coastguard Worker {
148*053f45beSAndroid Build Coastguard Worker unsigned int i, count = 0;
149*053f45beSAndroid Build Coastguard Worker struct sync_fence_info *fence_info = NULL;
150*053f45beSAndroid Build Coastguard Worker struct sync_file_info *info = sync_file_info(fd);
151*053f45beSAndroid Build Coastguard Worker
152*053f45beSAndroid Build Coastguard Worker if (!info)
153*053f45beSAndroid Build Coastguard Worker return -1;
154*053f45beSAndroid Build Coastguard Worker
155*053f45beSAndroid Build Coastguard Worker fence_info = (struct sync_fence_info *)(unsigned long)info->sync_fence_info;
156*053f45beSAndroid Build Coastguard Worker for (i = 0 ; i < info->num_fences ; i++) {
157*053f45beSAndroid Build Coastguard Worker if (fence_info[i].status == status)
158*053f45beSAndroid Build Coastguard Worker count++;
159*053f45beSAndroid Build Coastguard Worker }
160*053f45beSAndroid Build Coastguard Worker
161*053f45beSAndroid Build Coastguard Worker sync_file_info_free(info);
162*053f45beSAndroid Build Coastguard Worker
163*053f45beSAndroid Build Coastguard Worker return count;
164*053f45beSAndroid Build Coastguard Worker }
165*053f45beSAndroid Build Coastguard Worker
sw_sync_timeline_create(void)166*053f45beSAndroid Build Coastguard Worker int sw_sync_timeline_create(void)
167*053f45beSAndroid Build Coastguard Worker {
168*053f45beSAndroid Build Coastguard Worker return open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
169*053f45beSAndroid Build Coastguard Worker }
170*053f45beSAndroid Build Coastguard Worker
sw_sync_timeline_inc(int fd,unsigned int count)171*053f45beSAndroid Build Coastguard Worker int sw_sync_timeline_inc(int fd, unsigned int count)
172*053f45beSAndroid Build Coastguard Worker {
173*053f45beSAndroid Build Coastguard Worker __u32 arg = count;
174*053f45beSAndroid Build Coastguard Worker
175*053f45beSAndroid Build Coastguard Worker return ioctl(fd, SW_SYNC_IOC_INC, &arg);
176*053f45beSAndroid Build Coastguard Worker }
177*053f45beSAndroid Build Coastguard Worker
sw_sync_timeline_is_valid(int fd)178*053f45beSAndroid Build Coastguard Worker int sw_sync_timeline_is_valid(int fd)
179*053f45beSAndroid Build Coastguard Worker {
180*053f45beSAndroid Build Coastguard Worker int status;
181*053f45beSAndroid Build Coastguard Worker
182*053f45beSAndroid Build Coastguard Worker if (fd == -1)
183*053f45beSAndroid Build Coastguard Worker return 0;
184*053f45beSAndroid Build Coastguard Worker
185*053f45beSAndroid Build Coastguard Worker status = fcntl(fd, F_GETFD, 0);
186*053f45beSAndroid Build Coastguard Worker return (status >= 0);
187*053f45beSAndroid Build Coastguard Worker }
188*053f45beSAndroid Build Coastguard Worker
sw_sync_timeline_destroy(int fd)189*053f45beSAndroid Build Coastguard Worker void sw_sync_timeline_destroy(int fd)
190*053f45beSAndroid Build Coastguard Worker {
191*053f45beSAndroid Build Coastguard Worker if (sw_sync_timeline_is_valid(fd))
192*053f45beSAndroid Build Coastguard Worker close(fd);
193*053f45beSAndroid Build Coastguard Worker }
194*053f45beSAndroid Build Coastguard Worker
sw_sync_fence_create(int fd,const char * name,unsigned int value)195*053f45beSAndroid Build Coastguard Worker int sw_sync_fence_create(int fd, const char *name, unsigned int value)
196*053f45beSAndroid Build Coastguard Worker {
197*053f45beSAndroid Build Coastguard Worker struct sw_sync_create_fence_data data = {};
198*053f45beSAndroid Build Coastguard Worker int err;
199*053f45beSAndroid Build Coastguard Worker
200*053f45beSAndroid Build Coastguard Worker data.value = value;
201*053f45beSAndroid Build Coastguard Worker strncpy(data.name, name, sizeof(data.name) - 1);
202*053f45beSAndroid Build Coastguard Worker data.name[sizeof(data.name) - 1] = '\0';
203*053f45beSAndroid Build Coastguard Worker
204*053f45beSAndroid Build Coastguard Worker err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
205*053f45beSAndroid Build Coastguard Worker if (err < 0)
206*053f45beSAndroid Build Coastguard Worker return err;
207*053f45beSAndroid Build Coastguard Worker
208*053f45beSAndroid Build Coastguard Worker return data.fence;
209*053f45beSAndroid Build Coastguard Worker }
210*053f45beSAndroid Build Coastguard Worker
sw_sync_fence_is_valid(int fd)211*053f45beSAndroid Build Coastguard Worker int sw_sync_fence_is_valid(int fd)
212*053f45beSAndroid Build Coastguard Worker {
213*053f45beSAndroid Build Coastguard Worker /* Same code! */
214*053f45beSAndroid Build Coastguard Worker return sw_sync_timeline_is_valid(fd);
215*053f45beSAndroid Build Coastguard Worker }
216*053f45beSAndroid Build Coastguard Worker
sw_sync_fence_destroy(int fd)217*053f45beSAndroid Build Coastguard Worker void sw_sync_fence_destroy(int fd)
218*053f45beSAndroid Build Coastguard Worker {
219*053f45beSAndroid Build Coastguard Worker if (sw_sync_fence_is_valid(fd))
220*053f45beSAndroid Build Coastguard Worker close(fd);
221*053f45beSAndroid Build Coastguard Worker }
222