162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  sync / sw_sync abstraction
362306a36Sopenharmony_ci *  Copyright 2015-2016 Collabora Ltd.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Based on the implementation from the Android Open Source Project,
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Copyright 2012 Google, Inc
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  Permission is hereby granted, free of charge, to any person obtaining a
1062306a36Sopenharmony_ci *  copy of this software and associated documentation files (the "Software"),
1162306a36Sopenharmony_ci *  to deal in the Software without restriction, including without limitation
1262306a36Sopenharmony_ci *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
1362306a36Sopenharmony_ci *  and/or sell copies of the Software, and to permit persons to whom the
1462306a36Sopenharmony_ci *  Software is furnished to do so, subject to the following conditions:
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci *  The above copyright notice and this permission notice shall be included in
1762306a36Sopenharmony_ci *  all copies or substantial portions of the Software.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2062306a36Sopenharmony_ci *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2162306a36Sopenharmony_ci *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2262306a36Sopenharmony_ci *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2362306a36Sopenharmony_ci *  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2462306a36Sopenharmony_ci *  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2562306a36Sopenharmony_ci *  OTHER DEALINGS IN THE SOFTWARE.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <fcntl.h>
2962306a36Sopenharmony_ci#include <malloc.h>
3062306a36Sopenharmony_ci#include <poll.h>
3162306a36Sopenharmony_ci#include <stdint.h>
3262306a36Sopenharmony_ci#include <string.h>
3362306a36Sopenharmony_ci#include <unistd.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#include <sys/ioctl.h>
3662306a36Sopenharmony_ci#include <sys/stat.h>
3762306a36Sopenharmony_ci#include <sys/types.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#include "sync.h"
4062306a36Sopenharmony_ci#include "sw_sync.h"
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include <linux/sync_file.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* SW_SYNC ioctls */
4662306a36Sopenharmony_cistruct sw_sync_create_fence_data {
4762306a36Sopenharmony_ci	__u32	value;
4862306a36Sopenharmony_ci	char	name[32];
4962306a36Sopenharmony_ci	__s32	fence;
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define SW_SYNC_IOC_MAGIC		'W'
5362306a36Sopenharmony_ci#define SW_SYNC_IOC_CREATE_FENCE	_IOWR(SW_SYNC_IOC_MAGIC, 0,\
5462306a36Sopenharmony_ci					      struct sw_sync_create_fence_data)
5562306a36Sopenharmony_ci#define SW_SYNC_IOC_INC			_IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ciint sync_wait(int fd, int timeout)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct pollfd fds;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	fds.fd = fd;
6362306a36Sopenharmony_ci	fds.events = POLLIN | POLLERR;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	return poll(&fds, 1, timeout);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciint sync_merge(const char *name, int fd1, int fd2)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct sync_merge_data data = {};
7162306a36Sopenharmony_ci	int err;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	data.fd2 = fd2;
7462306a36Sopenharmony_ci	strncpy(data.name, name, sizeof(data.name) - 1);
7562306a36Sopenharmony_ci	data.name[sizeof(data.name) - 1] = '\0';
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	err = ioctl(fd1, SYNC_IOC_MERGE, &data);
7862306a36Sopenharmony_ci	if (err < 0)
7962306a36Sopenharmony_ci		return err;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return data.fence;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic struct sync_file_info *sync_file_info(int fd)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct sync_file_info *info;
8762306a36Sopenharmony_ci	struct sync_fence_info *fence_info;
8862306a36Sopenharmony_ci	int err, num_fences;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	info = calloc(1, sizeof(*info));
9162306a36Sopenharmony_ci	if (info == NULL)
9262306a36Sopenharmony_ci		return NULL;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
9562306a36Sopenharmony_ci	if (err < 0) {
9662306a36Sopenharmony_ci		free(info);
9762306a36Sopenharmony_ci		return NULL;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	num_fences = info->num_fences;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if (num_fences) {
10362306a36Sopenharmony_ci		info->flags = 0;
10462306a36Sopenharmony_ci		info->num_fences = num_fences;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		fence_info = calloc(num_fences, sizeof(*fence_info));
10762306a36Sopenharmony_ci		if (!fence_info) {
10862306a36Sopenharmony_ci			free(info);
10962306a36Sopenharmony_ci			return NULL;
11062306a36Sopenharmony_ci		}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		info->sync_fence_info = (uint64_t)(unsigned long)fence_info;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci		err = ioctl(fd, SYNC_IOC_FILE_INFO, info);
11562306a36Sopenharmony_ci		if (err < 0) {
11662306a36Sopenharmony_ci			free(fence_info);
11762306a36Sopenharmony_ci			free(info);
11862306a36Sopenharmony_ci			return NULL;
11962306a36Sopenharmony_ci		}
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return info;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic void sync_file_info_free(struct sync_file_info *info)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	free((void *)(unsigned long)info->sync_fence_info);
12862306a36Sopenharmony_ci	free(info);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciint sync_fence_size(int fd)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	int count;
13462306a36Sopenharmony_ci	struct sync_file_info *info = sync_file_info(fd);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (!info)
13762306a36Sopenharmony_ci		return 0;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	count = info->num_fences;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	sync_file_info_free(info);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return count;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ciint sync_fence_count_with_status(int fd, int status)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	unsigned int i, count = 0;
14962306a36Sopenharmony_ci	struct sync_fence_info *fence_info = NULL;
15062306a36Sopenharmony_ci	struct sync_file_info *info = sync_file_info(fd);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (!info)
15362306a36Sopenharmony_ci		return -1;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	fence_info = (struct sync_fence_info *)(unsigned long)info->sync_fence_info;
15662306a36Sopenharmony_ci	for (i = 0 ; i < info->num_fences ; i++) {
15762306a36Sopenharmony_ci		if (fence_info[i].status == status)
15862306a36Sopenharmony_ci			count++;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	sync_file_info_free(info);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	return count;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ciint sw_sync_timeline_create(void)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	return open("/sys/kernel/debug/sync/sw_sync", O_RDWR);
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ciint sw_sync_timeline_inc(int fd, unsigned int count)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	__u32 arg = count;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return ioctl(fd, SW_SYNC_IOC_INC, &arg);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ciint sw_sync_timeline_is_valid(int fd)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	int status;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (fd == -1)
18362306a36Sopenharmony_ci		return 0;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	status = fcntl(fd, F_GETFD, 0);
18662306a36Sopenharmony_ci	return (status >= 0);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_civoid sw_sync_timeline_destroy(int fd)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	if (sw_sync_timeline_is_valid(fd))
19262306a36Sopenharmony_ci		close(fd);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ciint sw_sync_fence_create(int fd, const char *name, unsigned int value)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct sw_sync_create_fence_data data = {};
19862306a36Sopenharmony_ci	int err;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	data.value = value;
20162306a36Sopenharmony_ci	strncpy(data.name, name, sizeof(data.name) - 1);
20262306a36Sopenharmony_ci	data.name[sizeof(data.name) - 1] = '\0';
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	err = ioctl(fd, SW_SYNC_IOC_CREATE_FENCE, &data);
20562306a36Sopenharmony_ci	if (err < 0)
20662306a36Sopenharmony_ci		return err;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	return data.fence;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ciint sw_sync_fence_is_valid(int fd)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	/* Same code! */
21462306a36Sopenharmony_ci	return sw_sync_timeline_is_valid(fd);
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_civoid sw_sync_fence_destroy(int fd)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	if (sw_sync_fence_is_valid(fd))
22062306a36Sopenharmony_ci		close(fd);
22162306a36Sopenharmony_ci}
222