1 /**************************************************************************
3 * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA
5 * Copyright 2009 VMware, Inc., Palo Alto, CA., USA
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:
16 * The above copyright notice and this permission notice (including the
17 * next paragraph) shall be included in all copies or substantial portions
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.
28 **************************************************************************/
30 * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
37 #include <ttm/ttm_placement_user.h>
46 #include "wsbm_pool.h"
47 #include "wsbm_fencemgr.h"
48 #include "wsbm_priv.h"
49 #include "wsbm_manager.h"
51 #define WSBM_SLABPOOL_ALLOC_RETRIES 100
52 #define DRMRESTARTCOMMANDWRITE(_fd, _val, _arg, _ret) \
54 (_ret) = drmCommandWrite(_fd, _val, &(_arg), sizeof(_arg)); \
55 } while ((_ret) == -EAGAIN || (_ret) == -ERESTART); \
57 #define DRMRESTARTCOMMANDWRITEREAD(_fd, _val, _arg, _ret) \
59 (_ret) = drmCommandWriteRead(_fd, _val, &(_arg), sizeof(_arg)); \
60 } while ((_ret) == -EAGAIN || (_ret) == -ERESTART); \
63 #ifdef DEBUG_FENCESIGNALED
64 static int createbuffer = 0;
65 static int fencesignaled = 0;
70 struct _WsbmSlabBuffer
72 struct _WsbmKernelBuf kBuf;
73 struct _WsbmBufStorage storage;
74 struct _WsbmCond event;
77 * Remains constant after creation.
81 struct _WsbmSlab *parent;
84 unsigned long requestedSize;
88 * Protected by struct _WsbmSlabSizeHeader::mutex
91 struct _WsbmListHead head;
94 * Protected by this::mutex
97 struct _WsbmFenceObject *fence;
99 struct _WsbmAtomic writers; /* (Only upping) */
103 struct _WsbmSlabPool;
104 struct _WsbmSlabKernelBO
108 * Constant at creation
111 struct _WsbmKernelBuf kBuf;
112 uint32_t pageAlignment;
114 unsigned long actualSize;
118 * Protected by struct _WsbmSlabCache::mutex
121 struct _WsbmSlabPool *slabPool;
122 uint32_t proposedPlacement;
123 struct _WsbmListHead timeoutHead;
124 struct _WsbmListHead head;
125 struct timeval timeFreed;
130 struct _WsbmListHead head;
131 struct _WsbmListHead freeBuffers;
134 struct _WsbmSlabBuffer *buffers;
135 struct _WsbmSlabSizeHeader *header;
136 struct _WsbmSlabKernelBO *kbo;
139 struct _WsbmSlabSizeHeader
142 * Constant at creation.
144 struct _WsbmSlabPool *slabPool;
148 * Protected by this::mutex
151 struct _WsbmListHead slabs;
152 struct _WsbmListHead freeSlabs;
153 struct _WsbmListHead delayedBuffers;
155 struct _WsbmMutex mutex;
158 struct _WsbmSlabCache
160 struct timeval slabTimeout;
161 struct timeval checkInterval;
162 struct timeval nextCheck;
163 struct _WsbmListHead timeoutList;
164 struct _WsbmListHead unCached;
165 struct _WsbmListHead cached;
166 struct _WsbmMutex mutex;
171 struct _WsbmBufferPool pool;
174 * The data of this structure remains constant after
175 * initialization and thus needs no mutex protection.
178 unsigned int devOffset;
179 struct _WsbmSlabCache *cache;
180 uint32_t proposedPlacement;
182 uint32_t *bucketSizes;
187 int desiredNumBuffers;
188 struct _WsbmSlabSizeHeader *headers;
191 static inline struct _WsbmSlabPool *
192 slabPoolFromPool(struct _WsbmBufferPool *pool)
194 return containerOf(pool, struct _WsbmSlabPool, pool);
197 static inline struct _WsbmSlabPool *
198 slabPoolFromBuf(struct _WsbmSlabBuffer *sBuf)
200 return slabPoolFromPool(sBuf->storage.pool);
203 static inline struct _WsbmSlabBuffer *
204 slabBuffer(struct _WsbmBufStorage *buf)
206 return containerOf(buf, struct _WsbmSlabBuffer, storage);
210 * FIXME: Perhaps arrange timeout slabs in size buckets for fast
215 wsbmTimeAfterEq(struct timeval *arg1, struct timeval *arg2)
217 return ((arg1->tv_sec > arg2->tv_sec) ||
218 ((arg1->tv_sec == arg2->tv_sec) &&
219 (arg1->tv_usec > arg2->tv_usec)));
223 wsbmTimeAdd(struct timeval *arg, struct timeval *add)
227 arg->tv_sec += add->tv_sec;
228 arg->tv_usec += add->tv_usec;
229 sec = arg->tv_usec / 1000000;
231 arg->tv_usec -= sec * 1000000;
235 wsbmFreeKernelBO(struct _WsbmSlabKernelBO *kbo)
237 struct ttm_pl_reference_req arg;
238 struct _WsbmSlabPool *slabPool;
243 slabPool = kbo->slabPool;
244 arg.handle = kbo->kBuf.handle;
245 (void)munmap(kbo->virtual, kbo->actualSize);
246 (void)drmCommandWrite(slabPool->pool.fd,
247 slabPool->devOffset + TTM_PL_UNREF, &arg,
253 wsbmFreeTimeoutKBOsLocked(struct _WsbmSlabCache *cache, struct timeval *time)
255 struct _WsbmListHead *list, *next;
256 struct _WsbmSlabKernelBO *kbo;
258 if (!wsbmTimeAfterEq(time, &cache->nextCheck))
261 WSBMLISTFOREACHSAFE(list, next, &cache->timeoutList) {
262 kbo = WSBMLISTENTRY(list, struct _WsbmSlabKernelBO, timeoutHead);
264 if (!wsbmTimeAfterEq(time, &kbo->timeFreed))
267 WSBMLISTDELINIT(&kbo->timeoutHead);
268 WSBMLISTDELINIT(&kbo->head);
269 wsbmFreeKernelBO(kbo);
272 cache->nextCheck = *time;
273 wsbmTimeAdd(&cache->nextCheck, &cache->checkInterval);
277 * Add a _SlabKernelBO to the free slab manager.
278 * This means that it is available for reuse, but if it's not
279 * reused in a while, it will be freed.
283 wsbmSetKernelBOFree(struct _WsbmSlabCache *cache,
284 struct _WsbmSlabKernelBO *kbo)
287 struct timeval timeFreed;
289 gettimeofday(&time, NULL);
291 WSBM_MUTEX_LOCK(&cache->mutex);
292 wsbmTimeAdd(&timeFreed, &cache->slabTimeout);
293 kbo->timeFreed = timeFreed;
295 if (kbo->kBuf.placement & TTM_PL_FLAG_CACHED)
296 WSBMLISTADD(&kbo->head, &cache->cached);
298 WSBMLISTADD(&kbo->head, &cache->unCached);
300 WSBMLISTADDTAIL(&kbo->timeoutHead, &cache->timeoutList);
301 wsbmFreeTimeoutKBOsLocked(cache, &time);
303 WSBM_MUTEX_UNLOCK(&cache->mutex);
307 * Get a _SlabKernelBO for us to use as storage for a slab.
310 static struct _WsbmSlabKernelBO *
311 wsbmAllocKernelBO(struct _WsbmSlabSizeHeader *header)
313 struct _WsbmSlabPool *slabPool = header->slabPool;
314 struct _WsbmSlabCache *cache = slabPool->cache;
315 struct _WsbmListHead *list, *head;
316 uint32_t size = header->bufSize * slabPool->desiredNumBuffers;
317 struct _WsbmSlabKernelBO *kbo;
318 struct _WsbmSlabKernelBO *kboTmp;
322 * FIXME: We should perhaps allow some variation in slabsize in order
323 * to efficiently reuse slabs.
326 size = (size <= slabPool->maxSlabSize) ? size : slabPool->maxSlabSize;
327 if (size < header->bufSize)
328 size = header->bufSize;
329 size = (size + slabPool->pageSize - 1) & ~(slabPool->pageSize - 1);
330 WSBM_MUTEX_LOCK(&cache->mutex);
335 head = (slabPool->proposedPlacement & TTM_PL_FLAG_CACHED) ?
336 &cache->cached : &cache->unCached;
338 WSBMLISTFOREACH(list, head) {
339 kboTmp = WSBMLISTENTRY(list, struct _WsbmSlabKernelBO, head);
341 if ((kboTmp->actualSize == size) &&
342 (slabPool->pageAlignment == 0 ||
343 (kboTmp->pageAlignment % slabPool->pageAlignment) == 0)) {
348 if ((kbo->proposedPlacement ^ slabPool->proposedPlacement) == 0)
355 WSBMLISTDELINIT(&kbo->head);
356 WSBMLISTDELINIT(&kbo->timeoutHead);
359 WSBM_MUTEX_UNLOCK(&cache->mutex);
363 kbo->proposedPlacement ^ slabPool->proposedPlacement;
367 union ttm_pl_setstatus_arg arg;
368 struct ttm_pl_setstatus_req *req = &arg.req;
369 struct ttm_pl_rep *rep = &arg.rep;
371 req->handle = kbo->kBuf.handle;
372 req->set_placement = slabPool->proposedPlacement & new_mask;
373 req->clr_placement = ~slabPool->proposedPlacement & new_mask;
374 DRMRESTARTCOMMANDWRITEREAD(slabPool->pool.fd,
375 slabPool->devOffset + TTM_PL_SETSTATUS,
378 kbo->kBuf.gpuOffset = rep->gpu_offset;
379 kbo->kBuf.placement = rep->placement;
381 kbo->proposedPlacement = slabPool->proposedPlacement;
387 wsbmFreeKernelBO(kbo);
392 kbo = calloc(1, sizeof(*kbo));
397 union ttm_pl_create_arg arg;
399 kbo->slabPool = slabPool;
400 WSBMINITLISTHEAD(&kbo->head);
401 WSBMINITLISTHEAD(&kbo->timeoutHead);
404 arg.req.placement = slabPool->proposedPlacement;
405 arg.req.page_alignment = slabPool->pageAlignment;
407 DRMRESTARTCOMMANDWRITEREAD(slabPool->pool.fd,
408 slabPool->devOffset + TTM_PL_CREATE,
413 kbo->kBuf.gpuOffset = arg.rep.gpu_offset;
414 kbo->kBuf.placement = arg.rep.placement;
415 kbo->kBuf.handle = arg.rep.handle;
417 kbo->actualSize = arg.rep.bo_size;
418 kbo->mapHandle = arg.rep.map_handle;
419 kbo->proposedPlacement = slabPool->proposedPlacement;
422 kbo->virtual = mmap(0, kbo->actualSize,
423 PROT_READ | PROT_WRITE, MAP_SHARED,
424 slabPool->pool.fd, kbo->mapHandle);
426 if (kbo->virtual == MAP_FAILED) {
435 struct ttm_pl_reference_req arg = {.handle = kbo->kBuf.handle };
437 (void)drmCommandWrite(slabPool->pool.fd,
438 slabPool->devOffset + TTM_PL_UNREF,
447 wsbmAllocSlab(struct _WsbmSlabSizeHeader *header)
449 struct _WsbmSlab *slab;
450 struct _WsbmSlabBuffer *sBuf;
455 slab = calloc(1, sizeof(*slab));
459 slab->kbo = wsbmAllocKernelBO(header);
465 numBuffers = slab->kbo->actualSize / header->bufSize;
467 slab->buffers = calloc(numBuffers, sizeof(*slab->buffers));
468 if (!slab->buffers) {
473 WSBMINITLISTHEAD(&slab->head);
474 WSBMINITLISTHEAD(&slab->freeBuffers);
475 slab->numBuffers = numBuffers;
477 slab->header = header;
479 sBuf = slab->buffers;
480 for (i = 0; i < numBuffers; ++i) {
481 ret = wsbmBufStorageInit(&sBuf->storage, &header->slabPool->pool);
485 sBuf->start = i * header->bufSize;
486 sBuf->virtual = (void *)((uint8_t *) slab->kbo->virtual +
488 wsbmAtomicSet(&sBuf->writers, 0);
489 sBuf->isSlabBuffer = 1;
490 WSBM_COND_INIT(&sBuf->event);
491 WSBMLISTADDTAIL(&sBuf->head, &slab->freeBuffers);
496 WSBMLISTADDTAIL(&slab->head, &header->slabs);
501 sBuf = slab->buffers;
502 for (i = 0; i < numBuffers; ++i) {
503 if (sBuf->parent == slab) {
504 WSBM_COND_FREE(&sBuf->event);
505 wsbmBufStorageTakedown(&sBuf->storage);
511 wsbmSetKernelBOFree(header->slabPool->cache, slab->kbo);
518 * Delete a buffer from the slab header delayed list and put
519 * it on the slab free list.
523 wsbmSlabFreeBufferLocked(struct _WsbmSlabBuffer *buf)
525 struct _WsbmSlab *slab = buf->parent;
526 struct _WsbmSlabSizeHeader *header = slab->header;
527 struct _WsbmListHead *list = &buf->head;
530 WSBMLISTADDTAIL(list, &slab->freeBuffers);
533 if (slab->head.next == &slab->head)
534 WSBMLISTADDTAIL(&slab->head, &header->slabs);
536 if (slab->numFree == slab->numBuffers) {
539 WSBMLISTADDTAIL(list, &header->freeSlabs);
542 if (header->slabs.next == &header->slabs ||
543 slab->numFree != slab->numBuffers) {
545 struct _WsbmListHead *next;
546 struct _WsbmSlabCache *cache = header->slabPool->cache;
548 WSBMLISTFOREACHSAFE(list, next, &header->freeSlabs) {
550 struct _WsbmSlabBuffer *sBuf;
552 slab = WSBMLISTENTRY(list, struct _WsbmSlab, head);
554 WSBMLISTDELINIT(list);
556 sBuf = slab->buffers;
557 for (i = 0; i < slab->numBuffers; ++i) {
558 if (sBuf->parent == slab) {
559 WSBM_COND_FREE(&sBuf->event);
560 wsbmBufStorageTakedown(&sBuf->storage);
564 wsbmSetKernelBOFree(cache, slab->kbo);
572 wsbmSlabCheckFreeLocked(struct _WsbmSlabSizeHeader *header, int wait)
574 struct _WsbmListHead *list, *prev, *first, *head;
575 struct _WsbmSlabBuffer *sBuf;
576 struct _WsbmSlab *slab;
577 int firstWasSignaled = 1;
583 * Rerun the freeing test if the youngest tested buffer
584 * was signaled, since there might be more idle buffers
588 while (firstWasSignaled) {
589 firstWasSignaled = 0;
591 first = header->delayedBuffers.next;
593 /* Only examine the oldest 1/3 of delayed buffers:
595 if (header->numDelayed > 3) {
596 for (i = 0; i < header->numDelayed; i += 3) {
602 * No need to take the buffer mutex for each buffer we loop
603 * through since we're currently the only user.
607 WSBMLISTFOREACHPREVSAFE(list, prev, head) {
609 if (list == &header->delayedBuffers)
612 sBuf = WSBMLISTENTRY(list, struct _WsbmSlabBuffer, head);
618 ret = wsbmFenceFinish(sBuf->fence, sBuf->fenceType, 0);
625 wsbmFenceSignaled(sBuf->fence, sBuf->fenceType);
626 #ifdef DEBUG_FENCESIGNALED
632 firstWasSignaled = 1;
633 wsbmFenceUnreference(&sBuf->fence);
634 header->numDelayed--;
635 wsbmSlabFreeBufferLocked(sBuf);
638 } else if (wsbmFenceSignaledCached(sBuf->fence, sBuf->fenceType)) {
639 wsbmFenceUnreference(&sBuf->fence);
640 header->numDelayed--;
641 wsbmSlabFreeBufferLocked(sBuf);
647 static struct _WsbmSlabBuffer *
648 wsbmSlabAllocBuffer(struct _WsbmSlabSizeHeader *header)
650 static struct _WsbmSlabBuffer *buf;
651 struct _WsbmSlab *slab;
652 struct _WsbmListHead *list;
653 int count = WSBM_SLABPOOL_ALLOC_RETRIES;
655 WSBM_MUTEX_LOCK(&header->mutex);
656 while (header->slabs.next == &header->slabs && count > 0) {
657 wsbmSlabCheckFreeLocked(header, 0);
658 if (header->slabs.next != &header->slabs)
661 WSBM_MUTEX_UNLOCK(&header->mutex);
662 if (count != WSBM_SLABPOOL_ALLOC_RETRIES)
664 WSBM_MUTEX_LOCK(&header->mutex);
665 (void)wsbmAllocSlab(header);
669 list = header->slabs.next;
670 if (list == &header->slabs) {
671 WSBM_MUTEX_UNLOCK(&header->mutex);
674 slab = WSBMLISTENTRY(list, struct _WsbmSlab, head);
675 if (--slab->numFree == 0)
676 WSBMLISTDELINIT(list);
678 list = slab->freeBuffers.next;
679 WSBMLISTDELINIT(list);
681 WSBM_MUTEX_UNLOCK(&header->mutex);
682 buf = WSBMLISTENTRY(list, struct _WsbmSlabBuffer, head);
684 buf->storage.destroyContainer = NULL;
686 #ifdef DEBUG_FENCESIGNALED
692 static struct _WsbmBufStorage *
693 pool_create(struct _WsbmBufferPool *pool, unsigned long size,
694 uint32_t placement, unsigned alignment)
696 struct _WsbmSlabPool *slabPool = slabPoolFromPool(pool);
697 struct _WsbmSlabSizeHeader *header;
698 struct _WsbmSlabBuffer *sBuf;
703 * FIXME: Check for compatibility.
706 header = slabPool->headers;
707 for (i = 0; i < slabPool->numBuckets; ++i) {
708 if (header->bufSize >= size)
713 if (i < slabPool->numBuckets) {
714 sBuf = wsbmSlabAllocBuffer(header);
715 return ((sBuf) ? &sBuf->storage : NULL);
719 * Fall back to allocate a buffer object directly from DRM.
720 * and wrap it in a wsbmBO structure.
723 sBuf = calloc(1, sizeof(*sBuf));
729 if ((alignment < slabPool->pageSize)
730 && (slabPool->pageSize % alignment))
732 if ((alignment > slabPool->pageSize)
733 && (alignment % slabPool->pageSize))
737 ret = wsbmBufStorageInit(&sBuf->storage, pool);
741 ret = WSBM_COND_INIT(&sBuf->event);
746 union ttm_pl_create_arg arg;
749 arg.req.placement = placement;
750 arg.req.page_alignment = alignment / slabPool->pageSize;
752 DRMRESTARTCOMMANDWRITEREAD(pool->fd,
753 slabPool->devOffset + TTM_PL_CREATE,
759 sBuf->kBuf.gpuOffset = arg.rep.gpu_offset;
760 sBuf->kBuf.placement = arg.rep.placement;
761 sBuf->kBuf.handle = arg.rep.handle;
762 sBuf->mapHandle = arg.rep.map_handle;
763 sBuf->requestedSize = size;
765 sBuf->virtual = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED,
766 pool->fd, sBuf->mapHandle);
768 if (sBuf->virtual == MAP_FAILED)
772 wsbmAtomicSet(&sBuf->writers, 0);
773 return &sBuf->storage;
776 struct ttm_pl_reference_req arg;
778 arg.handle = sBuf->kBuf.handle;
779 (void)drmCommandWriteRead(pool->fd,
780 slabPool->devOffset + TTM_PL_UNREF,
784 WSBM_COND_FREE(&sBuf->event);
786 wsbmBufStorageTakedown(&sBuf->storage);
793 pool_destroy(struct _WsbmBufStorage **p_buf)
795 struct _WsbmBufStorage *buf = *p_buf;
796 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
797 struct _WsbmSlab *slab;
798 struct _WsbmSlabSizeHeader *header;
802 if (!sBuf->isSlabBuffer) {
803 struct _WsbmSlabPool *slabPool = slabPoolFromBuf(sBuf);
804 struct ttm_pl_reference_req arg;
806 if (sBuf->virtual != NULL) {
807 (void)munmap(sBuf->virtual, sBuf->requestedSize);
808 sBuf->virtual = NULL;
811 arg.handle = sBuf->kBuf.handle;
812 (void)drmCommandWrite(slabPool->pool.fd,
813 slabPool->devOffset + TTM_PL_UNREF,
816 WSBM_COND_FREE(&sBuf->event);
817 wsbmBufStorageTakedown(&sBuf->storage);
823 header = slab->header;
826 * No need to take the buffer mutex below since we're the only user.
829 WSBM_MUTEX_LOCK(&header->mutex);
831 wsbmAtomicSet(&sBuf->writers, 0);
832 wsbmAtomicSet(&sBuf->storage.refCount, 1);
834 if (sBuf->fence && !wsbmFenceSignaledCached(sBuf->fence, sBuf->fenceType)) {
835 WSBMLISTADDTAIL(&sBuf->head, &header->delayedBuffers);
836 header->numDelayed++;
839 wsbmFenceUnreference(&sBuf->fence);
840 wsbmSlabFreeBufferLocked(sBuf);
843 WSBM_MUTEX_UNLOCK(&header->mutex);
847 waitIdleLocked(struct _WsbmSlabBuffer *sBuf, int lazy)
849 struct _WsbmBufStorage *storage = &sBuf->storage;
851 while (sBuf->unFenced || sBuf->fence != NULL) {
854 WSBM_COND_WAIT(&sBuf->event, &storage->mutex);
856 if (sBuf->fence != NULL) {
857 if (!wsbmFenceSignaled(sBuf->fence, sBuf->fenceType)) {
858 struct _WsbmFenceObject *fence =
859 wsbmFenceReference(sBuf->fence);
861 WSBM_MUTEX_UNLOCK(&storage->mutex);
862 (void)wsbmFenceFinish(fence, sBuf->fenceType, lazy);
863 WSBM_MUTEX_LOCK(&storage->mutex);
864 if (sBuf->fence == fence)
865 wsbmFenceUnreference(&sBuf->fence);
867 wsbmFenceUnreference(&fence);
869 wsbmFenceUnreference(&sBuf->fence);
876 pool_waitIdle(struct _WsbmBufStorage *buf, int lazy)
878 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
880 WSBM_MUTEX_LOCK(&buf->mutex);
881 waitIdleLocked(sBuf, lazy);
882 WSBM_MUTEX_UNLOCK(&buf->mutex);
888 pool_map(struct _WsbmBufStorage *buf, unsigned mode, void **virtual)
890 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
892 *virtual = sBuf->virtual;
898 pool_releaseFromCpu(struct _WsbmBufStorage *buf, unsigned mode)
900 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
902 if (wsbmAtomicDecZero(&sBuf->writers))
903 WSBM_COND_BROADCAST(&sBuf->event);
907 pool_syncForCpu(struct _WsbmBufStorage *buf, unsigned mode)
909 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
912 WSBM_MUTEX_LOCK(&buf->mutex);
913 if ((mode & WSBM_SYNCCPU_DONT_BLOCK)) {
916 if (sBuf->unFenced) {
921 if (sBuf->isSlabBuffer)
922 signaled = (sBuf->fence == NULL) ||
923 wsbmFenceSignaledCached(sBuf->fence, sBuf->fenceType);
925 signaled = (sBuf->fence == NULL) ||
926 wsbmFenceSignaled(sBuf->fence, sBuf->fenceType);
930 wsbmFenceUnreference(&sBuf->fence);
931 wsbmAtomicInc(&sBuf->writers);
936 waitIdleLocked(sBuf, 0);
937 wsbmAtomicInc(&sBuf->writers);
939 WSBM_MUTEX_UNLOCK(&buf->mutex);
944 pool_unmap(struct _WsbmBufStorage *buf)
950 pool_poolOffset(struct _WsbmBufStorage *buf)
952 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
958 pool_size(struct _WsbmBufStorage *buf)
960 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
962 if (!sBuf->isSlabBuffer)
963 return sBuf->requestedSize;
965 return sBuf->parent->header->bufSize;
968 static struct _WsbmKernelBuf *
969 pool_kernel(struct _WsbmBufStorage *buf)
971 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
973 return (sBuf->isSlabBuffer) ? &sBuf->parent->kbo->kBuf : &sBuf->kBuf;
977 pool_offset(struct _WsbmBufStorage *buf)
979 return pool_kernel(buf)->gpuOffset + pool_poolOffset(buf);
983 pool_fence(struct _WsbmBufStorage *buf, struct _WsbmFenceObject *fence)
985 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
986 struct _WsbmKernelBuf *kBuf;
988 WSBM_MUTEX_LOCK(&buf->mutex);
990 wsbmFenceUnreference(&sBuf->fence);
992 kBuf = pool_kernel(buf);
993 sBuf->fenceType = kBuf->fence_type_mask;
994 if (!wsbmFenceSignaledCached(fence, sBuf->fenceType))
995 sBuf->fence = wsbmFenceReference(fence);
998 WSBM_COND_BROADCAST(&sBuf->event);
999 WSBM_MUTEX_UNLOCK(&buf->mutex);
1003 pool_validate(struct _WsbmBufStorage *buf,
1004 uint64_t set_flags, uint64_t clr_flags)
1006 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
1008 WSBM_MUTEX_LOCK(&buf->mutex);
1009 while (wsbmAtomicRead(&sBuf->writers) != 0) {
1010 WSBM_COND_WAIT(&sBuf->event, &buf->mutex);
1014 WSBM_MUTEX_UNLOCK(&buf->mutex);
1019 pool_unvalidate(struct _WsbmBufStorage *buf)
1021 struct _WsbmSlabBuffer *sBuf = slabBuffer(buf);
1023 WSBM_MUTEX_LOCK(&buf->mutex);
1024 if (sBuf->unFenced) {
1026 WSBM_COND_BROADCAST(&sBuf->event);
1028 WSBM_MUTEX_UNLOCK(&buf->mutex);
1031 struct _WsbmSlabCache *
1032 wsbmSlabCacheInit(uint32_t checkIntervalMsec, uint32_t slabTimeoutMsec)
1034 struct _WsbmSlabCache *tmp;
1036 tmp = calloc(1, sizeof(*tmp));
1040 WSBM_MUTEX_INIT(&tmp->mutex);
1041 WSBM_MUTEX_LOCK(&tmp->mutex);
1042 tmp->slabTimeout.tv_usec = slabTimeoutMsec * 1000;
1043 tmp->slabTimeout.tv_sec = tmp->slabTimeout.tv_usec / 1000000;
1044 tmp->slabTimeout.tv_usec -= tmp->slabTimeout.tv_sec * 1000000;
1046 tmp->checkInterval.tv_usec = checkIntervalMsec * 1000;
1047 tmp->checkInterval.tv_sec = tmp->checkInterval.tv_usec / 1000000;
1048 tmp->checkInterval.tv_usec -= tmp->checkInterval.tv_sec * 1000000;
1050 gettimeofday(&tmp->nextCheck, NULL);
1051 wsbmTimeAdd(&tmp->nextCheck, &tmp->checkInterval);
1052 WSBMINITLISTHEAD(&tmp->timeoutList);
1053 WSBMINITLISTHEAD(&tmp->unCached);
1054 WSBMINITLISTHEAD(&tmp->cached);
1055 WSBM_MUTEX_UNLOCK(&tmp->mutex);
1061 wsbmSlabCacheFinish(struct _WsbmSlabCache *cache)
1063 struct timeval time;
1065 time = cache->nextCheck;
1066 WSBM_MUTEX_LOCK(&cache->mutex);
1067 wsbmTimeAdd(&time, &cache->checkInterval);
1068 wsbmFreeTimeoutKBOsLocked(cache, &time);
1069 WSBM_MUTEX_UNLOCK(&cache->mutex);
1071 assert(cache->timeoutList.next == &cache->timeoutList);
1072 assert(cache->unCached.next == &cache->unCached);
1073 assert(cache->cached.next == &cache->cached);
1075 WSBM_MUTEX_FREE(&cache->mutex);
1080 wsbmInitSizeHeader(struct _WsbmSlabPool *slabPool, uint32_t size,
1081 struct _WsbmSlabSizeHeader *header)
1083 WSBM_MUTEX_INIT(&header->mutex);
1084 WSBM_MUTEX_LOCK(&header->mutex);
1086 WSBMINITLISTHEAD(&header->slabs);
1087 WSBMINITLISTHEAD(&header->freeSlabs);
1088 WSBMINITLISTHEAD(&header->delayedBuffers);
1090 header->numDelayed = 0;
1091 header->slabPool = slabPool;
1092 header->bufSize = size;
1094 WSBM_MUTEX_UNLOCK(&header->mutex);
1098 wsbmFinishSizeHeader(struct _WsbmSlabSizeHeader *header)
1100 struct _WsbmListHead *list, *next;
1101 struct _WsbmSlabBuffer *sBuf;
1103 WSBM_MUTEX_LOCK(&header->mutex);
1104 WSBMLISTFOREACHSAFE(list, next, &header->delayedBuffers) {
1105 sBuf = WSBMLISTENTRY(list, struct _WsbmSlabBuffer, head);
1108 (void)wsbmFenceFinish(sBuf->fence, sBuf->fenceType, 0);
1109 wsbmFenceUnreference(&sBuf->fence);
1111 header->numDelayed--;
1112 wsbmSlabFreeBufferLocked(sBuf);
1114 WSBM_MUTEX_UNLOCK(&header->mutex);
1115 WSBM_MUTEX_FREE(&header->mutex);
1119 pool_takedown(struct _WsbmBufferPool *pool)
1121 struct _WsbmSlabPool *slabPool = slabPoolFromPool(pool);
1124 for (i = 0; i < slabPool->numBuckets; ++i) {
1125 wsbmFinishSizeHeader(&slabPool->headers[i]);
1128 free(slabPool->headers);
1129 free(slabPool->bucketSizes);
1133 struct _WsbmBufferPool *
1134 wsbmSlabPoolInit(int fd,
1138 uint32_t smallestSize,
1140 uint32_t desiredNumBuffers,
1141 uint32_t maxSlabSize,
1142 uint32_t pageAlignment, struct _WsbmSlabCache *cache)
1144 struct _WsbmBufferPool *pool;
1145 struct _WsbmSlabPool *slabPool;
1148 slabPool = calloc(1, sizeof(*slabPool));
1152 pool = &slabPool->pool;
1154 slabPool->bucketSizes = calloc(numSizes, sizeof(*slabPool->bucketSizes));
1155 if (!slabPool->bucketSizes)
1158 slabPool->headers = calloc(numSizes, sizeof(*slabPool->headers));
1159 if (!slabPool->headers)
1162 slabPool->devOffset = devOffset;
1163 slabPool->cache = cache;
1164 slabPool->proposedPlacement = placement;
1165 slabPool->validMask = validMask;
1166 slabPool->numBuckets = numSizes;
1167 slabPool->pageSize = getpagesize();
1168 slabPool->pageAlignment = pageAlignment;
1169 slabPool->maxSlabSize = maxSlabSize;
1170 slabPool->desiredNumBuffers = desiredNumBuffers;
1172 for (i = 0; i < slabPool->numBuckets; ++i) {
1173 slabPool->bucketSizes[i] = (smallestSize << i);
1174 wsbmInitSizeHeader(slabPool, slabPool->bucketSizes[i],
1175 &slabPool->headers[i]);
1179 pool->map = &pool_map;
1180 pool->unmap = &pool_unmap;
1181 pool->destroy = &pool_destroy;
1182 pool->offset = &pool_offset;
1183 pool->poolOffset = &pool_poolOffset;
1184 pool->size = &pool_size;
1185 pool->create = &pool_create;
1186 pool->fence = &pool_fence;
1187 pool->kernel = &pool_kernel;
1188 pool->validate = &pool_validate;
1189 pool->unvalidate = &pool_unvalidate;
1190 pool->waitIdle = &pool_waitIdle;
1191 pool->takeDown = &pool_takedown;
1192 pool->releasefromcpu = &pool_releaseFromCpu;
1193 pool->syncforcpu = &pool_syncForCpu;
1198 free(slabPool->bucketSizes);