iris_fence.c revision 9f464c52
1/* 2 * Copyright © 2018 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23/** 24 * @file iris_fence.c 25 * 26 * Fences for driver and IPC serialisation, scheduling and synchronisation. 27 */ 28 29#include "util/u_inlines.h" 30 31#include "iris_batch.h" 32#include "iris_bufmgr.h" 33#include "iris_context.h" 34#include "iris_fence.h" 35#include "iris_screen.h" 36 37static uint32_t 38gem_syncobj_create(int fd, uint32_t flags) 39{ 40 struct drm_syncobj_create args = { 41 .flags = flags, 42 }; 43 44 drm_ioctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args); 45 46 return args.handle; 47} 48 49static void 50gem_syncobj_destroy(int fd, uint32_t handle) 51{ 52 struct drm_syncobj_destroy args = { 53 .handle = handle, 54 }; 55 56 drm_ioctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); 57} 58 59/** 60 * Make a new sync-point. 61 */ 62struct iris_syncpt * 63iris_create_syncpt(struct iris_screen *screen) 64{ 65 struct iris_syncpt *syncpt = malloc(sizeof(*syncpt)); 66 67 if (!syncpt) 68 return NULL; 69 70 syncpt->handle = gem_syncobj_create(screen->fd, 0); 71 assert(syncpt->handle); 72 73 pipe_reference_init(&syncpt->ref, 1); 74 75 return syncpt; 76} 77 78void 79iris_syncpt_destroy(struct iris_screen *screen, struct iris_syncpt *syncpt) 80{ 81 gem_syncobj_destroy(screen->fd, syncpt->handle); 82 free(syncpt); 83} 84 85/** 86 * Add a sync-point to the batch, with the given flags. 87 * 88 * \p flags One of I915_EXEC_FENCE_WAIT or I915_EXEC_FENCE_SIGNAL. 89 */ 90void 91iris_batch_add_syncpt(struct iris_batch *batch, 92 struct iris_syncpt *syncpt, 93 unsigned flags) 94{ 95 struct drm_i915_gem_exec_fence *fence = 96 util_dynarray_grow(&batch->exec_fences, sizeof(*fence)); 97 98 *fence = (struct drm_i915_gem_exec_fence) { 99 .handle = syncpt->handle, 100 .flags = flags, 101 }; 102 103 struct iris_syncpt **store = 104 util_dynarray_grow(&batch->syncpts, sizeof(*store)); 105 106 *store = NULL; 107 iris_syncpt_reference(batch->screen, store, syncpt); 108} 109 110/* ------------------------------------------------------------------- */ 111 112struct pipe_fence_handle { 113 struct pipe_reference ref; 114 struct iris_syncpt *syncpt[IRIS_BATCH_COUNT]; 115 unsigned count; 116}; 117 118static void 119iris_fence_destroy(struct pipe_screen *p_screen, 120 struct pipe_fence_handle *fence) 121{ 122 struct iris_screen *screen = (struct iris_screen *)p_screen; 123 124 for (unsigned i = 0; i < fence->count; i++) 125 iris_syncpt_reference(screen, &fence->syncpt[i], NULL); 126 127 free(fence); 128} 129 130static void 131iris_fence_reference(struct pipe_screen *p_screen, 132 struct pipe_fence_handle **dst, 133 struct pipe_fence_handle *src) 134{ 135 if (pipe_reference(&(*dst)->ref, &src->ref)) 136 iris_fence_destroy(p_screen, *dst); 137 138 *dst = src; 139} 140 141bool 142iris_wait_syncpt(struct pipe_screen *p_screen, 143 struct iris_syncpt *syncpt, 144 int64_t timeout_nsec) 145{ 146 if (!syncpt) 147 return false; 148 149 struct iris_screen *screen = (struct iris_screen *)p_screen; 150 struct drm_syncobj_wait args = { 151 .handles = (uintptr_t)&syncpt->handle, 152 .count_handles = 1, 153 .timeout_nsec = timeout_nsec, 154 }; 155 return drm_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); 156} 157 158static void 159iris_fence_flush(struct pipe_context *ctx, 160 struct pipe_fence_handle **out_fence, 161 unsigned flags) 162{ 163 struct iris_screen *screen = (void *) ctx->screen; 164 struct iris_context *ice = (struct iris_context *)ctx; 165 166 /* XXX PIPE_FLUSH_DEFERRED */ 167 for (unsigned i = 0; i < IRIS_BATCH_COUNT; i++) 168 iris_batch_flush(&ice->batches[i]); 169 170 if (!out_fence) 171 return; 172 173 struct pipe_fence_handle *fence = calloc(1, sizeof(*fence)); 174 if (!fence) 175 return; 176 177 pipe_reference_init(&fence->ref, 1); 178 179 for (unsigned b = 0; b < IRIS_BATCH_COUNT; b++) { 180 if (!iris_wait_syncpt(ctx->screen, ice->batches[b].last_syncpt, 0)) 181 continue; 182 183 iris_syncpt_reference(screen, &fence->syncpt[fence->count++], 184 ice->batches[b].last_syncpt); 185 } 186 *out_fence = fence; 187} 188 189static void 190iris_fence_await(struct pipe_context *ctx, 191 struct pipe_fence_handle *fence) 192{ 193 struct iris_context *ice = (struct iris_context *)ctx; 194 195 for (unsigned b = 0; b < IRIS_BATCH_COUNT; b++) { 196 for (unsigned i = 0; i < fence->count; i++) { 197 iris_batch_add_syncpt(&ice->batches[b], fence->syncpt[i], 198 I915_EXEC_FENCE_WAIT); 199 } 200 } 201} 202 203#define NSEC_PER_SEC (1000 * USEC_PER_SEC) 204#define USEC_PER_SEC (1000 * MSEC_PER_SEC) 205#define MSEC_PER_SEC (1000) 206 207static uint64_t 208gettime_ns(void) 209{ 210 struct timespec current; 211 clock_gettime(CLOCK_MONOTONIC, ¤t); 212 return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec; 213} 214 215static uint64_t 216rel2abs(uint64_t timeout) 217{ 218 if (timeout == 0) 219 return 0; 220 221 uint64_t current_time = gettime_ns(); 222 uint64_t max_timeout = (uint64_t) INT64_MAX - current_time; 223 224 timeout = MIN2(max_timeout, timeout); 225 226 return current_time + timeout; 227} 228 229static boolean 230iris_fence_finish(struct pipe_screen *p_screen, 231 struct pipe_context *ctx, 232 struct pipe_fence_handle *fence, 233 uint64_t timeout) 234{ 235 struct iris_screen *screen = (struct iris_screen *)p_screen; 236 237 if (!fence->count) 238 return true; 239 240 uint32_t handles[ARRAY_SIZE(fence->syncpt)]; 241 for (unsigned i = 0; i < fence->count; i++) 242 handles[i] = fence->syncpt[i]->handle; 243 244 struct drm_syncobj_wait args = { 245 .handles = (uintptr_t)handles, 246 .count_handles = fence->count, 247 .timeout_nsec = rel2abs(timeout), 248 .flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL 249 }; 250 return drm_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args) == 0; 251} 252 253#ifndef SYNC_IOC_MAGIC 254/* duplicated from linux/sync_file.h to avoid build-time dependency 255 * on new (v4.7) kernel headers. Once distro's are mostly using 256 * something newer than v4.7 drop this and #include <linux/sync_file.h> 257 * instead. 258 */ 259struct sync_merge_data { 260 char name[32]; 261 __s32 fd2; 262 __s32 fence; 263 __u32 flags; 264 __u32 pad; 265}; 266 267#define SYNC_IOC_MAGIC '>' 268#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data) 269#endif 270 271static int 272sync_merge_fd(int sync_fd, int new_fd) 273{ 274 if (sync_fd == -1) 275 return new_fd; 276 277 if (new_fd == -1) 278 return sync_fd; 279 280 struct sync_merge_data args = { 281 .name = "iris fence", 282 .fd2 = new_fd, 283 .fence = -1, 284 }; 285 286 drm_ioctl(sync_fd, SYNC_IOC_MERGE, &args); 287 close(new_fd); 288 close(sync_fd); 289 290 return args.fence; 291} 292 293static int 294iris_fence_get_fd(struct pipe_screen *p_screen, 295 struct pipe_fence_handle *fence) 296{ 297 struct iris_screen *screen = (struct iris_screen *)p_screen; 298 int fd = -1; 299 300 for (unsigned i = 0; i < fence->count; i++) { 301 struct drm_syncobj_handle args = { 302 .handle = fence->syncpt[i]->handle, 303 .flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE, 304 .fd = -1, 305 }; 306 307 drm_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); 308 fd = sync_merge_fd(fd, args.fd); 309 } 310 311 return fd; 312} 313 314static void 315iris_fence_create_fd(struct pipe_context *ctx, 316 struct pipe_fence_handle **out, 317 int fd, 318 enum pipe_fd_type type) 319{ 320 assert(type == PIPE_FD_TYPE_NATIVE_SYNC); 321 322 struct iris_screen *screen = (struct iris_screen *)ctx->screen; 323 struct drm_syncobj_handle args = { 324 .flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE, 325 .fd = fd, 326 }; 327 drm_ioctl(screen->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); 328 329 struct iris_syncpt *syncpt = malloc(sizeof(*syncpt)); 330 syncpt->handle = args.handle; 331 pipe_reference_init(&syncpt->ref, 1); 332 333 struct pipe_fence_handle *fence = malloc(sizeof(*fence)); 334 pipe_reference_init(&fence->ref, 1); 335 fence->syncpt[0] = syncpt; 336 fence->count = 1; 337 338 *out = fence; 339} 340 341void 342iris_init_screen_fence_functions(struct pipe_screen *screen) 343{ 344 screen->fence_reference = iris_fence_reference; 345 screen->fence_finish = iris_fence_finish; 346 screen->fence_get_fd = iris_fence_get_fd; 347} 348 349void 350iris_init_context_fence_functions(struct pipe_context *ctx) 351{ 352 ctx->flush = iris_fence_flush; 353 ctx->create_fence_fd = iris_fence_create_fd; 354 ctx->fence_server_sync = iris_fence_await; 355} 356