sw_sync.c 5.23 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * Copyright © 2016 Collabora, Ltd.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors:
 *    Robert Foss <robert.foss@collabora.com>
 */

27
#ifdef HAVE_LIBGEN_H
28 29 30 31 32 33 34 35
#include <libgen.h>
#endif
#include <fcntl.h>
#include <poll.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/ioctl.h>

36 37
#include "sync_file.h"

38
#include "igt_debugfs.h"
39
#include "igt_kmod.h"
40 41 42 43
#include "sw_sync.h"
#include "drmtest.h"
#include "ioctl_wrappers.h"

44 45 46 47 48 49 50
/**
 * SECTION:sw_sync
 * @short_description: Software sync (fencing) support library
 * @title: SW Sync
 * @include: sw_sync.h
 */

51
struct int_sync_create_fence_data {
52 53 54 55 56
	__u32	value;
	char	name[32];
	__s32	fence;
};

57 58 59 60
#define INT_SYNC_IOC_MAGIC 'W'
#define INT_SYNC_IOC_CREATE_FENCE	_IOWR(INT_SYNC_IOC_MAGIC, 0, struct int_sync_create_fence_data)
#define INT_SYNC_IOC_INC		_IOW(INT_SYNC_IOC_MAGIC, 1, __u32)

61 62 63
static bool kernel_sw_sync_path(char *path, int length)
{
	snprintf(path, length, "%s", "/dev/sw_sync");
64 65
	if (access(path, R_OK | W_OK) == 0)
		return true;
66 67

	snprintf(path, length, "%s", "/sys/kernel/debug/sync/sw_sync");
68 69
	if (access(path, R_OK | W_OK) == 0)
		return true;
70 71

	snprintf(path, length, "%s/sw_sync", igt_debugfs_mount());
72 73
	if (access(path, R_OK | W_OK) == 0)
		return true;
74

75
	return false;
76 77 78 79 80 81 82
}

static bool sw_sync_fd_is_valid(int fd)
{
	int status;

	if (fd < 0)
83
		return false;
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

	status = fcntl(fd, F_GETFD, 0);
	return status >= 0;
}

int sw_sync_timeline_create(void)
{
	char buf[128];
	int fd;

	igt_assert_f(kernel_sw_sync_path(buf, sizeof(buf)),
	    "Unable to find valid path for sw_sync\n");

	fd = open(buf, O_RDWR);
	igt_assert_f(sw_sync_fd_is_valid(fd), "Created invalid timeline\n");

	return fd;
}

103
int __sw_sync_timeline_create_fence(int fd, uint32_t seqno)
104
{
105
	struct int_sync_create_fence_data data = { .value = seqno};
106

107
	if (igt_ioctl(fd, INT_SYNC_IOC_CREATE_FENCE, &data))
108 109 110 111 112
		return -errno;

	return data.fence;
}

113
int sw_sync_timeline_create_fence(int fd, uint32_t seqno)
114
{
115
	int fence = __sw_sync_timeline_create_fence(fd, seqno);
116 117 118 119 120 121 122 123

	igt_assert_f(sw_sync_fd_is_valid(fence), "Created invalid fence\n");

	return fence;
}

void sw_sync_timeline_inc(int fd, uint32_t count)
{
124
	do_ioctl(fd, INT_SYNC_IOC_INC, &count);
125 126
}

127
int sync_fence_merge(int fd1, int fd2)
128
{
129
	struct sync_merge_data data = { .fd2 = fd2};
130

131
	if (ioctl(fd1, SYNC_IOC_MERGE, &data))
132 133 134 135 136
		return -errno;

	return data.fence;
}

137
int sync_fence_wait(int fd, int timeout)
138
{
139
	struct pollfd fds = { fd, POLLIN };
140 141 142
	int ret;

	do {
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
		ret = poll(&fds, 1, timeout);
		if (ret > 0) {
			if (fds.revents & (POLLERR | POLLNVAL))
				return -EINVAL;

			return 0;
		} else if (ret == 0) {
			return -ETIME;
		} else  {
			ret = -errno;
			if (ret == -EINTR || ret == -EAGAIN)
				continue;
			return ret;
		}
	} while (1);
158 159 160 161
}

int sync_fence_count(int fd)
{
162
	struct sync_file_info info = {};
163

164
	if (ioctl(fd, SYNC_IOC_FILE_INFO, &info))
165 166 167 168 169 170 171
		return -errno;

	return info.num_fences;
}

static int __sync_fence_count_status(int fd, int status)
{
172 173
	struct sync_file_info info = {};
	struct sync_fence_info *fence_info;
174 175 176
	int count;
	int i;

177
	if (ioctl(fd, SYNC_IOC_FILE_INFO, &info))
178 179 180 181 182 183
		return -errno;

	fence_info = calloc(info.num_fences, sizeof(*fence_info));
	if (!fence_info)
		return -ENOMEM;

184
	info.sync_fence_info = to_user_pointer(fence_info);
185
	if (ioctl(fd, SYNC_IOC_FILE_INFO, &info)) {
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
		count = -errno;
	} else {
		count = 0;
		for (i = 0 ; i < info.num_fences ; i++)
			if (fence_info[i].status == status)
				count++;
	}

	free(fence_info);

	return count;
}

int sync_fence_count_status(int fd, int status)
{
	int count = __sync_fence_count_status(fd, status);
	igt_assert_f(count >= 0, "No fences with supplied status found\n");

	return count;
}
206

207 208
int sync_fence_status(int fence)
{
209 210
	struct sync_fence_info fence_info;
	struct sync_file_info file_info = {
211 212 213 214
		.sync_fence_info = to_user_pointer(&fence_info),
		.num_fences = 1,
	};

215
	if (ioctl(fence, SYNC_IOC_FILE_INFO, &file_info))
216 217 218 219 220 221 222 223
		return -errno;

	if (file_info.num_fences != 1)
		return -EINVAL;

	return fence_info.status;
}

224 225
static void modprobe(const char *driver)
{
226
	igt_kmod_load(driver, NULL);
227 228
}

229 230 231 232
static bool kernel_has_sw_sync(void)
{
	char buf[128];

233
	modprobe("sw_sync");
234 235 236 237 238 239 240 241

	return kernel_sw_sync_path(buf, sizeof(buf));
}

void igt_require_sw_sync(void)
{
	igt_require(kernel_has_sw_sync());
}