1 /************************************************************************** 2 * 3 * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA 4 * All Rights Reserved. 5 * Copyright 2009 Vmware, Inc., Palo Alto, CA., USA 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sub license, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the 17 * next paragraph) shall be included in all copies or substantial portions 18 * of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 23 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 24 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 26 * USE OR OTHER DEALINGS IN THE SOFTWARE. 27 * 28 **************************************************************************/ 29 /* 30 * Authors: Thomas Hellstrm <thomas-at-tungstengraphics-dot-com> 31 * Keith Whitwell <keithw-at-tungstengraphics-dot-com> 32 */ 33 34 #ifdef HAVE_CONFIG_H 35 #include "config.h" 36 #endif 37 38 #include <stdlib.h> 39 #include "errno.h" 40 #include "string.h" 41 #include "wsbm_pool.h" 42 #include "wsbm_manager.h" 43 #include "wsbm_fencemgr.h" 44 #include "wsbm_driver.h" 45 #include "wsbm_priv.h" 46 #include "wsbm_util.h" 47 #include "wsbm_atomic.h" 48 #include "assert.h" 49 50 #define WSBM_BODATA_SIZE_ACCEPT 4096 51 52 #define WSBM_BUFFER_COMPLEX 0 53 #define WSBM_BUFFER_SIMPLE 1 54 #define WSBM_BUFFER_REF 2 55 56 struct _ValidateList 57 { 58 unsigned numTarget; 59 unsigned numCurrent; 60 unsigned numOnList; 61 unsigned hashSize; 62 uint32_t hashMask; 63 int driverData; 64 struct _WsbmListHead list; 65 struct _WsbmListHead free; 66 struct _WsbmListHead *hashTable; 67 }; 68 69 struct _WsbmBufferObject 70 { 71 /* Left to the client to protect this data for now. */ 72 73 struct _WsbmAtomic refCount; 74 struct _WsbmBufStorage *storage; 75 76 uint32_t placement; 77 unsigned alignment; 78 unsigned bufferType; 79 struct _WsbmBufferPool *pool; 80 }; 81 82 struct _WsbmBufferList 83 { 84 int hasKernelBuffers; 85 86 struct _ValidateList kernelBuffers; /* List of kernel buffers needing validation */ 87 struct _ValidateList userBuffers; /* List of user-space buffers needing validation */ 88 }; 89 90 static struct _WsbmMutex bmMutex; 91 static struct _WsbmCond bmCond; 92 static int initialized = 0; 93 static void *commonData = NULL; 94 95 static int kernelReaders = 0; 96 static int kernelLocked = 0; 97 98 int 99 wsbmInit(struct _WsbmThreadFuncs *tf, struct _WsbmVNodeFuncs *vf) 100 { 101 int ret; 102 103 wsbmCurThreadFunc = tf; 104 wsbmCurVNodeFunc = vf; 105 106 ret = WSBM_MUTEX_INIT(&bmMutex); 107 if (ret) 108 return -ENOMEM; 109 ret = WSBM_COND_INIT(&bmCond); 110 if (ret) { 111 WSBM_MUTEX_FREE(&bmMutex); 112 return -ENOMEM; 113 } 114 115 initialized = 1; 116 return 0; 117 } 118 119 void 120 wsbmCommonDataSet(void *d) 121 { 122 commonData = d; 123 } 124 125 void * 126 wsbmCommonDataGet(void) 127 { 128 return commonData; 129 } 130 131 int 132 wsbmIsInitialized(void) 133 { 134 return initialized; 135 } 136 137 void 138 wsbmTakedown(void) 139 { 140 initialized = 0; 141 commonData = NULL; 142 WSBM_COND_FREE(&bmCond); 143 WSBM_MUTEX_FREE(&bmMutex); 144 } 145 146 static struct _ValidateNode * 147 validateListAddNode(struct _ValidateList *list, void *item, 148 uint32_t hash, uint64_t flags, uint64_t mask) 149 { 150 struct _ValidateNode *node; 151 struct _WsbmListHead *l; 152 struct _WsbmListHead *hashHead; 153 154 l = list->free.next; 155 if (l == &list->free) { 156 node = wsbmVNodeFuncs()->alloc(wsbmVNodeFuncs(), 0); 157 if (!node) { 158 return NULL; 159 } 160 list->numCurrent++; 161 } else { 162 WSBMLISTDEL(l); 163 node = WSBMLISTENTRY(l, struct _ValidateNode, head); 164 } 165 node->buf = item; 166 node->set_flags = flags & mask; 167 node->clr_flags = (~flags) & mask; 168 node->listItem = list->numOnList; 169 WSBMLISTADDTAIL(&node->head, &list->list); 170 list->numOnList++; 171 hashHead = list->hashTable + hash; 172 WSBMLISTADDTAIL(&node->hashHead, hashHead); 173 174 return node; 175 } 176 177 static uint32_t 178 wsbmHashFunc(uint8_t * key, uint32_t len, uint32_t mask) 179 { 180 uint32_t hash, i; 181 182 for (hash = 0, i = 0; i < len; ++i) { 183 hash += *key++; 184 hash += (hash << 10); 185 hash ^= (hash >> 6); 186 } 187 188 hash += (hash << 3); 189 hash ^= (hash >> 11); 190 hash += (hash << 15); 191 192 return hash & mask; 193 } 194 195 static void 196 validateFreeList(struct _ValidateList *list) 197 { 198 struct _ValidateNode *node; 199 struct _WsbmListHead *l; 200 201 l = list->list.next; 202 while (l != &list->list) { 203 WSBMLISTDEL(l); 204 node = WSBMLISTENTRY(l, struct _ValidateNode, head); 205 206 WSBMLISTDEL(&node->hashHead); 207 node->func->free(node); 208 l = list->list.next; 209 list->numCurrent--; 210 list->numOnList--; 211 } 212 213 l = list->free.next; 214 while (l != &list->free) { 215 WSBMLISTDEL(l); 216 node = WSBMLISTENTRY(l, struct _ValidateNode, head); 217 218 node->func->free(node); 219 l = list->free.next; 220 list->numCurrent--; 221 } 222 free(list->hashTable); 223 } 224 225 static int 226 validateListAdjustNodes(struct _ValidateList *list) 227 { 228 struct _ValidateNode *node; 229 struct _WsbmListHead *l; 230 int ret = 0; 231 232 while (list->numCurrent < list->numTarget) { 233 node = wsbmVNodeFuncs()->alloc(wsbmVNodeFuncs(), list->driverData); 234 if (!node) { 235 ret = -ENOMEM; 236 break; 237 } 238 list->numCurrent++; 239 WSBMLISTADD(&node->head, &list->free); 240 } 241 242 while (list->numCurrent > list->numTarget) { 243 l = list->free.next; 244 if (l == &list->free) 245 break; 246 WSBMLISTDEL(l); 247 node = WSBMLISTENTRY(l, struct _ValidateNode, head); 248 249 node->func->free(node); 250 list->numCurrent--; 251 } 252 return ret; 253 } 254 255 static inline int 256 wsbmPot(unsigned int val) 257 { 258 unsigned int shift = 0; 259 while(val > (unsigned int)(1 << shift)) 260 shift++; 261 262 return shift; 263 } 264 265 266 267 static int 268 validateCreateList(int numTarget, struct _ValidateList *list, int driverData) 269 { 270 unsigned int i; 271 unsigned int shift = wsbmPot(numTarget); 272 int ret; 273 274 list->hashSize = (1 << shift); 275 list->hashMask = list->hashSize - 1; 276 277 list->hashTable = malloc(list->hashSize * sizeof(*list->hashTable)); 278 if (!list->hashTable) 279 return -ENOMEM; 280 281 for (i = 0; i < list->hashSize; ++i) 282 WSBMINITLISTHEAD(&list->hashTable[i]); 283 284 WSBMINITLISTHEAD(&list->list); 285 WSBMINITLISTHEAD(&list->free); 286 list->numTarget = numTarget; 287 list->numCurrent = 0; 288 list->numOnList = 0; 289 list->driverData = driverData; 290 ret = validateListAdjustNodes(list); 291 if (ret != 0) 292 free(list->hashTable); 293 294 return ret; 295 } 296 297 static int 298 validateResetList(struct _ValidateList *list) 299 { 300 struct _WsbmListHead *l; 301 struct _ValidateNode *node; 302 int ret; 303 304 ret = validateListAdjustNodes(list); 305 if (ret) 306 return ret; 307 308 l = list->list.next; 309 while (l != &list->list) { 310 WSBMLISTDEL(l); 311 node = WSBMLISTENTRY(l, struct _ValidateNode, head); 312 313 WSBMLISTDEL(&node->hashHead); 314 WSBMLISTADD(l, &list->free); 315 list->numOnList--; 316 l = list->list.next; 317 } 318 return validateListAdjustNodes(list); 319 } 320 321 void 322 wsbmWriteLockKernelBO(void) 323 { 324 WSBM_MUTEX_LOCK(&bmMutex); 325 while (kernelReaders != 0) 326 WSBM_COND_WAIT(&bmCond, &bmMutex); 327 kernelLocked = 1; 328 } 329 330 void 331 wsbmWriteUnlockKernelBO(void) 332 { 333 kernelLocked = 0; 334 WSBM_MUTEX_UNLOCK(&bmMutex); 335 } 336 337 void 338 wsbmReadLockKernelBO(void) 339 { 340 WSBM_MUTEX_LOCK(&bmMutex); 341 if (kernelReaders++ == 0) 342 kernelLocked = 1; 343 WSBM_MUTEX_UNLOCK(&bmMutex); 344 } 345 346 void 347 wsbmReadUnlockKernelBO(void) 348 { 349 WSBM_MUTEX_LOCK(&bmMutex); 350 if (--kernelReaders == 0) { 351 kernelLocked = 0; 352 WSBM_COND_BROADCAST(&bmCond); 353 } 354 WSBM_MUTEX_UNLOCK(&bmMutex); 355 } 356 357 void 358 wsbmBOWaitIdle(struct _WsbmBufferObject *buf, int lazy) 359 { 360 struct _WsbmBufStorage *storage; 361 362 storage = buf->storage; 363 if (!storage) 364 return; 365 366 (void)storage->pool->waitIdle(storage, lazy); 367 } 368 369 void * 370 wsbmBOMap(struct _WsbmBufferObject *buf, unsigned mode) 371 { 372 struct _WsbmBufStorage *storage = buf->storage; 373 void *virtual; 374 int retval; 375 376 retval = storage->pool->map(storage, mode, &virtual); 377 378 return (retval == 0) ? virtual : NULL; 379 } 380 381 void 382 wsbmBOUnmap(struct _WsbmBufferObject *buf) 383 { 384 struct _WsbmBufStorage *storage = buf->storage; 385 386 if (!storage) 387 return; 388 389 storage->pool->unmap(storage); 390 } 391 392 int 393 wsbmBOSyncForCpu(struct _WsbmBufferObject *buf, unsigned mode) 394 { 395 struct _WsbmBufStorage *storage = buf->storage; 396 397 return storage->pool->syncforcpu(storage, mode); 398 } 399 400 void 401 wsbmBOReleaseFromCpu(struct _WsbmBufferObject *buf, unsigned mode) 402 { 403 struct _WsbmBufStorage *storage = buf->storage; 404 405 storage->pool->releasefromcpu(storage, mode); 406 } 407 408 unsigned long 409 wsbmBOOffsetHint(struct _WsbmBufferObject *buf) 410 { 411 struct _WsbmBufStorage *storage = buf->storage; 412 413 return storage->pool->offset(storage); 414 } 415 416 unsigned long 417 wsbmBOPoolOffset(struct _WsbmBufferObject *buf) 418 { 419 struct _WsbmBufStorage *storage = buf->storage; 420 421 return storage->pool->poolOffset(storage); 422 } 423 424 uint32_t 425 wsbmBOPlacementHint(struct _WsbmBufferObject * buf) 426 { 427 struct _WsbmBufStorage *storage = buf->storage; 428 429 assert(buf->storage != NULL); 430 431 return storage->pool->placement(storage); 432 } 433 434 struct _WsbmBufferObject * 435 wsbmBOReference(struct _WsbmBufferObject *buf) 436 { 437 if (buf->bufferType == WSBM_BUFFER_SIMPLE) { 438 wsbmAtomicInc(&buf->storage->refCount); 439 } else { 440 wsbmAtomicInc(&buf->refCount); 441 } 442 return buf; 443 } 444 445 int 446 wsbmBOSetStatus(struct _WsbmBufferObject *buf, 447 uint32_t setFlags, uint32_t clrFlags) 448 { 449 struct _WsbmBufStorage *storage = buf->storage; 450 451 if (!storage) 452 return 0; 453 454 if (storage->pool->setStatus == NULL) 455 return -EINVAL; 456 457 return storage->pool->setStatus(storage, setFlags, clrFlags); 458 } 459 460 void 461 wsbmBOUnreference(struct _WsbmBufferObject **p_buf) 462 { 463 struct _WsbmBufferObject *buf = *p_buf; 464 465 *p_buf = NULL; 466 467 if (!buf) 468 return; 469 470 if (buf->bufferType == WSBM_BUFFER_SIMPLE) { 471 struct _WsbmBufStorage *dummy = buf->storage; 472 473 wsbmBufStorageUnref(&dummy); 474 return; 475 } 476 477 if (wsbmAtomicDecZero(&buf->refCount)) { 478 wsbmBufStorageUnref(&buf->storage); 479 free(buf); 480 } 481 } 482 483 int 484 wsbmBOData(struct _WsbmBufferObject *buf, 485 unsigned size, const void *data, 486 struct _WsbmBufferPool *newPool, uint32_t placement) 487 { 488 void *virtual = NULL; 489 int newBuffer; 490 int retval = 0; 491 struct _WsbmBufStorage *storage; 492 int synced = 0; 493 uint32_t placement_diff; 494 struct _WsbmBufferPool *curPool; 495 496 if (buf->bufferType == WSBM_BUFFER_SIMPLE) 497 return -EINVAL; 498 499 storage = buf->storage; 500 501 if (newPool == NULL) 502 newPool = buf->pool; 503 504 if (newPool == NULL) 505 return -EINVAL; 506 507 newBuffer = (!storage || storage->pool != newPool || 508 storage->pool->size(storage) < size || 509 storage->pool->size(storage) > 510 size + WSBM_BODATA_SIZE_ACCEPT); 511 512 if (!placement) 513 placement = buf->placement; 514 515 if (newBuffer) { 516 if (buf->bufferType == WSBM_BUFFER_REF) 517 return -EINVAL; 518 519 wsbmBufStorageUnref(&buf->storage); 520 521 if (size == 0) { 522 buf->pool = newPool; 523 buf->placement = placement; 524 retval = 0; 525 goto out; 526 } 527 528 buf->storage = 529 newPool->create(newPool, size, placement, buf->alignment); 530 if (!buf->storage) { 531 retval = -ENOMEM; 532 goto out; 533 } 534 535 buf->placement = placement; 536 buf->pool = newPool; 537 } else if (wsbmAtomicRead(&storage->onList) || 538 0 != storage->pool->syncforcpu(storage, WSBM_SYNCCPU_WRITE | 539 WSBM_SYNCCPU_DONT_BLOCK)) { 540 /* 541 * Buffer is busy. need to create a new one. 542 */ 543 544 struct _WsbmBufStorage *tmp_storage; 545 546 curPool = storage->pool; 547 548 tmp_storage = 549 curPool->create(curPool, size, placement, buf->alignment); 550 551 if (tmp_storage) { 552 wsbmBufStorageUnref(&buf->storage); 553 buf->storage = tmp_storage; 554 buf->placement = placement; 555 } else { 556 retval = curPool->syncforcpu(storage, WSBM_SYNCCPU_WRITE); 557 if (retval) 558 goto out; 559 synced = 1; 560 } 561 } else 562 synced = 1; 563 564 placement_diff = placement ^ buf->placement; 565 566 /* 567 * We might need to change buffer placement. 568 */ 569 570 storage = buf->storage; 571 curPool = storage->pool; 572 573 if (placement_diff) { 574 assert(curPool->setStatus != NULL); 575 curPool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); 576 retval = curPool->setStatus(storage, 577 placement_diff & placement, 578 placement_diff & ~placement); 579 if (retval) 580 goto out; 581 582 buf->placement = placement; 583 584 } 585 586 if (!synced) { 587 retval = curPool->syncforcpu(buf->storage, WSBM_SYNCCPU_WRITE); 588 589 if (retval) 590 goto out; 591 synced = 1; 592 } 593 594 storage = buf->storage; 595 curPool = storage->pool; 596 597 if (data) { 598 retval = curPool->map(storage, WSBM_ACCESS_WRITE, &virtual); 599 if (retval) 600 goto out; 601 memcpy(virtual, data, size); 602 curPool->unmap(storage); 603 } 604 605 out: 606 607 if (synced) 608 curPool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); 609 610 return retval; 611 } 612 613 int 614 wsbmBODataUB(struct _WsbmBufferObject *buf, 615 unsigned size, const void *data, struct _WsbmBufferPool *newPool, 616 uint32_t placement, const unsigned long *user_ptr, int fd) 617 { 618 int newBuffer; 619 int retval = 0; 620 struct _WsbmBufStorage *storage; 621 int synced = 0; 622 uint32_t placement_diff; 623 struct _WsbmBufferPool *curPool; 624 extern struct _WsbmBufStorage * 625 ttm_pool_ub_create(struct _WsbmBufferPool *pool, 626 unsigned long size, uint32_t placement, unsigned alignment, 627 const unsigned long *user_ptr, int fd); 628 629 if (buf->bufferType == WSBM_BUFFER_SIMPLE) 630 return -EINVAL; 631 632 storage = buf->storage; 633 634 if (newPool == NULL) 635 newPool = buf->pool; 636 637 if (newPool == NULL) 638 return -EINVAL; 639 640 newBuffer = (!storage || storage->pool != newPool || 641 storage->pool->size(storage) < size || 642 storage->pool->size(storage) > 643 size + WSBM_BODATA_SIZE_ACCEPT); 644 645 if (!placement) 646 placement = buf->placement; 647 648 if (newBuffer) { 649 if (buf->bufferType == WSBM_BUFFER_REF) 650 return -EINVAL; 651 652 wsbmBufStorageUnref(&buf->storage); 653 654 if (size == 0) { 655 buf->pool = newPool; 656 buf->placement = placement; 657 retval = 0; 658 goto out; 659 } 660 661 buf->storage = 662 ttm_pool_ub_create(newPool, size, placement, buf->alignment, user_ptr, fd); 663 if (!buf->storage) { 664 retval = -ENOMEM; 665 goto out; 666 } 667 668 buf->placement = placement; 669 buf->pool = newPool; 670 } else if (wsbmAtomicRead(&storage->onList) || 671 0 != storage->pool->syncforcpu(storage, WSBM_SYNCCPU_WRITE | 672 WSBM_SYNCCPU_DONT_BLOCK)) { 673 /* 674 * Buffer is busy. need to create a new one. 675 * Actually such case will not be encountered for current ICS implementation 676 * TODO: maybe need refine the following code when such usage case is required 677 */ 678 679 struct _WsbmBufStorage *tmp_storage; 680 681 curPool = storage->pool; 682 683 tmp_storage = 684 ttm_pool_ub_create(curPool, size, placement, buf->alignment, user_ptr, fd); 685 686 if (tmp_storage) { 687 wsbmBufStorageUnref(&buf->storage); 688 buf->storage = tmp_storage; 689 buf->placement = placement; 690 } else { 691 retval = curPool->syncforcpu(storage, WSBM_SYNCCPU_WRITE); 692 if (retval) 693 goto out; 694 synced = 1; 695 } 696 } else { 697 synced = 1; 698 } 699 700 placement_diff = placement ^ buf->placement; 701 702 /* 703 * We might need to change buffer placement. 704 */ 705 706 storage = buf->storage; 707 curPool = storage->pool; 708 709 if (placement_diff) { 710 assert(curPool->setStatus != NULL); 711 curPool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); 712 retval = curPool->setStatus(storage, 713 placement_diff & placement, 714 placement_diff & ~placement); 715 if (retval) 716 goto out; 717 718 buf->placement = placement; 719 } 720 721 if (!synced) { 722 retval = curPool->syncforcpu(buf->storage, WSBM_SYNCCPU_WRITE); 723 if (retval) 724 goto out; 725 synced = 1; 726 } 727 728 storage = buf->storage; 729 curPool = storage->pool; 730 731 if (data) { 732 memcpy((unsigned long *) user_ptr, data, size); 733 } 734 735 out: 736 737 if (synced) 738 curPool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); 739 740 return retval; 741 } 742 743 static struct _WsbmBufStorage * 744 wsbmStorageClone(struct _WsbmBufferObject *buf) 745 { 746 struct _WsbmBufStorage *storage = buf->storage; 747 struct _WsbmBufferPool *pool = storage->pool; 748 749 return pool->create(pool, pool->size(storage), buf->placement, 750 buf->alignment); 751 } 752 753 struct _WsbmBufferObject * 754 wsbmBOClone(struct _WsbmBufferObject *buf, 755 int (*accelCopy) (struct _WsbmBufferObject *, 756 struct _WsbmBufferObject *)) 757 { 758 struct _WsbmBufferObject *newBuf; 759 int ret; 760 761 newBuf = malloc(sizeof(*newBuf)); 762 if (!newBuf) 763 return NULL; 764 765 *newBuf = *buf; 766 newBuf->storage = wsbmStorageClone(buf); 767 if (!newBuf->storage) 768 goto out_err0; 769 770 wsbmAtomicSet(&newBuf->refCount, 1); 771 if (!accelCopy || accelCopy(newBuf, buf) != 0) { 772 773 struct _WsbmBufferPool *pool = buf->storage->pool; 774 struct _WsbmBufStorage *storage = buf->storage; 775 struct _WsbmBufStorage *newStorage = newBuf->storage; 776 void *virtual; 777 void *nVirtual; 778 779 ret = pool->syncforcpu(storage, WSBM_SYNCCPU_READ); 780 if (ret) 781 goto out_err1; 782 ret = pool->map(storage, WSBM_ACCESS_READ, &virtual); 783 if (ret) 784 goto out_err2; 785 ret = pool->map(newStorage, WSBM_ACCESS_WRITE, &nVirtual); 786 if (ret) 787 goto out_err3; 788 789 memcpy(nVirtual, virtual, pool->size(storage)); 790 pool->unmap(newBuf->storage); 791 pool->unmap(buf->storage); 792 pool->releasefromcpu(storage, WSBM_SYNCCPU_READ); 793 } 794 795 return newBuf; 796 out_err3: 797 buf->pool->unmap(buf->storage); 798 out_err2: 799 buf->pool->releasefromcpu(buf->storage, WSBM_SYNCCPU_READ); 800 out_err1: 801 wsbmBufStorageUnref(&newBuf->storage); 802 out_err0: 803 free(newBuf); 804 return 0; 805 } 806 807 int 808 wsbmBOSubData(struct _WsbmBufferObject *buf, 809 unsigned long offset, unsigned long size, const void *data, 810 int (*accelCopy) (struct _WsbmBufferObject *, 811 struct _WsbmBufferObject *)) 812 { 813 int ret = 0; 814 815 if (buf->bufferType == WSBM_BUFFER_SIMPLE) 816 return -EINVAL; 817 818 if (size && data) { 819 void *virtual; 820 struct _WsbmBufStorage *storage = buf->storage; 821 struct _WsbmBufferPool *pool = storage->pool; 822 823 ret = pool->syncforcpu(storage, WSBM_SYNCCPU_WRITE); 824 if (ret) 825 goto out; 826 827 if (wsbmAtomicRead(&storage->onList)) { 828 829 struct _WsbmBufferObject *newBuf; 830 831 /* 832 * Another context has this buffer on its validate list. 833 * This should be a very rare situation, but it can be valid, 834 * and therefore we must deal with it by cloning the storage. 835 */ 836 837 pool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); 838 newBuf = wsbmBOClone(buf, accelCopy); 839 840 /* 841 * If clone fails we have the choice of either bailing. 842 * (The other context will be happy), or go on and update 843 * the old buffer anyway. (We will be happy). We choose the 844 * latter. 845 */ 846 847 if (newBuf) { 848 storage = newBuf->storage; 849 wsbmAtomicInc(&storage->refCount); 850 wsbmBufStorageUnref(&buf->storage); 851 buf->storage = storage; 852 wsbmBOUnreference(&newBuf); 853 pool = storage->pool; 854 } 855 856 ret = pool->syncforcpu(storage, WSBM_SYNCCPU_WRITE); 857 if (ret) 858 goto out; 859 } 860 861 ret = pool->map(storage, WSBM_ACCESS_WRITE, &virtual); 862 if (ret) { 863 pool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); 864 goto out; 865 } 866 867 memcpy((unsigned char *)virtual + offset, data, size); 868 pool->unmap(storage); 869 pool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); 870 } 871 out: 872 return ret; 873 } 874 875 int 876 wsbmBOGetSubData(struct _WsbmBufferObject *buf, 877 unsigned long offset, unsigned long size, void *data) 878 { 879 int ret = 0; 880 881 if (size && data) { 882 void *virtual; 883 struct _WsbmBufStorage *storage = buf->storage; 884 struct _WsbmBufferPool *pool = storage->pool; 885 886 ret = pool->syncforcpu(storage, WSBM_SYNCCPU_READ); 887 if (ret) 888 goto out; 889 ret = pool->map(storage, WSBM_ACCESS_READ, &virtual); 890 if (ret) { 891 pool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); 892 goto out; 893 } 894 memcpy(data, (unsigned char *)virtual + offset, size); 895 pool->unmap(storage); 896 pool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE); 897 } 898 out: 899 return ret; 900 } 901 902 int 903 wsbmBOSetReferenced(struct _WsbmBufferObject *buf, unsigned long handle) 904 { 905 int ret = 0; 906 907 wsbmBufStorageUnref(&buf->storage); 908 if (buf->pool->createByReference == NULL) { 909 ret = -EINVAL; 910 goto out; 911 } 912 buf->storage = buf->pool->createByReference(buf->pool, handle); 913 if (!buf->storage) { 914 ret = -EINVAL; 915 goto out; 916 } 917 buf->bufferType = WSBM_BUFFER_REF; 918 out: 919 return ret; 920 } 921 922 void 923 wsbmBOFreeSimple(void *ptr) 924 { 925 free(ptr); 926 } 927 928 struct _WsbmBufferObject * 929 wsbmBOCreateSimple(struct _WsbmBufferPool *pool, 930 unsigned long size, 931 uint32_t placement, 932 unsigned alignment, size_t extra_size, size_t * offset) 933 { 934 struct _WsbmBufferObject *buf; 935 struct _WsbmBufStorage *storage; 936 937 *offset = (sizeof(*buf) + 15) & ~15; 938 939 if (extra_size) { 940 extra_size += *offset - sizeof(*buf); 941 } 942 943 buf = (struct _WsbmBufferObject *)calloc(1, sizeof(*buf) + extra_size); 944 if (!buf) 945 return NULL; 946 947 storage = pool->create(pool, size, placement, alignment); 948 if (!storage) 949 goto out_err0; 950 951 storage->destroyContainer = &wsbmBOFreeSimple; 952 storage->destroyArg = buf; 953 954 buf->storage = storage; 955 buf->alignment = alignment; 956 buf->pool = pool; 957 buf->placement = placement; 958 buf->bufferType = WSBM_BUFFER_SIMPLE; 959 960 return buf; 961 962 out_err0: 963 free(buf); 964 return NULL; 965 } 966 967 int 968 wsbmGenBuffers(struct _WsbmBufferPool *pool, 969 unsigned n, 970 struct _WsbmBufferObject *buffers[], 971 unsigned alignment, uint32_t placement) 972 { 973 struct _WsbmBufferObject *buf; 974 unsigned int i; 975 976 placement = (placement) ? placement : 977 WSBM_PL_FLAG_SYSTEM | WSBM_PL_FLAG_CACHED; 978 979 for (i = 0; i < n; ++i) { 980 buf = (struct _WsbmBufferObject *)calloc(1, sizeof(*buf)); 981 if (!buf) 982 return -ENOMEM; 983 984 wsbmAtomicSet(&buf->refCount, 1); 985 buf->placement = placement; 986 buf->alignment = alignment; 987 buf->pool = pool; 988 buf->bufferType = WSBM_BUFFER_COMPLEX; 989 buffers[i] = buf; 990 } 991 return 0; 992 } 993 994 void 995 wsbmDeleteBuffers(unsigned n, struct _WsbmBufferObject *buffers[]) 996 { 997 unsigned int i; 998 999 for (i = 0; i < n; ++i) { 1000 wsbmBOUnreference(&buffers[i]); 1001 } 1002 } 1003 1004 /* 1005 * Note that lists are per-context and don't need mutex protection. 1006 */ 1007 1008 struct _WsbmBufferList * 1009 wsbmBOCreateList(int target, int hasKernelBuffers) 1010 { 1011 struct _WsbmBufferList *list = calloc(sizeof(*list), 1); 1012 int ret; 1013 1014 if (!list) 1015 return NULL; 1016 list->hasKernelBuffers = hasKernelBuffers; 1017 if (hasKernelBuffers) { 1018 ret = validateCreateList(target, &list->kernelBuffers, 0); 1019 if (ret) 1020 return NULL; 1021 } 1022 1023 ret = validateCreateList(target, &list->userBuffers, 1); 1024 if (ret) { 1025 validateFreeList(&list->kernelBuffers); 1026 return NULL; 1027 } 1028 1029 return list; 1030 } 1031 1032 int 1033 wsbmBOResetList(struct _WsbmBufferList *list) 1034 { 1035 int ret; 1036 1037 if (list->hasKernelBuffers) { 1038 ret = validateResetList(&list->kernelBuffers); 1039 if (ret) 1040 return ret; 1041 } 1042 ret = validateResetList(&list->userBuffers); 1043 return ret; 1044 } 1045 1046 void 1047 wsbmBOFreeList(struct _WsbmBufferList *list) 1048 { 1049 if (list->hasKernelBuffers) 1050 validateFreeList(&list->kernelBuffers); 1051 validateFreeList(&list->userBuffers); 1052 free(list); 1053 } 1054 1055 static int 1056 wsbmAddValidateItem(struct _ValidateList *list, void *buf, uint64_t flags, 1057 uint64_t mask, int *itemLoc, 1058 struct _ValidateNode **pnode, int *newItem) 1059 { 1060 struct _ValidateNode *node, *cur; 1061 struct _WsbmListHead *l; 1062 struct _WsbmListHead *hashHead; 1063 uint32_t hash; 1064 uint32_t count = 0; 1065 uint32_t key = (unsigned long) buf; 1066 1067 cur = NULL; 1068 hash = wsbmHashFunc((uint8_t *) &key, 4, list->hashMask); 1069 hashHead = list->hashTable + hash; 1070 *newItem = 0; 1071 1072 for (l = hashHead->next; l != hashHead; l = l->next) { 1073 count++; 1074 node = WSBMLISTENTRY(l, struct _ValidateNode, hashHead); 1075 1076 if (node->buf == buf) { 1077 cur = node; 1078 break; 1079 } 1080 } 1081 1082 if (!cur) { 1083 cur = validateListAddNode(list, buf, hash, flags, mask); 1084 if (!cur) 1085 return -ENOMEM; 1086 *newItem = 1; 1087 cur->func->clear(cur); 1088 } else { 1089 uint64_t set_flags = flags & mask; 1090 uint64_t clr_flags = (~flags) & mask; 1091 1092 if (((cur->clr_flags | clr_flags) & WSBM_PL_MASK_MEM) == 1093 WSBM_PL_MASK_MEM) { 1094 /* 1095 * No available memory type left. Bail. 1096 */ 1097 return -EINVAL; 1098 } 1099 1100 if ((cur->set_flags | set_flags) & 1101 (cur->clr_flags | clr_flags) & ~WSBM_PL_MASK_MEM) { 1102 /* 1103 * Conflicting flags. Bail. 1104 */ 1105 return -EINVAL; 1106 } 1107 1108 cur->set_flags &= ~(clr_flags & WSBM_PL_MASK_MEM); 1109 cur->set_flags |= (set_flags & ~WSBM_PL_MASK_MEM); 1110 cur->clr_flags |= clr_flags; 1111 } 1112 *itemLoc = cur->listItem; 1113 if (pnode) 1114 *pnode = cur; 1115 return 0; 1116 } 1117 1118 int 1119 wsbmBOAddListItem(struct _WsbmBufferList *list, 1120 struct _WsbmBufferObject *buf, 1121 uint64_t flags, uint64_t mask, int *itemLoc, 1122 struct _ValidateNode **node) 1123 { 1124 int newItem; 1125 struct _WsbmBufStorage *storage = buf->storage; 1126 int ret; 1127 int dummy; 1128 struct _ValidateNode *dummyNode; 1129 1130 if (list->hasKernelBuffers) { 1131 ret = wsbmAddValidateItem(&list->kernelBuffers, 1132 storage->pool->kernel(storage), 1133 flags, mask, itemLoc, node, &dummy); 1134 if (ret) 1135 goto out_unlock; 1136 } else { 1137 *node = NULL; 1138 *itemLoc = -1000; 1139 } 1140 1141 ret = wsbmAddValidateItem(&list->userBuffers, storage, 1142 flags, mask, &dummy, &dummyNode, &newItem); 1143 if (ret) 1144 goto out_unlock; 1145 1146 if (newItem) { 1147 wsbmAtomicInc(&storage->refCount); 1148 wsbmAtomicInc(&storage->onList); 1149 } 1150 1151 out_unlock: 1152 return ret; 1153 } 1154 1155 void 1156 wsbmBOFence(struct _WsbmBufferObject *buf, struct _WsbmFenceObject *fence) 1157 { 1158 struct _WsbmBufStorage *storage; 1159 1160 storage = buf->storage; 1161 if (storage->pool->fence) 1162 storage->pool->fence(storage, fence); 1163 1164 } 1165 1166 int 1167 wsbmBOOnList(const struct _WsbmBufferObject *buf) 1168 { 1169 if (buf->storage == NULL) 1170 return 0; 1171 return wsbmAtomicRead(&buf->storage->onList); 1172 } 1173 1174 int 1175 wsbmBOUnrefUserList(struct _WsbmBufferList *list) 1176 { 1177 struct _WsbmBufStorage *storage; 1178 void *curBuf; 1179 1180 curBuf = validateListIterator(&list->userBuffers); 1181 1182 while (curBuf) { 1183 storage = (struct _WsbmBufStorage *)(validateListNode(curBuf)->buf); 1184 wsbmAtomicDec(&storage->onList); 1185 wsbmBufStorageUnref(&storage); 1186 curBuf = validateListNext(&list->userBuffers, curBuf); 1187 } 1188 1189 return wsbmBOResetList(list); 1190 } 1191 1192 1193 int 1194 wsbmBOFenceUserList(struct _WsbmBufferList *list, 1195 struct _WsbmFenceObject *fence) 1196 { 1197 struct _WsbmBufStorage *storage; 1198 void *curBuf; 1199 1200 curBuf = validateListIterator(&list->userBuffers); 1201 1202 /* 1203 * User-space fencing callbacks. 1204 */ 1205 1206 while (curBuf) { 1207 storage = (struct _WsbmBufStorage *)(validateListNode(curBuf)->buf); 1208 1209 storage->pool->fence(storage, fence); 1210 wsbmAtomicDec(&storage->onList); 1211 wsbmBufStorageUnref(&storage); 1212 curBuf = validateListNext(&list->userBuffers, curBuf); 1213 } 1214 1215 return wsbmBOResetList(list); 1216 } 1217 1218 int 1219 wsbmBOValidateUserList(struct _WsbmBufferList *list) 1220 { 1221 void *curBuf; 1222 struct _WsbmBufStorage *storage; 1223 struct _ValidateNode *node; 1224 int ret; 1225 1226 curBuf = validateListIterator(&list->userBuffers); 1227 1228 /* 1229 * User-space validation callbacks. 1230 */ 1231 1232 while (curBuf) { 1233 node = validateListNode(curBuf); 1234 storage = (struct _WsbmBufStorage *)node->buf; 1235 if (storage->pool->validate) { 1236 ret = storage->pool->validate(storage, node->set_flags, 1237 node->clr_flags); 1238 if (ret) 1239 return ret; 1240 } 1241 curBuf = validateListNext(&list->userBuffers, curBuf); 1242 } 1243 return 0; 1244 } 1245 1246 int 1247 wsbmBOUnvalidateUserList(struct _WsbmBufferList *list) 1248 { 1249 void *curBuf; 1250 struct _WsbmBufStorage *storage; 1251 struct _ValidateNode *node; 1252 1253 curBuf = validateListIterator(&list->userBuffers); 1254 1255 /* 1256 * User-space validation callbacks. 1257 */ 1258 1259 while (curBuf) { 1260 node = validateListNode(curBuf); 1261 storage = (struct _WsbmBufStorage *)node->buf; 1262 if (storage->pool->unvalidate) { 1263 storage->pool->unvalidate(storage); 1264 } 1265 wsbmAtomicDec(&storage->onList); 1266 wsbmBufStorageUnref(&storage); 1267 curBuf = validateListNext(&list->userBuffers, curBuf); 1268 } 1269 return wsbmBOResetList(list); 1270 } 1271 1272 void 1273 wsbmPoolTakeDown(struct _WsbmBufferPool *pool) 1274 { 1275 pool->takeDown(pool); 1276 1277 } 1278 1279 unsigned long 1280 wsbmBOSize(struct _WsbmBufferObject *buf) 1281 { 1282 unsigned long size; 1283 struct _WsbmBufStorage *storage; 1284 1285 storage = buf->storage; 1286 size = storage->pool->size(storage); 1287 1288 return size; 1289 1290 } 1291 1292 struct _ValidateList * 1293 wsbmGetKernelValidateList(struct _WsbmBufferList *list) 1294 { 1295 return (list->hasKernelBuffers) ? &list->kernelBuffers : NULL; 1296 } 1297 1298 struct _ValidateList * 1299 wsbmGetUserValidateList(struct _WsbmBufferList *list) 1300 { 1301 return &list->userBuffers; 1302 } 1303 1304 struct _ValidateNode * 1305 validateListNode(void *iterator) 1306 { 1307 struct _WsbmListHead *l = (struct _WsbmListHead *)iterator; 1308 1309 return WSBMLISTENTRY(l, struct _ValidateNode, head); 1310 } 1311 1312 void * 1313 validateListIterator(struct _ValidateList *list) 1314 { 1315 void *ret = list->list.next; 1316 1317 if (ret == &list->list) 1318 return NULL; 1319 return ret; 1320 } 1321 1322 void * 1323 validateListNext(struct _ValidateList *list, void *iterator) 1324 { 1325 void *ret; 1326 1327 struct _WsbmListHead *l = (struct _WsbmListHead *)iterator; 1328 1329 ret = l->next; 1330 if (ret == &list->list) 1331 return NULL; 1332 return ret; 1333 } 1334 1335 uint32_t 1336 wsbmKBufHandle(const struct _WsbmKernelBuf * kBuf) 1337 { 1338 return kBuf->handle; 1339 } 1340 1341 extern void 1342 wsbmUpdateKBuf(struct _WsbmKernelBuf *kBuf, 1343 uint64_t gpuOffset, uint32_t placement, 1344 uint32_t fence_type_mask) 1345 { 1346 kBuf->gpuOffset = gpuOffset; 1347 kBuf->placement = placement; 1348 kBuf->fence_type_mask = fence_type_mask; 1349 } 1350 1351 extern struct _WsbmKernelBuf * 1352 wsbmKBuf(const struct _WsbmBufferObject *buf) 1353 { 1354 struct _WsbmBufStorage *storage = buf->storage; 1355 1356 return storage->pool->kernel(storage); 1357 } 1358