1 /********************************************************** 2 * Copyright 2009-2015 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 **********************************************************/ 25 #include <libsync.h> 26 27 #include "util/u_memory.h" 28 #include "util/u_atomic.h" 29 #include "util/list.h" 30 #include "os/os_thread.h" 31 32 #include "pipebuffer/pb_buffer_fenced.h" 33 34 #include "vmw_screen.h" 35 #include "vmw_fence.h" 36 37 struct vmw_fence_ops 38 { 39 /* 40 * Immutable members. 41 */ 42 struct pb_fence_ops base; 43 struct vmw_winsys_screen *vws; 44 45 mtx_t mutex; 46 47 /* 48 * Protected by mutex; 49 */ 50 struct list_head not_signaled; 51 uint32_t last_signaled; 52 uint32_t last_emitted; 53 }; 54 55 struct vmw_fence 56 { 57 struct list_head ops_list; 58 int32_t refcount; 59 uint32_t handle; 60 uint32_t mask; 61 int32_t signalled; 62 uint32_t seqno; 63 int32_t fence_fd; 64 boolean imported; /* TRUE if imported from another process */ 65 }; 66 67 /** 68 * vmw_fence_seq_is_signaled - Check whether a fence seqno is 69 * signaled. 70 * 71 * @ops: Pointer to a struct pb_fence_ops. 72 * 73 */ 74 static inline boolean 75 vmw_fence_seq_is_signaled(uint32_t seq, uint32_t last, uint32_t cur) 76 { 77 return (cur - last <= cur - seq); 78 } 79 80 81 /** 82 * vmw_fence_ops - Return the vmw_fence_ops structure backing a 83 * struct pb_fence_ops pointer. 84 * 85 * @ops: Pointer to a struct pb_fence_ops. 86 * 87 */ 88 static inline struct vmw_fence_ops * 89 vmw_fence_ops(struct pb_fence_ops *ops) 90 { 91 assert(ops); 92 return (struct vmw_fence_ops *)ops; 93 } 94 95 96 /** 97 * vmw_fences_release - Release all fences from the not_signaled 98 * list. 99 * 100 * @ops: Pointer to a struct vmw_fence_ops. 101 * 102 */ 103 static void 104 vmw_fences_release(struct vmw_fence_ops *ops) 105 { 106 struct vmw_fence *fence, *n; 107 108 mtx_lock(&ops->mutex); 109 LIST_FOR_EACH_ENTRY_SAFE(fence, n, &ops->not_signaled, ops_list) 110 LIST_DELINIT(&fence->ops_list); 111 mtx_unlock(&ops->mutex); 112 } 113 114 /** 115 * vmw_fences_signal - Traverse the not_signaled list and try to 116 * signal unsignaled fences. 117 * 118 * @ops: Pointer to a struct pb_fence_ops. 119 * @signaled: Seqno that has signaled. 120 * @emitted: Last seqno emitted by the kernel. 121 * @has_emitted: Whether we provide the emitted value. 122 * 123 */ 124 void 125 vmw_fences_signal(struct pb_fence_ops *fence_ops, 126 uint32_t signaled, 127 uint32_t emitted, 128 boolean has_emitted) 129 { 130 struct vmw_fence_ops *ops = NULL; 131 struct vmw_fence *fence, *n; 132 133 if (fence_ops == NULL) 134 return; 135 136 ops = vmw_fence_ops(fence_ops); 137 mtx_lock(&ops->mutex); 138 139 if (!has_emitted) { 140 emitted = ops->last_emitted; 141 if (emitted - signaled > (1 << 30)) 142 emitted = signaled; 143 } 144 145 if (signaled == ops->last_signaled && emitted == ops->last_emitted) 146 goto out_unlock; 147 148 LIST_FOR_EACH_ENTRY_SAFE(fence, n, &ops->not_signaled, ops_list) { 149 if (!vmw_fence_seq_is_signaled(fence->seqno, signaled, emitted)) 150 break; 151 152 p_atomic_set(&fence->signalled, 1); 153 LIST_DELINIT(&fence->ops_list); 154 } 155 ops->last_signaled = signaled; 156 ops->last_emitted = emitted; 157 158 out_unlock: 159 mtx_unlock(&ops->mutex); 160 } 161 162 163 /** 164 * vmw_fence - return the vmw_fence object identified by a 165 * struct pipe_fence_handle * 166 * 167 * @fence: The opaque pipe fence handle. 168 */ 169 static inline struct vmw_fence * 170 vmw_fence(struct pipe_fence_handle *fence) 171 { 172 return (struct vmw_fence *) fence; 173 } 174 175 176 /** 177 * vmw_fence_create - Create a user-space fence object. 178 * 179 * @fence_ops: The fence_ops manager to register with. 180 * @handle: Handle identifying the kernel fence object. 181 * @mask: Mask of flags that this fence object may signal. 182 * @fd: File descriptor to associate with the fence 183 * 184 * Returns NULL on failure. 185 */ 186 struct pipe_fence_handle * 187 vmw_fence_create(struct pb_fence_ops *fence_ops, uint32_t handle, 188 uint32_t seqno, uint32_t mask, int32_t fd) 189 { 190 struct vmw_fence *fence = CALLOC_STRUCT(vmw_fence); 191 struct vmw_fence_ops *ops = NULL; 192 193 if (!fence) 194 return NULL; 195 196 p_atomic_set(&fence->refcount, 1); 197 fence->handle = handle; 198 fence->mask = mask; 199 fence->seqno = seqno; 200 fence->fence_fd = fd; 201 p_atomic_set(&fence->signalled, 0); 202 203 /* 204 * If the fence was not created by our device, then we won't 205 * manage it with our ops 206 */ 207 if (!fence_ops) { 208 fence->imported = true; 209 return (struct pipe_fence_handle *) fence; 210 } 211 212 ops = vmw_fence_ops(fence_ops); 213 214 mtx_lock(&ops->mutex); 215 216 if (vmw_fence_seq_is_signaled(seqno, ops->last_signaled, seqno)) { 217 p_atomic_set(&fence->signalled, 1); 218 LIST_INITHEAD(&fence->ops_list); 219 } else { 220 p_atomic_set(&fence->signalled, 0); 221 LIST_ADDTAIL(&fence->ops_list, &ops->not_signaled); 222 } 223 224 mtx_unlock(&ops->mutex); 225 226 return (struct pipe_fence_handle *) fence; 227 } 228 229 230 /** 231 * vmw_fence_destroy - Frees a vmw fence object. 232 * 233 * Also closes the file handle associated with the object, if any 234 */ 235 static 236 void vmw_fence_destroy(struct vmw_fence *vfence) 237 { 238 if (vfence->fence_fd != -1) 239 close(vfence->fence_fd); 240 241 FREE(vfence); 242 } 243 244 245 /** 246 * vmw_fence_reference - Reference / unreference a vmw fence object. 247 * 248 * @vws: Pointer to the winsys screen. 249 * @ptr: Pointer to reference transfer destination. 250 * @fence: Pointer to object to reference. May be NULL. 251 */ 252 void 253 vmw_fence_reference(struct vmw_winsys_screen *vws, 254 struct pipe_fence_handle **ptr, 255 struct pipe_fence_handle *fence) 256 { 257 if (*ptr) { 258 struct vmw_fence *vfence = vmw_fence(*ptr); 259 260 if (p_atomic_dec_zero(&vfence->refcount)) { 261 struct vmw_fence_ops *ops = vmw_fence_ops(vws->fence_ops); 262 263 if (!vfence->imported) { 264 vmw_ioctl_fence_unref(vws, vfence->handle); 265 266 mtx_lock(&ops->mutex); 267 LIST_DELINIT(&vfence->ops_list); 268 mtx_unlock(&ops->mutex); 269 } 270 271 vmw_fence_destroy(vfence); 272 } 273 } 274 275 if (fence) { 276 struct vmw_fence *vfence = vmw_fence(fence); 277 278 p_atomic_inc(&vfence->refcount); 279 } 280 281 *ptr = fence; 282 } 283 284 285 /** 286 * vmw_fence_signalled - Check whether a fence object is signalled. 287 * 288 * @vws: Pointer to the winsys screen. 289 * @fence: Handle to the fence object. 290 * @flag: Fence flags to check. If the fence object can't signal 291 * a flag, it is assumed to be already signaled. 292 * 293 * Returns 0 if the fence object was signaled, nonzero otherwise. 294 */ 295 int 296 vmw_fence_signalled(struct vmw_winsys_screen *vws, 297 struct pipe_fence_handle *fence, 298 unsigned flag) 299 { 300 struct vmw_fence *vfence; 301 int32_t vflags = SVGA_FENCE_FLAG_EXEC; 302 int ret; 303 uint32_t old; 304 305 if (!fence) 306 return 0; 307 308 vfence = vmw_fence(fence); 309 old = p_atomic_read(&vfence->signalled); 310 311 vflags &= ~vfence->mask; 312 313 if ((old & vflags) == vflags) 314 return 0; 315 316 /* 317 * Currently we update signaled fences on each execbuf call. 318 * That should really be sufficient, and we can avoid 319 * a lot of kernel calls this way. 320 */ 321 #if 1 322 ret = vmw_ioctl_fence_signalled(vws, vfence->handle, vflags); 323 324 if (ret == 0) 325 p_atomic_set(&vfence->signalled, 1); 326 return ret; 327 #else 328 (void) ret; 329 return -1; 330 #endif 331 } 332 333 /** 334 * vmw_fence_finish - Wait for a fence object to signal. 335 * 336 * @vws: Pointer to the winsys screen. 337 * @fence: Handle to the fence object. 338 * @timeout: How long to wait before timing out. 339 * @flag: Fence flags to wait for. If the fence object can't signal 340 * a flag, it is assumed to be already signaled. 341 * 342 * Returns 0 if the wait succeeded. Nonzero otherwise. 343 */ 344 int 345 vmw_fence_finish(struct vmw_winsys_screen *vws, 346 struct pipe_fence_handle *fence, 347 uint64_t timeout, 348 unsigned flag) 349 { 350 struct vmw_fence *vfence; 351 int32_t vflags = SVGA_FENCE_FLAG_EXEC; 352 int ret; 353 uint32_t old; 354 355 if (!fence) 356 return 0; 357 358 vfence = vmw_fence(fence); 359 360 if (vfence->imported) { 361 ret = sync_wait(vfence->fence_fd, timeout / 1000000); 362 363 if (!ret) 364 p_atomic_set(&vfence->signalled, 1); 365 366 return !!ret; 367 } 368 369 old = p_atomic_read(&vfence->signalled); 370 vflags &= ~vfence->mask; 371 372 if ((old & vflags) == vflags) 373 return 0; 374 375 ret = vmw_ioctl_fence_finish(vws, vfence->handle, vflags); 376 377 if (ret == 0) { 378 int32_t prev = old; 379 380 do { 381 old = prev; 382 prev = p_atomic_cmpxchg(&vfence->signalled, old, old | vflags); 383 } while (prev != old); 384 } 385 386 return ret; 387 } 388 389 /** 390 * vmw_fence_get_fd 391 * 392 * Returns the file descriptor associated with the fence 393 */ 394 int 395 vmw_fence_get_fd(struct pipe_fence_handle *fence) 396 { 397 struct vmw_fence *vfence; 398 399 if (!fence) 400 return -1; 401 402 vfence = vmw_fence(fence); 403 return vfence->fence_fd; 404 } 405 406 407 /** 408 * vmw_fence_ops_fence_reference - wrapper for the pb_fence_ops api. 409 * 410 * wrapper around vmw_fence_reference. 411 */ 412 static void 413 vmw_fence_ops_fence_reference(struct pb_fence_ops *ops, 414 struct pipe_fence_handle **ptr, 415 struct pipe_fence_handle *fence) 416 { 417 struct vmw_winsys_screen *vws = vmw_fence_ops(ops)->vws; 418 419 vmw_fence_reference(vws, ptr, fence); 420 } 421 422 /** 423 * vmw_fence_ops_fence_signalled - wrapper for the pb_fence_ops api. 424 * 425 * wrapper around vmw_fence_signalled. 426 */ 427 static int 428 vmw_fence_ops_fence_signalled(struct pb_fence_ops *ops, 429 struct pipe_fence_handle *fence, 430 unsigned flag) 431 { 432 struct vmw_winsys_screen *vws = vmw_fence_ops(ops)->vws; 433 434 return vmw_fence_signalled(vws, fence, flag); 435 } 436 437 438 /** 439 * vmw_fence_ops_fence_finish - wrapper for the pb_fence_ops api. 440 * 441 * wrapper around vmw_fence_finish. 442 */ 443 static int 444 vmw_fence_ops_fence_finish(struct pb_fence_ops *ops, 445 struct pipe_fence_handle *fence, 446 unsigned flag) 447 { 448 struct vmw_winsys_screen *vws = vmw_fence_ops(ops)->vws; 449 450 return vmw_fence_finish(vws, fence, PIPE_TIMEOUT_INFINITE, flag); 451 } 452 453 454 /** 455 * vmw_fence_ops_destroy - Destroy a pb_fence_ops function table. 456 * 457 * @ops: The function table to destroy. 458 * 459 * Part of the pb_fence_ops api. 460 */ 461 static void 462 vmw_fence_ops_destroy(struct pb_fence_ops *ops) 463 { 464 vmw_fences_release(vmw_fence_ops(ops)); 465 FREE(ops); 466 } 467 468 469 /** 470 * vmw_fence_ops_create - Create a pb_fence_ops function table. 471 * 472 * @vws: Pointer to a struct vmw_winsys_screen. 473 * 474 * Returns a pointer to a pb_fence_ops function table to interface 475 * with pipe_buffer. This function is typically called on driver setup. 476 * 477 * Returns NULL on failure. 478 */ 479 struct pb_fence_ops * 480 vmw_fence_ops_create(struct vmw_winsys_screen *vws) 481 { 482 struct vmw_fence_ops *ops; 483 484 ops = CALLOC_STRUCT(vmw_fence_ops); 485 if(!ops) 486 return NULL; 487 488 (void) mtx_init(&ops->mutex, mtx_plain); 489 LIST_INITHEAD(&ops->not_signaled); 490 ops->base.destroy = &vmw_fence_ops_destroy; 491 ops->base.fence_reference = &vmw_fence_ops_fence_reference; 492 ops->base.fence_signalled = &vmw_fence_ops_fence_signalled; 493 ops->base.fence_finish = &vmw_fence_ops_fence_finish; 494 495 ops->vws = vws; 496 497 return &ops->base; 498 } 499