Home | History | Annotate | Download | only in src
      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             free(list);
   1021             return NULL;
   1022         }
   1023     }
   1024 
   1025     ret = validateCreateList(target, &list->userBuffers, 1);
   1026     if (ret) {
   1027         validateFreeList(&list->kernelBuffers);
   1028         free(list);
   1029         return NULL;
   1030     }
   1031 
   1032     return list;
   1033 }
   1034 
   1035 int
   1036 wsbmBOResetList(struct _WsbmBufferList *list)
   1037 {
   1038     int ret;
   1039 
   1040     if (list->hasKernelBuffers) {
   1041 	ret = validateResetList(&list->kernelBuffers);
   1042 	if (ret)
   1043 	    return ret;
   1044     }
   1045     ret = validateResetList(&list->userBuffers);
   1046     return ret;
   1047 }
   1048 
   1049 void
   1050 wsbmBOFreeList(struct _WsbmBufferList *list)
   1051 {
   1052     if (list->hasKernelBuffers)
   1053 	validateFreeList(&list->kernelBuffers);
   1054     validateFreeList(&list->userBuffers);
   1055     free(list);
   1056 }
   1057 
   1058 static int
   1059 wsbmAddValidateItem(struct _ValidateList *list, void *buf, uint64_t flags,
   1060 		    uint64_t mask, int *itemLoc,
   1061 		    struct _ValidateNode **pnode, int *newItem)
   1062 {
   1063     struct _ValidateNode *node, *cur;
   1064     struct _WsbmListHead *l;
   1065     struct _WsbmListHead *hashHead;
   1066     uint32_t hash;
   1067     uint32_t count = 0;
   1068     uint32_t key = (unsigned long) buf;
   1069 
   1070     cur = NULL;
   1071     hash = wsbmHashFunc((uint8_t *) &key, 4, list->hashMask);
   1072     hashHead = list->hashTable + hash;
   1073     *newItem = 0;
   1074 
   1075     for (l = hashHead->next; l != hashHead; l = l->next) {
   1076         count++;
   1077 	node = WSBMLISTENTRY(l, struct _ValidateNode, hashHead);
   1078 
   1079 	if (node->buf == buf) {
   1080 	    cur = node;
   1081 	    break;
   1082 	}
   1083     }
   1084 
   1085     if (!cur) {
   1086 	cur = validateListAddNode(list, buf, hash, flags, mask);
   1087 	if (!cur)
   1088 	    return -ENOMEM;
   1089 	*newItem = 1;
   1090 	cur->func->clear(cur);
   1091     } else {
   1092 	uint64_t set_flags = flags & mask;
   1093 	uint64_t clr_flags = (~flags) & mask;
   1094 
   1095 	if (((cur->clr_flags | clr_flags) & WSBM_PL_MASK_MEM) ==
   1096 	    WSBM_PL_MASK_MEM) {
   1097 	    /*
   1098 	     * No available memory type left. Bail.
   1099 	     */
   1100 	    return -EINVAL;
   1101 	}
   1102 
   1103 	if ((cur->set_flags | set_flags) &
   1104 	    (cur->clr_flags | clr_flags) & ~WSBM_PL_MASK_MEM) {
   1105 	    /*
   1106 	     * Conflicting flags. Bail.
   1107 	     */
   1108 	    return -EINVAL;
   1109 	}
   1110 
   1111 	cur->set_flags &= ~(clr_flags & WSBM_PL_MASK_MEM);
   1112 	cur->set_flags |= (set_flags & ~WSBM_PL_MASK_MEM);
   1113 	cur->clr_flags |= clr_flags;
   1114     }
   1115     *itemLoc = cur->listItem;
   1116     if (pnode)
   1117 	*pnode = cur;
   1118     return 0;
   1119 }
   1120 
   1121 int
   1122 wsbmBOAddListItem(struct _WsbmBufferList *list,
   1123 		  struct _WsbmBufferObject *buf,
   1124 		  uint64_t flags, uint64_t mask, int *itemLoc,
   1125 		  struct _ValidateNode **node)
   1126 {
   1127     int newItem;
   1128     struct _WsbmBufStorage *storage = buf->storage;
   1129     int ret;
   1130     int dummy;
   1131     struct _ValidateNode *dummyNode;
   1132 
   1133     if (list->hasKernelBuffers) {
   1134 	ret = wsbmAddValidateItem(&list->kernelBuffers,
   1135 				  storage->pool->kernel(storage),
   1136 				  flags, mask, itemLoc, node, &dummy);
   1137 	if (ret)
   1138 	    goto out_unlock;
   1139     } else {
   1140 	*node = NULL;
   1141 	*itemLoc = -1000;
   1142     }
   1143 
   1144     ret = wsbmAddValidateItem(&list->userBuffers, storage,
   1145 			      flags, mask, &dummy, &dummyNode, &newItem);
   1146     if (ret)
   1147 	goto out_unlock;
   1148 
   1149     if (newItem) {
   1150 	wsbmAtomicInc(&storage->refCount);
   1151 	wsbmAtomicInc(&storage->onList);
   1152     }
   1153 
   1154   out_unlock:
   1155     return ret;
   1156 }
   1157 
   1158 void
   1159 wsbmBOFence(struct _WsbmBufferObject *buf, struct _WsbmFenceObject *fence)
   1160 {
   1161     struct _WsbmBufStorage *storage;
   1162 
   1163     storage = buf->storage;
   1164     if (storage->pool->fence)
   1165 	storage->pool->fence(storage, fence);
   1166 
   1167 }
   1168 
   1169 int
   1170 wsbmBOOnList(const struct _WsbmBufferObject *buf)
   1171 {
   1172     if (buf->storage == NULL)
   1173 	return 0;
   1174     return wsbmAtomicRead(&buf->storage->onList);
   1175 }
   1176 
   1177 int
   1178 wsbmBOUnrefUserList(struct _WsbmBufferList *list)
   1179 {
   1180     struct _WsbmBufStorage *storage;
   1181     void *curBuf;
   1182 
   1183     curBuf = validateListIterator(&list->userBuffers);
   1184 
   1185     while (curBuf) {
   1186 	storage = (struct _WsbmBufStorage *)(validateListNode(curBuf)->buf);
   1187 	wsbmAtomicDec(&storage->onList);
   1188 	wsbmBufStorageUnref(&storage);
   1189 	curBuf = validateListNext(&list->userBuffers, curBuf);
   1190     }
   1191 
   1192     return wsbmBOResetList(list);
   1193 }
   1194 
   1195 
   1196 int
   1197 wsbmBOFenceUserList(struct _WsbmBufferList *list,
   1198 		    struct _WsbmFenceObject *fence)
   1199 {
   1200     struct _WsbmBufStorage *storage;
   1201     void *curBuf;
   1202 
   1203     curBuf = validateListIterator(&list->userBuffers);
   1204 
   1205     /*
   1206      * User-space fencing callbacks.
   1207      */
   1208 
   1209     while (curBuf) {
   1210 	storage = (struct _WsbmBufStorage *)(validateListNode(curBuf)->buf);
   1211 
   1212 	storage->pool->fence(storage, fence);
   1213 	wsbmAtomicDec(&storage->onList);
   1214 	wsbmBufStorageUnref(&storage);
   1215 	curBuf = validateListNext(&list->userBuffers, curBuf);
   1216     }
   1217 
   1218     return wsbmBOResetList(list);
   1219 }
   1220 
   1221 int
   1222 wsbmBOValidateUserList(struct _WsbmBufferList *list)
   1223 {
   1224     void *curBuf;
   1225     struct _WsbmBufStorage *storage;
   1226     struct _ValidateNode *node;
   1227     int ret;
   1228 
   1229     curBuf = validateListIterator(&list->userBuffers);
   1230 
   1231     /*
   1232      * User-space validation callbacks.
   1233      */
   1234 
   1235     while (curBuf) {
   1236 	node = validateListNode(curBuf);
   1237 	storage = (struct _WsbmBufStorage *)node->buf;
   1238 	if (storage->pool->validate) {
   1239 	    ret = storage->pool->validate(storage, node->set_flags,
   1240 					  node->clr_flags);
   1241 	    if (ret)
   1242 		return ret;
   1243 	}
   1244 	curBuf = validateListNext(&list->userBuffers, curBuf);
   1245     }
   1246     return 0;
   1247 }
   1248 
   1249 int
   1250 wsbmBOUnvalidateUserList(struct _WsbmBufferList *list)
   1251 {
   1252     void *curBuf;
   1253     struct _WsbmBufStorage *storage;
   1254     struct _ValidateNode *node;
   1255 
   1256     curBuf = validateListIterator(&list->userBuffers);
   1257 
   1258     /*
   1259      * User-space validation callbacks.
   1260      */
   1261 
   1262     while (curBuf) {
   1263 	node = validateListNode(curBuf);
   1264 	storage = (struct _WsbmBufStorage *)node->buf;
   1265 	if (storage->pool->unvalidate) {
   1266 	    storage->pool->unvalidate(storage);
   1267 	}
   1268 	wsbmAtomicDec(&storage->onList);
   1269 	wsbmBufStorageUnref(&storage);
   1270 	curBuf = validateListNext(&list->userBuffers, curBuf);
   1271     }
   1272     return wsbmBOResetList(list);
   1273 }
   1274 
   1275 void
   1276 wsbmPoolTakeDown(struct _WsbmBufferPool *pool)
   1277 {
   1278     pool->takeDown(pool);
   1279 
   1280 }
   1281 
   1282 unsigned long
   1283 wsbmBOSize(struct _WsbmBufferObject *buf)
   1284 {
   1285     unsigned long size;
   1286     struct _WsbmBufStorage *storage;
   1287 
   1288     storage = buf->storage;
   1289     size = storage->pool->size(storage);
   1290 
   1291     return size;
   1292 
   1293 }
   1294 
   1295 struct _ValidateList *
   1296 wsbmGetKernelValidateList(struct _WsbmBufferList *list)
   1297 {
   1298     return (list->hasKernelBuffers) ? &list->kernelBuffers : NULL;
   1299 }
   1300 
   1301 struct _ValidateList *
   1302 wsbmGetUserValidateList(struct _WsbmBufferList *list)
   1303 {
   1304     return &list->userBuffers;
   1305 }
   1306 
   1307 struct _ValidateNode *
   1308 validateListNode(void *iterator)
   1309 {
   1310     struct _WsbmListHead *l = (struct _WsbmListHead *)iterator;
   1311 
   1312     return WSBMLISTENTRY(l, struct _ValidateNode, head);
   1313 }
   1314 
   1315 void *
   1316 validateListIterator(struct _ValidateList *list)
   1317 {
   1318     void *ret = list->list.next;
   1319 
   1320     if (ret == &list->list)
   1321 	return NULL;
   1322     return ret;
   1323 }
   1324 
   1325 void *
   1326 validateListNext(struct _ValidateList *list, void *iterator)
   1327 {
   1328     void *ret;
   1329 
   1330     struct _WsbmListHead *l = (struct _WsbmListHead *)iterator;
   1331 
   1332     ret = l->next;
   1333     if (ret == &list->list)
   1334 	return NULL;
   1335     return ret;
   1336 }
   1337 
   1338 uint32_t
   1339 wsbmKBufHandle(const struct _WsbmKernelBuf * kBuf)
   1340 {
   1341     return kBuf->handle;
   1342 }
   1343 
   1344 extern void
   1345 wsbmUpdateKBuf(struct _WsbmKernelBuf *kBuf,
   1346 	       uint64_t gpuOffset, uint32_t placement,
   1347 	       uint32_t fence_type_mask)
   1348 {
   1349     kBuf->gpuOffset = gpuOffset;
   1350     kBuf->placement = placement;
   1351     kBuf->fence_type_mask = fence_type_mask;
   1352 }
   1353 
   1354 extern struct _WsbmKernelBuf *
   1355 wsbmKBuf(const struct _WsbmBufferObject *buf)
   1356 {
   1357     struct _WsbmBufStorage *storage = buf->storage;
   1358 
   1359     return storage->pool->kernel(storage);
   1360 }
   1361