merge with master
[platform/upstream/libwsbm.git] / src / wsbm_manager.c
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 Hellström <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 > (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     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 static struct _WsbmBufStorage *
614 wsbmStorageClone(struct _WsbmBufferObject *buf)
615 {
616     struct _WsbmBufStorage *storage = buf->storage;
617     struct _WsbmBufferPool *pool = storage->pool;
618
619     return pool->create(pool, pool->size(storage), buf->placement,
620                         buf->alignment);
621 }
622
623 struct _WsbmBufferObject *
624 wsbmBOClone(struct _WsbmBufferObject *buf,
625             int (*accelCopy) (struct _WsbmBufferObject *,
626                               struct _WsbmBufferObject *))
627 {
628     struct _WsbmBufferObject *newBuf;
629     int ret;
630
631     newBuf = malloc(sizeof(*newBuf));
632     if (!newBuf)
633         return NULL;
634
635     *newBuf = *buf;
636     newBuf->storage = wsbmStorageClone(buf);
637     if (!newBuf->storage)
638         goto out_err0;
639
640     wsbmAtomicSet(&newBuf->refCount, 1);
641     if (!accelCopy || accelCopy(newBuf, buf) != 0) {
642
643         struct _WsbmBufferPool *pool = buf->storage->pool;
644         struct _WsbmBufStorage *storage = buf->storage;
645         struct _WsbmBufStorage *newStorage = newBuf->storage;
646         void *virtual;
647         void *nVirtual;
648
649         ret = pool->syncforcpu(storage, WSBM_SYNCCPU_READ);
650         if (ret)
651             goto out_err1;
652         ret = pool->map(storage, WSBM_ACCESS_READ, &virtual);
653         if (ret)
654             goto out_err2;
655         ret = pool->map(newStorage, WSBM_ACCESS_WRITE, &nVirtual);
656         if (ret)
657             goto out_err3;
658
659         memcpy(nVirtual, virtual, pool->size(storage));
660         pool->unmap(newBuf->storage);
661         pool->unmap(buf->storage);
662         pool->releasefromcpu(storage, WSBM_SYNCCPU_READ);
663     }
664
665     return newBuf;
666   out_err3:
667     buf->pool->unmap(buf->storage);
668   out_err2:
669     buf->pool->releasefromcpu(buf->storage, WSBM_SYNCCPU_READ);
670   out_err1:
671     wsbmBufStorageUnref(&newBuf->storage);
672   out_err0:
673     free(newBuf);
674     return 0;
675 }
676
677 int
678 wsbmBOSubData(struct _WsbmBufferObject *buf,
679               unsigned long offset, unsigned long size, const void *data,
680               int (*accelCopy) (struct _WsbmBufferObject *,
681                                 struct _WsbmBufferObject *))
682 {
683     int ret = 0;
684
685     if (buf->bufferType == WSBM_BUFFER_SIMPLE)
686         return -EINVAL;
687
688     if (size && data) {
689         void *virtual;
690         struct _WsbmBufStorage *storage = buf->storage;
691         struct _WsbmBufferPool *pool = storage->pool;
692
693         ret = pool->syncforcpu(storage, WSBM_SYNCCPU_WRITE);
694         if (ret)
695             goto out;
696
697         if (wsbmAtomicRead(&storage->onList)) {
698
699             struct _WsbmBufferObject *newBuf;
700
701             /*
702              * Another context has this buffer on its validate list.
703              * This should be a very rare situation, but it can be valid,
704              * and therefore we must deal with it by cloning the storage.
705              */
706
707             pool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE);
708             newBuf = wsbmBOClone(buf, accelCopy);
709
710             /*
711              * If clone fails we have the choice of either bailing.
712              * (The other context will be happy), or go on and update
713              * the old buffer anyway. (We will be happy). We choose the
714              * latter.
715              */
716
717             if (newBuf) {
718                 storage = newBuf->storage;
719                 wsbmAtomicInc(&storage->refCount);
720                 wsbmBufStorageUnref(&buf->storage);
721                 buf->storage = storage;
722                 wsbmBOUnreference(&newBuf);
723                 pool = storage->pool;
724             }
725
726             ret = pool->syncforcpu(storage, WSBM_SYNCCPU_WRITE);
727             if (ret)
728                 goto out;
729         }
730
731         ret = pool->map(storage, WSBM_ACCESS_WRITE, &virtual);
732         if (ret) {
733             pool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE);
734             goto out;
735         }
736
737         memcpy((unsigned char *)virtual + offset, data, size);
738         pool->unmap(storage);
739         pool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE);
740     }
741   out:
742     return ret;
743 }
744
745 int
746 wsbmBOGetSubData(struct _WsbmBufferObject *buf,
747                  unsigned long offset, unsigned long size, void *data)
748 {
749     int ret = 0;
750
751     if (size && data) {
752         void *virtual;
753         struct _WsbmBufStorage *storage = buf->storage;
754         struct _WsbmBufferPool *pool = storage->pool;
755
756         ret = pool->syncforcpu(storage, WSBM_SYNCCPU_READ);
757         if (ret)
758             goto out;
759         ret = pool->map(storage, WSBM_ACCESS_READ, &virtual);
760         if (ret) {
761             pool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE);
762             goto out;
763         }
764         memcpy(data, (unsigned char *)virtual + offset, size);
765         pool->unmap(storage);
766         pool->releasefromcpu(storage, WSBM_SYNCCPU_WRITE);
767     }
768   out:
769     return ret;
770 }
771
772 int
773 wsbmBOSetReferenced(struct _WsbmBufferObject *buf, unsigned long handle)
774 {
775     int ret = 0;
776
777     wsbmBufStorageUnref(&buf->storage);
778     if (buf->pool->createByReference == NULL) {
779         ret = -EINVAL;
780         goto out;
781     }
782     buf->storage = buf->pool->createByReference(buf->pool, handle);
783     if (!buf->storage) {
784         ret = -EINVAL;
785         goto out;
786     }
787     buf->bufferType = WSBM_BUFFER_REF;
788   out:
789     return ret;
790 }
791
792 void
793 wsbmBOFreeSimple(void *ptr)
794 {
795     free(ptr);
796 }
797
798 struct _WsbmBufferObject *
799 wsbmBOCreateSimple(struct _WsbmBufferPool *pool,
800                    unsigned long size,
801                    uint32_t placement,
802                    unsigned alignment, size_t extra_size, size_t * offset)
803 {
804     struct _WsbmBufferObject *buf;
805     struct _WsbmBufStorage *storage;
806
807     *offset = (sizeof(*buf) + 15) & ~15;
808
809     if (extra_size) {
810         extra_size += *offset - sizeof(*buf);
811     }
812
813     buf = (struct _WsbmBufferObject *)calloc(1, sizeof(*buf) + extra_size);
814     if (!buf)
815         return NULL;
816
817     storage = pool->create(pool, size, placement, alignment);
818     if (!storage)
819         goto out_err0;
820
821     storage->destroyContainer = &wsbmBOFreeSimple;
822     storage->destroyArg = buf;
823
824     buf->storage = storage;
825     buf->alignment = alignment;
826     buf->pool = pool;
827     buf->placement = placement;
828     buf->bufferType = WSBM_BUFFER_SIMPLE;
829
830     return buf;
831
832   out_err0:
833     free(buf);
834     return NULL;
835 }
836
837 int
838 wsbmGenBuffers(struct _WsbmBufferPool *pool,
839                unsigned n,
840                struct _WsbmBufferObject *buffers[],
841                unsigned alignment, uint32_t placement)
842 {
843     struct _WsbmBufferObject *buf;
844     int i;
845
846     placement = (placement) ? placement :
847         WSBM_PL_FLAG_SYSTEM | WSBM_PL_FLAG_CACHED;
848
849     for (i = 0; i < n; ++i) {
850         buf = (struct _WsbmBufferObject *)calloc(1, sizeof(*buf));
851         if (!buf)
852             return -ENOMEM;
853
854         wsbmAtomicSet(&buf->refCount, 1);
855         buf->placement = placement;
856         buf->alignment = alignment;
857         buf->pool = pool;
858         buf->bufferType = WSBM_BUFFER_COMPLEX;
859         buffers[i] = buf;
860     }
861     return 0;
862 }
863
864 void
865 wsbmDeleteBuffers(unsigned n, struct _WsbmBufferObject *buffers[])
866 {
867     int i;
868
869     for (i = 0; i < n; ++i) {
870         wsbmBOUnreference(&buffers[i]);
871     }
872 }
873
874 /*
875  * Note that lists are per-context and don't need mutex protection.
876  */
877
878 struct _WsbmBufferList *
879 wsbmBOCreateList(int target, int hasKernelBuffers)
880 {
881     struct _WsbmBufferList *list = calloc(sizeof(*list), 1);
882     int ret;
883
884     list->hasKernelBuffers = hasKernelBuffers;
885     if (hasKernelBuffers) {
886         ret = validateCreateList(target, &list->kernelBuffers, 0);
887         if (ret)
888             return NULL;
889     }
890
891     ret = validateCreateList(target, &list->userBuffers, 1);
892     if (ret) {
893         validateFreeList(&list->kernelBuffers);
894         return NULL;
895     }
896
897     return list;
898 }
899
900 int
901 wsbmBOResetList(struct _WsbmBufferList *list)
902 {
903     int ret;
904
905     if (list->hasKernelBuffers) {
906         ret = validateResetList(&list->kernelBuffers);
907         if (ret)
908             return ret;
909     }
910     ret = validateResetList(&list->userBuffers);
911     return ret;
912 }
913
914 void
915 wsbmBOFreeList(struct _WsbmBufferList *list)
916 {
917     if (list->hasKernelBuffers)
918         validateFreeList(&list->kernelBuffers);
919     validateFreeList(&list->userBuffers);
920     free(list);
921 }
922
923 static int
924 wsbmAddValidateItem(struct _ValidateList *list, void *buf, uint64_t flags,
925                     uint64_t mask, int *itemLoc,
926                     struct _ValidateNode **pnode, int *newItem)
927 {
928     struct _ValidateNode *node, *cur;
929     struct _WsbmListHead *l;
930     struct _WsbmListHead *hashHead;
931     uint32_t hash;
932     uint32_t count = 0;
933     uint32_t key = (unsigned long) buf;
934
935     cur = NULL;
936     hash = wsbmHashFunc((uint8_t *) &key, 4, list->hashMask);
937     hashHead = list->hashTable + hash;
938     *newItem = 0;
939
940     for (l = hashHead->next; l != hashHead; l = l->next) {
941         count++;
942         node = WSBMLISTENTRY(l, struct _ValidateNode, hashHead);
943
944         if (node->buf == buf) {
945             cur = node;
946             break;
947         }
948     }
949
950     if (!cur) {
951         cur = validateListAddNode(list, buf, hash, flags, mask);
952         if (!cur)
953             return -ENOMEM;
954         *newItem = 1;
955         cur->func->clear(cur);
956     } else {
957         uint64_t set_flags = flags & mask;
958         uint64_t clr_flags = (~flags) & mask;
959
960         if (((cur->clr_flags | clr_flags) & WSBM_PL_MASK_MEM) ==
961             WSBM_PL_MASK_MEM) {
962             /*
963              * No available memory type left. Bail.
964              */
965             return -EINVAL;
966         }
967
968         if ((cur->set_flags | set_flags) &
969             (cur->clr_flags | clr_flags) & ~WSBM_PL_MASK_MEM) {
970             /*
971              * Conflicting flags. Bail.
972              */
973             return -EINVAL;
974         }
975
976         cur->set_flags &= ~(clr_flags & WSBM_PL_MASK_MEM);
977         cur->set_flags |= (set_flags & ~WSBM_PL_MASK_MEM);
978         cur->clr_flags |= clr_flags;
979     }
980     *itemLoc = cur->listItem;
981     if (pnode)
982         *pnode = cur;
983     return 0;
984 }
985
986 int
987 wsbmBOAddListItem(struct _WsbmBufferList *list,
988                   struct _WsbmBufferObject *buf,
989                   uint64_t flags, uint64_t mask, int *itemLoc,
990                   struct _ValidateNode **node)
991 {
992     int newItem;
993     struct _WsbmBufStorage *storage = buf->storage;
994     int ret;
995     int dummy;
996     struct _ValidateNode *dummyNode;
997
998     if (list->hasKernelBuffers) {
999         ret = wsbmAddValidateItem(&list->kernelBuffers,
1000                                   storage->pool->kernel(storage),
1001                                   flags, mask, itemLoc, node, &dummy);
1002         if (ret)
1003             goto out_unlock;
1004     } else {
1005         *node = NULL;
1006         *itemLoc = -1000;
1007     }
1008
1009     ret = wsbmAddValidateItem(&list->userBuffers, storage,
1010                               flags, mask, &dummy, &dummyNode, &newItem);
1011     if (ret)
1012         goto out_unlock;
1013
1014     if (newItem) {
1015         wsbmAtomicInc(&storage->refCount);
1016         wsbmAtomicInc(&storage->onList);
1017     }
1018
1019   out_unlock:
1020     return ret;
1021 }
1022
1023 void
1024 wsbmBOFence(struct _WsbmBufferObject *buf, struct _WsbmFenceObject *fence)
1025 {
1026     struct _WsbmBufStorage *storage;
1027
1028     storage = buf->storage;
1029     if (storage->pool->fence)
1030         storage->pool->fence(storage, fence);
1031
1032 }
1033
1034 int
1035 wsbmBOOnList(const struct _WsbmBufferObject *buf)
1036 {
1037     if (buf->storage == NULL)
1038         return 0;
1039     return wsbmAtomicRead(&buf->storage->onList);
1040 }
1041
1042 int
1043 wsbmBOUnrefUserList(struct _WsbmBufferList *list)
1044 {
1045     struct _WsbmBufStorage *storage;
1046     void *curBuf;
1047
1048     curBuf = validateListIterator(&list->userBuffers);
1049
1050     while (curBuf) {
1051         storage = (struct _WsbmBufStorage *)(validateListNode(curBuf)->buf);
1052         wsbmAtomicDec(&storage->onList);
1053         wsbmBufStorageUnref(&storage);
1054         curBuf = validateListNext(&list->userBuffers, curBuf);
1055     }
1056
1057     return wsbmBOResetList(list);
1058 }
1059
1060
1061 int
1062 wsbmBOFenceUserList(struct _WsbmBufferList *list,
1063                     struct _WsbmFenceObject *fence)
1064 {
1065     struct _WsbmBufStorage *storage;
1066     void *curBuf;
1067
1068     curBuf = validateListIterator(&list->userBuffers);
1069
1070     /*
1071      * User-space fencing callbacks.
1072      */
1073
1074     while (curBuf) {
1075         storage = (struct _WsbmBufStorage *)(validateListNode(curBuf)->buf);
1076
1077         storage->pool->fence(storage, fence);
1078         wsbmAtomicDec(&storage->onList);
1079         wsbmBufStorageUnref(&storage);
1080         curBuf = validateListNext(&list->userBuffers, curBuf);
1081     }
1082
1083     return wsbmBOResetList(list);
1084 }
1085
1086 int
1087 wsbmBOValidateUserList(struct _WsbmBufferList *list)
1088 {
1089     void *curBuf;
1090     struct _WsbmBufStorage *storage;
1091     struct _ValidateNode *node;
1092     int ret;
1093
1094     curBuf = validateListIterator(&list->userBuffers);
1095
1096     /*
1097      * User-space validation callbacks.
1098      */
1099
1100     while (curBuf) {
1101         node = validateListNode(curBuf);
1102         storage = (struct _WsbmBufStorage *)node->buf;
1103         if (storage->pool->validate) {
1104             ret = storage->pool->validate(storage, node->set_flags,
1105                                           node->clr_flags);
1106             if (ret)
1107                 return ret;
1108         }
1109         curBuf = validateListNext(&list->userBuffers, curBuf);
1110     }
1111     return 0;
1112 }
1113
1114 int
1115 wsbmBOUnvalidateUserList(struct _WsbmBufferList *list)
1116 {
1117     void *curBuf;
1118     struct _WsbmBufStorage *storage;
1119     struct _ValidateNode *node;
1120
1121     curBuf = validateListIterator(&list->userBuffers);
1122
1123     /*
1124      * User-space validation callbacks.
1125      */
1126
1127     while (curBuf) {
1128         node = validateListNode(curBuf);
1129         storage = (struct _WsbmBufStorage *)node->buf;
1130         if (storage->pool->unvalidate) {
1131             storage->pool->unvalidate(storage);
1132         }
1133         wsbmAtomicDec(&storage->onList);
1134         wsbmBufStorageUnref(&storage);
1135         curBuf = validateListNext(&list->userBuffers, curBuf);
1136     }
1137     return wsbmBOResetList(list);
1138 }
1139
1140 void
1141 wsbmPoolTakeDown(struct _WsbmBufferPool *pool)
1142 {
1143     pool->takeDown(pool);
1144
1145 }
1146
1147 unsigned long
1148 wsbmBOSize(struct _WsbmBufferObject *buf)
1149 {
1150     unsigned long size;
1151     struct _WsbmBufStorage *storage;
1152
1153     storage = buf->storage;
1154     size = storage->pool->size(storage);
1155
1156     return size;
1157
1158 }
1159
1160 struct _ValidateList *
1161 wsbmGetKernelValidateList(struct _WsbmBufferList *list)
1162 {
1163     return (list->hasKernelBuffers) ? &list->kernelBuffers : NULL;
1164 }
1165
1166 struct _ValidateList *
1167 wsbmGetUserValidateList(struct _WsbmBufferList *list)
1168 {
1169     return &list->userBuffers;
1170 }
1171
1172 struct _ValidateNode *
1173 validateListNode(void *iterator)
1174 {
1175     struct _WsbmListHead *l = (struct _WsbmListHead *)iterator;
1176
1177     return WSBMLISTENTRY(l, struct _ValidateNode, head);
1178 }
1179
1180 void *
1181 validateListIterator(struct _ValidateList *list)
1182 {
1183     void *ret = list->list.next;
1184
1185     if (ret == &list->list)
1186         return NULL;
1187     return ret;
1188 }
1189
1190 void *
1191 validateListNext(struct _ValidateList *list, void *iterator)
1192 {
1193     void *ret;
1194
1195     struct _WsbmListHead *l = (struct _WsbmListHead *)iterator;
1196
1197     ret = l->next;
1198     if (ret == &list->list)
1199         return NULL;
1200     return ret;
1201 }
1202
1203 uint32_t
1204 wsbmKBufHandle(const struct _WsbmKernelBuf * kBuf)
1205 {
1206     return kBuf->handle;
1207 }
1208
1209 extern void
1210 wsbmUpdateKBuf(struct _WsbmKernelBuf *kBuf,
1211                uint64_t gpuOffset, uint32_t placement,
1212                uint32_t fence_type_mask)
1213 {
1214     kBuf->gpuOffset = gpuOffset;
1215     kBuf->placement = placement;
1216     kBuf->fence_type_mask = fence_type_mask;
1217 }
1218
1219 extern struct _WsbmKernelBuf *
1220 wsbmKBuf(const struct _WsbmBufferObject *buf)
1221 {
1222     struct _WsbmBufStorage *storage = buf->storage;
1223
1224     return storage->pool->kernel(storage);
1225 }