18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *  sync / sw_sync abstraction
38c2ecf20Sopenharmony_ci *  Copyright 2015-2016 Collabora Ltd.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Based on the implementation from the Android Open Source Project,
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Copyright 2012 Google, Inc
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *  Permission is hereby granted, free of charge, to any person obtaining a
108c2ecf20Sopenharmony_ci *  copy of this software and associated documentation files (the "Software"),
118c2ecf20Sopenharmony_ci *  to deal in the Software without restriction, including without limitation
128c2ecf20Sopenharmony_ci *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
138c2ecf20Sopenharmony_ci *  and/or sell copies of the Software, and to permit persons to whom the
148c2ecf20Sopenharmony_ci *  Software is furnished to do so, subject to the following conditions:
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci *  The above copyright notice and this permission notice shall be included in
178c2ecf20Sopenharmony_ci *  all copies or substantial portions of the Software.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
208c2ecf20Sopenharmony_ci *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
218c2ecf20Sopenharmony_ci *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
228c2ecf20Sopenharmony_ci *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
238c2ecf20Sopenharmony_ci *  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
248c2ecf20Sopenharmony_ci *  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
258c2ecf20Sopenharmony_ci *  OTHER DEALINGS IN THE SOFTWARE.
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include <fcntl.h>
298c2ecf20Sopenharmony_ci#include <malloc.h>
308c2ecf20Sopenharmony_ci#include <poll.h>
318c2ecf20Sopenharmony_ci#include <stdint.h>
328c2ecf20Sopenharmony_ci#include <string.h>
338c2ecf20Sopenharmony_ci#include <unistd.h>
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <sys/ioctl.h>
368c2ecf20Sopenharmony_ci#include <sys/stat.h>
378c2ecf20Sopenharmony_ci#include <sys/types.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#include "sync.h"
408c2ecf20Sopenharmony_ci#include "sw_sync.h"
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include <linux/sync_file.h>
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* SW_SYNC ioctls */
468c2ecf20Sopenharmony_cistruct sw_sync_create_fence_data {
478c2ecf20Sopenharmony_ci	__u32	value;
488c2ecf20Sopenharmony_ci	char	name[32];
498c2ecf20Sopenharmony_ci	__s32	fence;
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define SW_SYNC_IOC_MAGIC		'W'
538c2ecf20Sopenharmony_ci#define SW_SYNC_IOC_CREATE_FENCE	_IOWR(SW_SYNC_IOC_MAGIC, 0,\
548c2ecf20Sopenharmony_ci					      struct sw_sync_create_fence_data)
558c2ecf20Sopenharmony_ci#define SW_SYNC_IOC_INC			_IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ciint sync_wait(int fd, int timeout)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	struct pollfd fds;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	fds.fd = fd;
638c2ecf20Sopenharmony_ci	fds.events = POLLIN | POLLERR;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return poll(&fds, 1, timeout);
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ciint sync_merge(const char *name, int fd1, int fd2)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct sync_merge_data data = {};
718c2ecf20Sopenharmony_ci	int err;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	data.fd2 = fd2;
748c2ecf20Sopenharmony_ci	strncpy(data.name, name, sizeof(data.name) - 1);
758c2ecf20Sopenharmony_ci	data.name[sizeof(data.name) - 1] = '\0';
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	err = ioctl(fd1, SYNC_IOC_MERGE, &data);
788c2ecf20Sopenharmony_ci	if (err < 0)
798c2ecf20Sopenharmony_ci		return err;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	return data.fence;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic struct sync_file_info *sync_file_info(int fd)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct sync_file_info *info;
878c2ecf20Sopenharmony_ci	struct sync_fence_info *fence_info;
888c2ecf20Sopenharmony_ci	int err, num_fences;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	info = calloc(1, sizeof(*info));
918c2ecf20Sopenharmony_ci	if (info == NULL)
928c2ecf20Sopenharmony_ci		return NULL;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
958c2ecf20Sopenharmony_ci	if (err < 0) {
968c2ecf20Sopenharmony_ci		free(info);
978c2ecf20Sopenharmony_ci		return NULL;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	num_fences = info->num_fences;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if (num_fences) {
1038c2ecf20Sopenharmony_ci		info->flags = 0;
1048c2ecf20Sopenharmony_ci		info->num_fences = num_fences;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		fence_info = calloc(num_fences, sizeof(*fence_info));
1078c2ecf20Sopenharmony_ci		if (!fence_info) {
1088c2ecf20Sopenharmony_ci			free(info);
1098c2ecf20Sopenharmony_ci			return NULL;
1108c2ecf20Sopenharmony_ci		}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		info->sync_fence_info = (uint64_t)(unsigned long)fence_info;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci		err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
1158c2ecf20Sopenharmony_ci		if (err < 0) {
1168c2ecf20Sopenharmony_ci			free(fence_info);
1178c2ecf20Sopenharmony_ci			free(info);
1188c2ecf20Sopenharmony_ci			return NULL;
1198c2ecf20Sopenharmony_ci		}
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	return info;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic void sync_file_info_free(struct sync_file_info *info)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	free((void *)(unsigned long)info->sync_fence_info);
1288c2ecf20Sopenharmony_ci	free(info);
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ciint sync_fence_size(int fd)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	int count;
1348c2ecf20Sopenharmony_ci	struct sync_file_info *info = sync_file_info(fd);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (!info)
1378c2ecf20Sopenharmony_ci		return 0;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	count = info->num_fences;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	sync_file_info_free(info);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return count;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ciint sync_fence_count_with_status(int fd, int status)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	unsigned int i, count = 0;
1498c2ecf20Sopenharmony_ci	struct sync_fence_info *fence_info = NULL;
1508c2ecf20Sopenharmony_ci	struct sync_file_info *info = sync_file_info(fd);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (!info)
1538c2ecf20Sopenharmony_ci		return -1;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	fence_info = (struct sync_fence_info *)(unsigned long)info->sync_fence_info;
1568c2ecf20Sopenharmony_ci	for (i = 0 ; i < info->num_fences ; i++) {
1578c2ecf20Sopenharmony_ci		if (fence_info[i].status == status)
1588c2ecf20Sopenharmony_ci			count++;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	sync_file_info_free(info);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return count;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ciint sw_sync_timeline_create(void)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	return open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ciint sw_sync_timeline_inc(int fd, unsigned int count)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	__u32 arg = count;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return ioctl(fd, SW_SYNC_IOC_INC, &arg);
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ciint sw_sync_timeline_is_valid(int fd)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	int status;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (fd == -1)
1838c2ecf20Sopenharmony_ci		return 0;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	status = fcntl(fd, F_GETFD, 0);
1868c2ecf20Sopenharmony_ci	return (status >= 0);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_civoid sw_sync_timeline_destroy(int fd)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	if (sw_sync_timeline_is_valid(fd))
1928c2ecf20Sopenharmony_ci		close(fd);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ciint sw_sync_fence_create(int fd, const char *name, unsigned int value)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct sw_sync_create_fence_data data = {};
1988c2ecf20Sopenharmony_ci	int err;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	data.value = value;
2018c2ecf20Sopenharmony_ci	strncpy(data.name, name, sizeof(data.name) - 1);
2028c2ecf20Sopenharmony_ci	data.name[sizeof(data.name) - 1] = '\0';
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
2058c2ecf20Sopenharmony_ci	if (err < 0)
2068c2ecf20Sopenharmony_ci		return err;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	return data.fence;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ciint sw_sync_fence_is_valid(int fd)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	/* Same code! */
2148c2ecf20Sopenharmony_ci	return sw_sync_timeline_is_valid(fd);
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_civoid sw_sync_fence_destroy(int fd)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	if (sw_sync_fence_is_valid(fd))
2208c2ecf20Sopenharmony_ci		close(fd);
2218c2ecf20Sopenharmony_ci}
222