blob: e68cc899ddc05bf3063f2146c2b9741ac7e39e77 [file] [log] [blame]
Erik Gilling196b3a52012-03-07 15:30:33 -08001/*
2 * sync.c
3 *
4 * Copyright 2012 Google, Inc
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#include <fcntl.h>
Elliott Hughesa744b052015-01-28 11:37:57 -080020#include <malloc.h>
Erik Gilling196b3a52012-03-07 15:30:33 -080021#include <stdint.h>
22#include <string.h>
Gustavo Padovan61ab0d72016-06-11 11:11:19 -030023#include <errno.h>
24#include <poll.h>
Erik Gilling196b3a52012-03-07 15:30:33 -080025
26#include <sys/ioctl.h>
27#include <sys/stat.h>
28#include <sys/types.h>
29
Christopher Ferrisf83c7922016-08-24 14:49:18 -070030#include <sync/sync.h>
31
Jesse Hallb7fdb2a2017-02-12 16:42:11 -080032/* Legacy Sync API */
33
34struct sync_legacy_merge_data {
35 int32_t fd2;
36 char name[32];
37 int32_t fence;
38};
39
40/**
41 * DOC: SYNC_IOC_MERGE - merge two fences
42 *
43 * Takes a struct sync_merge_data. Creates a new fence containing copies of
44 * the sync_pts in both the calling fd and sync_merge_data.fd2. Returns the
45 * new fence's fd in sync_merge_data.fence
46 *
47 * This is the legacy version of the Sync API before the de-stage that happened
48 * on Linux kernel 4.7.
49 */
50#define SYNC_IOC_LEGACY_MERGE _IOWR(SYNC_IOC_MAGIC, 1, \
51 struct sync_legacy_merge_data)
52
53/**
54 * DOC: SYNC_IOC_LEGACY_FENCE_INFO - get detailed information on a fence
55 *
56 * Takes a struct sync_fence_info_data with extra space allocated for pt_info.
57 * Caller should write the size of the buffer into len. On return, len is
58 * updated to reflect the total size of the sync_fence_info_data including
59 * pt_info.
60 *
61 * pt_info is a buffer containing sync_pt_infos for every sync_pt in the fence.
62 * To iterate over the sync_pt_infos, use the sync_pt_info.len field.
63 *
64 * This is the legacy version of the Sync API before the de-stage that happened
65 * on Linux kernel 4.7.
66 */
67#define SYNC_IOC_LEGACY_FENCE_INFO _IOWR(SYNC_IOC_MAGIC, 2,\
68 struct sync_fence_info_data)
69
70/* SW Sync API */
Christopher Ferrisf83c7922016-08-24 14:49:18 -070071
Christopher Ferris1514bb42016-12-12 17:32:55 -080072struct sw_sync_create_fence_data {
73 __u32 value;
74 char name[32];
75 __s32 fence;
76};
77
78#define SW_SYNC_IOC_MAGIC 'W'
79#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0, struct sw_sync_create_fence_data)
80#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
81
Erik Gilling984d3572012-08-21 18:21:18 -070082int sync_wait(int fd, int timeout)
Erik Gilling196b3a52012-03-07 15:30:33 -080083{
Gustavo Padovan61ab0d72016-06-11 11:11:19 -030084 struct pollfd fds;
85 int ret;
Erik Gilling196b3a52012-03-07 15:30:33 -080086
Gustavo Padovan61ab0d72016-06-11 11:11:19 -030087 if (fd < 0) {
88 errno = EINVAL;
89 return -1;
90 }
91
92 fds.fd = fd;
93 fds.events = POLLIN;
94
95 do {
96 ret = poll(&fds, 1, timeout);
97 if (ret > 0) {
98 if (fds.revents & (POLLERR | POLLNVAL)) {
99 errno = EINVAL;
100 return -1;
101 }
102 return 0;
103 } else if (ret == 0) {
104 errno = ETIME;
105 return -1;
106 }
107 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
108
109 return ret;
Erik Gilling196b3a52012-03-07 15:30:33 -0800110}
111
112int sync_merge(const char *name, int fd1, int fd2)
113{
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300114 struct sync_legacy_merge_data legacy_data;
115 struct sync_merge_data data;
116 int ret;
Erik Gilling196b3a52012-03-07 15:30:33 -0800117
118 data.fd2 = fd2;
119 strlcpy(data.name, name, sizeof(data.name));
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300120 data.flags = 0;
121 data.pad = 0;
Erik Gilling196b3a52012-03-07 15:30:33 -0800122
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300123 ret = ioctl(fd1, SYNC_IOC_MERGE, &data);
124 if (ret < 0 && errno == ENOTTY) {
125 legacy_data.fd2 = fd2;
126 strlcpy(legacy_data.name, name, sizeof(legacy_data.name));
127
128 ret = ioctl(fd1, SYNC_IOC_LEGACY_MERGE, &legacy_data);
129 if (ret < 0)
130 return ret;
131
132 return legacy_data.fence;
133 } else if (ret < 0) {
134 return ret;
135 }
Erik Gilling196b3a52012-03-07 15:30:33 -0800136
137 return data.fence;
138}
139
Jesse Hall89530822017-02-12 16:17:22 -0800140static struct sync_fence_info_data *legacy_sync_fence_info(int fd)
Erik Gilling196b3a52012-03-07 15:30:33 -0800141{
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300142 struct sync_fence_info_data *legacy_info;
143 struct sync_pt_info *legacy_pt_info;
Jesse Hall89530822017-02-12 16:17:22 -0800144 int err;
Erik Gilling196b3a52012-03-07 15:30:33 -0800145
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300146 legacy_info = malloc(4096);
147 if (legacy_info == NULL)
Erik Gilling196b3a52012-03-07 15:30:33 -0800148 return NULL;
149
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300150 legacy_info->len = 4096;
151 err = ioctl(fd, SYNC_IOC_LEGACY_FENCE_INFO, legacy_info);
Jesse Hall89530822017-02-12 16:17:22 -0800152 if (err < 0) {
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300153 free(legacy_info);
Erik Gilling196b3a52012-03-07 15:30:33 -0800154 return NULL;
155 }
Jesse Hall89530822017-02-12 16:17:22 -0800156 return legacy_info;
157}
Erik Gilling196b3a52012-03-07 15:30:33 -0800158
Jesse Hall89530822017-02-12 16:17:22 -0800159static struct sync_file_info *modern_sync_file_info(int fd)
160{
161 struct sync_file_info local_info;
162 struct sync_file_info *info;
163 int err;
164
165 memset(&local_info, 0, sizeof(local_info));
166 err = ioctl(fd, SYNC_IOC_FILE_INFO, &local_info);
167 if (err < 0)
168 return NULL;
169
170 info = calloc(1, sizeof(struct sync_file_info) +
171 local_info.num_fences * sizeof(struct sync_fence_info));
172 if (!info)
173 return NULL;
174 info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300175
176 err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
Jesse Hall89530822017-02-12 16:17:22 -0800177 if (err < 0) {
178 free(info);
179 return NULL;
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300180 }
181
Jesse Hall89530822017-02-12 16:17:22 -0800182 return info;
183}
184
185static struct sync_fence_info_data *sync_file_info_to_legacy_fence_info(
186 const struct sync_file_info *info)
187{
188 struct sync_fence_info_data *legacy_info;
189 struct sync_pt_info *legacy_pt_info;
190 const struct sync_fence_info *fence_info = sync_get_fence_info(info);
191 const uint32_t num_fences = info->num_fences;
192
193 legacy_info = malloc(4096);
194 if (legacy_info == NULL)
195 return NULL;
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300196 legacy_info->len = sizeof(*legacy_info) +
Jesse Hall077ffd52017-02-12 16:01:36 -0800197 num_fences * sizeof(struct sync_pt_info);
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300198 strlcpy(legacy_info->name, info->name, sizeof(legacy_info->name));
199 legacy_info->status = info->status;
200
201 legacy_pt_info = (struct sync_pt_info *)legacy_info->pt_info;
Jesse Hall89530822017-02-12 16:17:22 -0800202 for (uint32_t i = 0; i < num_fences; i++) {
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300203 legacy_pt_info[i].len = sizeof(*legacy_pt_info);
204 strlcpy(legacy_pt_info[i].obj_name, fence_info[i].obj_name,
205 sizeof(legacy_pt_info->obj_name));
206 strlcpy(legacy_pt_info[i].driver_name, fence_info[i].driver_name,
207 sizeof(legacy_pt_info->driver_name));
208 legacy_pt_info[i].status = fence_info[i].status;
209 legacy_pt_info[i].timestamp_ns = fence_info[i].timestamp_ns;
210 }
211
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300212 return legacy_info;
Jesse Hall89530822017-02-12 16:17:22 -0800213}
Gustavo Padovan61ab0d72016-06-11 11:11:19 -0300214
Jesse Hall83666162017-02-12 16:32:39 -0800215static struct sync_file_info* legacy_fence_info_to_sync_file_info(
216 struct sync_fence_info_data *legacy_info)
217{
218 struct sync_file_info *info;
219 struct sync_pt_info *pt;
220 struct sync_fence_info *fence;
221 size_t num_fences;
222 int err;
223
224 pt = NULL;
225 num_fences = 0;
226 while ((pt = sync_pt_info(legacy_info, pt)) != NULL)
227 num_fences++;
228
229 info = calloc(1, sizeof(struct sync_file_info) +
230 num_fences * sizeof(struct sync_fence_info));
231 if (!info) {
232 free(legacy_info);
233 return NULL;
234 }
235 info->sync_fence_info = (__u64)(uintptr_t)(info + 1);
236
237 strlcpy(info->name, legacy_info->name, sizeof(info->name));
238 info->status = legacy_info->status;
239 info->num_fences = num_fences;
240
241 pt = NULL;
242 fence = sync_get_fence_info(info);
243 while ((pt = sync_pt_info(legacy_info, pt)) != NULL) {
244 strlcpy(fence->obj_name, pt->obj_name, sizeof(fence->obj_name));
245 strlcpy(fence->driver_name, pt->driver_name,
246 sizeof(fence->driver_name));
247 fence->status = pt->status;
248 fence->timestamp_ns = pt->timestamp_ns;
249 fence++;
250 }
251
252 return info;
253}
254
Jesse Hall89530822017-02-12 16:17:22 -0800255struct sync_fence_info_data *sync_fence_info(int fd)
256{
257 struct sync_fence_info_data *legacy_info;
258
259 legacy_info = legacy_sync_fence_info(fd);
260 if (legacy_info || errno != ENOTTY)
261 return legacy_info;
262
263 struct sync_file_info* file_info;
264 file_info = modern_sync_file_info(fd);
265 if (!file_info)
266 return NULL;
267 legacy_info = sync_file_info_to_legacy_fence_info(file_info);
268 sync_file_info_free(file_info);
269 return legacy_info;
Erik Gilling196b3a52012-03-07 15:30:33 -0800270}
271
Jesse Hall83666162017-02-12 16:32:39 -0800272struct sync_file_info* sync_file_info(int32_t fd)
273{
274 struct sync_file_info *info;
275 struct sync_fence_info_data *legacy_info;
276
277 info = modern_sync_file_info(fd);
278 if (info || errno != ENOTTY)
279 return info;
280
281 legacy_info = legacy_sync_fence_info(fd);
282 if (!legacy_info)
283 return NULL;
284 info = legacy_fence_info_to_sync_file_info(legacy_info);
285 sync_fence_info_free(legacy_info);
286 return info;
287}
288
Erik Gilling196b3a52012-03-07 15:30:33 -0800289struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info,
290 struct sync_pt_info *itr)
291{
292 if (itr == NULL)
293 itr = (struct sync_pt_info *) info->pt_info;
294 else
295 itr = (struct sync_pt_info *) ((__u8 *)itr + itr->len);
296
297 if ((__u8 *)itr - (__u8 *)info >= (int)info->len)
298 return NULL;
299
300 return itr;
301}
302
303void sync_fence_info_free(struct sync_fence_info_data *info)
304{
305 free(info);
306}
307
Jesse Hall89530822017-02-12 16:17:22 -0800308void sync_file_info_free(struct sync_file_info *info)
309{
310 free(info);
311}
312
Erik Gilling196b3a52012-03-07 15:30:33 -0800313
314int sw_sync_timeline_create(void)
315{
Gustavo Padovanffc687b2016-06-10 16:51:29 -0300316 int ret;
317
318 ret = open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
319 if (ret < 0)
320 ret = open("/dev/sw_sync", O_RDWR);
321
322 return ret;
Erik Gilling196b3a52012-03-07 15:30:33 -0800323}
324
325int sw_sync_timeline_inc(int fd, unsigned count)
326{
327 __u32 arg = count;
328
329 return ioctl(fd, SW_SYNC_IOC_INC, &arg);
330}
331
332int sw_sync_fence_create(int fd, const char *name, unsigned value)
333{
334 struct sw_sync_create_fence_data data;
335 int err;
336
337 data.value = value;
338 strlcpy(data.name, name, sizeof(data.name));
339
340 err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
341 if (err < 0)
342 return err;
343
344 return data.fence;
345}