00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <stdint.h>
00033 #include <sys/time.h>
00034 #include <errno.h>
00035 #include <unistd.h>
00036 #include <assert.h>
00037 #include "ws_dri_bufpool.h"
00038 #include "ws_dri_fencemgr.h"
00039 #include "ws_dri_bufmgr.h"
00040 #include "pipe/p_thread.h"
00041
00042 #define DRI_SLABPOOL_ALLOC_RETRIES 100
00043
00044 struct _DriSlab;
00045
00046 struct _DriSlabBuffer {
00047 int isSlabBuffer;
00048 drmBO *bo;
00049 struct _DriFenceObject *fence;
00050 struct _DriSlab *parent;
00051 drmMMListHead head;
00052 uint32_t mapCount;
00053 uint32_t start;
00054 uint32_t fenceType;
00055 int unFenced;
00056 pipe_condvar event;
00057 };
00058
00059 struct _DriKernelBO {
00060 int fd;
00061 drmBO bo;
00062 drmMMListHead timeoutHead;
00063 drmMMListHead head;
00064 struct timeval timeFreed;
00065 uint32_t pageAlignment;
00066 void *virtual;
00067 };
00068
00069 struct _DriSlab{
00070 drmMMListHead head;
00071 drmMMListHead freeBuffers;
00072 uint32_t numBuffers;
00073 uint32_t numFree;
00074 struct _DriSlabBuffer *buffers;
00075 struct _DriSlabSizeHeader *header;
00076 struct _DriKernelBO *kbo;
00077 };
00078
00079
00080 struct _DriSlabSizeHeader {
00081 drmMMListHead slabs;
00082 drmMMListHead freeSlabs;
00083 drmMMListHead delayedBuffers;
00084 uint32_t numDelayed;
00085 struct _DriSlabPool *slabPool;
00086 uint32_t bufSize;
00087 pipe_mutex mutex;
00088 };
00089
00090 struct _DriFreeSlabManager {
00091 struct timeval slabTimeout;
00092 struct timeval checkInterval;
00093 struct timeval nextCheck;
00094 drmMMListHead timeoutList;
00095 drmMMListHead unCached;
00096 drmMMListHead cached;
00097 pipe_mutex mutex;
00098 };
00099
00100
00101 struct _DriSlabPool {
00102
00103
00104
00105
00106
00107
00108 struct _DriFreeSlabManager *fMan;
00109 uint64_t proposedFlags;
00110 uint64_t validMask;
00111 uint32_t *bucketSizes;
00112 uint32_t numBuckets;
00113 uint32_t pageSize;
00114 int fd;
00115 int pageAlignment;
00116 int maxSlabSize;
00117 int desiredNumBuffers;
00118 struct _DriSlabSizeHeader *headers;
00119 };
00120
00121
00122
00123
00124
00125
00126
00127 static inline int
00128 driTimeAfterEq(struct timeval *arg1, struct timeval *arg2)
00129 {
00130 return ((arg1->tv_sec > arg2->tv_sec) ||
00131 ((arg1->tv_sec == arg2->tv_sec) &&
00132 (arg1->tv_usec > arg2->tv_usec)));
00133 }
00134
00135 static inline void
00136 driTimeAdd(struct timeval *arg, struct timeval *add)
00137 {
00138 unsigned int sec;
00139
00140 arg->tv_sec += add->tv_sec;
00141 arg->tv_usec += add->tv_usec;
00142 sec = arg->tv_usec / 1000000;
00143 arg->tv_sec += sec;
00144 arg->tv_usec -= sec*1000000;
00145 }
00146
00147 static void
00148 driFreeKernelBO(struct _DriKernelBO *kbo)
00149 {
00150 if (!kbo)
00151 return;
00152
00153 (void) drmBOUnreference(kbo->fd, &kbo->bo);
00154 free(kbo);
00155 }
00156
00157
00158 static void
00159 driFreeTimeoutKBOsLocked(struct _DriFreeSlabManager *fMan,
00160 struct timeval *time)
00161 {
00162 drmMMListHead *list, *next;
00163 struct _DriKernelBO *kbo;
00164
00165 if (!driTimeAfterEq(time, &fMan->nextCheck))
00166 return;
00167
00168 for (list = fMan->timeoutList.next, next = list->next;
00169 list != &fMan->timeoutList;
00170 list = next, next = list->next) {
00171
00172 kbo = DRMLISTENTRY(struct _DriKernelBO, list, timeoutHead);
00173
00174 if (!driTimeAfterEq(time, &kbo->timeFreed))
00175 break;
00176
00177 DRMLISTDELINIT(&kbo->timeoutHead);
00178 DRMLISTDELINIT(&kbo->head);
00179 driFreeKernelBO(kbo);
00180 }
00181
00182 fMan->nextCheck = *time;
00183 driTimeAdd(&fMan->nextCheck, &fMan->checkInterval);
00184 }
00185
00186
00187
00188
00189
00190
00191
00192
00193 static void
00194 driSetKernelBOFree(struct _DriFreeSlabManager *fMan,
00195 struct _DriKernelBO *kbo)
00196 {
00197 struct timeval time;
00198
00199 pipe_mutex_lock(fMan->mutex);
00200 gettimeofday(&time, NULL);
00201 driTimeAdd(&time, &fMan->slabTimeout);
00202
00203 kbo->timeFreed = time;
00204
00205 if (kbo->bo.flags & DRM_BO_FLAG_CACHED)
00206 DRMLISTADD(&kbo->head, &fMan->cached);
00207 else
00208 DRMLISTADD(&kbo->head, &fMan->unCached);
00209
00210 DRMLISTADDTAIL(&kbo->timeoutHead, &fMan->timeoutList);
00211 driFreeTimeoutKBOsLocked(fMan, &time);
00212
00213 pipe_mutex_unlock(fMan->mutex);
00214 }
00215
00216
00217
00218
00219
00220
00221 static struct _DriKernelBO *
00222 driAllocKernelBO(struct _DriSlabSizeHeader *header)
00223
00224 {
00225 struct _DriSlabPool *slabPool = header->slabPool;
00226 struct _DriFreeSlabManager *fMan = slabPool->fMan;
00227 drmMMListHead *list, *next, *head;
00228 uint32_t size = header->bufSize * slabPool->desiredNumBuffers;
00229 struct _DriKernelBO *kbo;
00230 struct _DriKernelBO *kboTmp;
00231 int ret;
00232
00233
00234
00235
00236
00237
00238 size = (size <= slabPool->maxSlabSize) ? size : slabPool->maxSlabSize;
00239 size = (size + slabPool->pageSize - 1) & ~(slabPool->pageSize - 1);
00240 pipe_mutex_lock(fMan->mutex);
00241
00242 kbo = NULL;
00243
00244 retry:
00245 head = (slabPool->proposedFlags & DRM_BO_FLAG_CACHED) ?
00246 &fMan->cached : &fMan->unCached;
00247
00248 for (list = head->next, next = list->next;
00249 list != head;
00250 list = next, next = list->next) {
00251
00252 kboTmp = DRMLISTENTRY(struct _DriKernelBO, list, head);
00253
00254 if ((kboTmp->bo.size == size) &&
00255 (slabPool->pageAlignment == 0 ||
00256 (kboTmp->pageAlignment % slabPool->pageAlignment) == 0)) {
00257
00258 if (!kbo)
00259 kbo = kboTmp;
00260
00261 if ((kbo->bo.proposedFlags ^ slabPool->proposedFlags) == 0)
00262 break;
00263
00264 }
00265 }
00266
00267 if (kbo) {
00268 DRMLISTDELINIT(&kbo->head);
00269 DRMLISTDELINIT(&kbo->timeoutHead);
00270 }
00271
00272 pipe_mutex_unlock(fMan->mutex);
00273
00274 if (kbo) {
00275 uint64_t new_mask = kbo->bo.proposedFlags ^ slabPool->proposedFlags;
00276
00277 ret = 0;
00278 if (new_mask) {
00279 ret = drmBOSetStatus(kbo->fd, &kbo->bo, slabPool->proposedFlags,
00280 new_mask, DRM_BO_HINT_DONT_FENCE, 0, 0);
00281 }
00282 if (ret == 0)
00283 return kbo;
00284
00285 driFreeKernelBO(kbo);
00286 kbo = NULL;
00287 goto retry;
00288 }
00289
00290 kbo = calloc(1, sizeof(struct _DriKernelBO));
00291 if (!kbo)
00292 return NULL;
00293
00294 kbo->fd = slabPool->fd;
00295 DRMINITLISTHEAD(&kbo->head);
00296 DRMINITLISTHEAD(&kbo->timeoutHead);
00297 ret = drmBOCreate(kbo->fd, size, slabPool->pageAlignment, NULL,
00298 slabPool->proposedFlags,
00299 DRM_BO_HINT_DONT_FENCE, &kbo->bo);
00300 if (ret)
00301 goto out_err0;
00302
00303 ret = drmBOMap(kbo->fd, &kbo->bo,
00304 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE,
00305 0, &kbo->virtual);
00306
00307 if (ret)
00308 goto out_err1;
00309
00310 ret = drmBOUnmap(kbo->fd, &kbo->bo);
00311 if (ret)
00312 goto out_err1;
00313
00314 return kbo;
00315
00316 out_err1:
00317 drmBOUnreference(kbo->fd, &kbo->bo);
00318 out_err0:
00319 free(kbo);
00320 return NULL;
00321 }
00322
00323
00324 static int
00325 driAllocSlab(struct _DriSlabSizeHeader *header)
00326 {
00327 struct _DriSlab *slab;
00328 struct _DriSlabBuffer *buf;
00329 uint32_t numBuffers;
00330 int ret;
00331 int i;
00332
00333 slab = calloc(1, sizeof(*slab));
00334 if (!slab)
00335 return -ENOMEM;
00336
00337 slab->kbo = driAllocKernelBO(header);
00338 if (!slab->kbo) {
00339 ret = -ENOMEM;
00340 goto out_err0;
00341 }
00342
00343 numBuffers = slab->kbo->bo.size / header->bufSize;
00344
00345 slab->buffers = calloc(numBuffers, sizeof(*slab->buffers));
00346 if (!slab->buffers) {
00347 ret = -ENOMEM;
00348 goto out_err1;
00349 }
00350
00351 DRMINITLISTHEAD(&slab->head);
00352 DRMINITLISTHEAD(&slab->freeBuffers);
00353 slab->numBuffers = numBuffers;
00354 slab->numFree = 0;
00355 slab->header = header;
00356
00357 buf = slab->buffers;
00358 for (i=0; i < numBuffers; ++i) {
00359 buf->parent = slab;
00360 buf->start = i* header->bufSize;
00361 buf->mapCount = 0;
00362 buf->isSlabBuffer = 1;
00363 pipe_condvar_init(buf->event);
00364 DRMLISTADDTAIL(&buf->head, &slab->freeBuffers);
00365 slab->numFree++;
00366 buf++;
00367 }
00368
00369 DRMLISTADDTAIL(&slab->head, &header->slabs);
00370
00371 return 0;
00372
00373 out_err1:
00374 driSetKernelBOFree(header->slabPool->fMan, slab->kbo);
00375 free(slab->buffers);
00376 out_err0:
00377 free(slab);
00378 return ret;
00379 }
00380
00381
00382
00383
00384
00385
00386 static void
00387 driSlabFreeBufferLocked(struct _DriSlabBuffer *buf)
00388 {
00389 struct _DriSlab *slab = buf->parent;
00390 struct _DriSlabSizeHeader *header = slab->header;
00391 drmMMListHead *list = &buf->head;
00392
00393 DRMLISTDEL(list);
00394 DRMLISTADDTAIL(list, &slab->freeBuffers);
00395 slab->numFree++;
00396
00397 if (slab->head.next == &slab->head)
00398 DRMLISTADDTAIL(&slab->head, &header->slabs);
00399
00400 if (slab->numFree == slab->numBuffers) {
00401 list = &slab->head;
00402 DRMLISTDEL(list);
00403 DRMLISTADDTAIL(list, &header->freeSlabs);
00404 }
00405
00406 if (header->slabs.next == &header->slabs ||
00407 slab->numFree != slab->numBuffers) {
00408
00409 drmMMListHead *next;
00410 struct _DriFreeSlabManager *fMan = header->slabPool->fMan;
00411
00412 for (list = header->freeSlabs.next, next = list->next;
00413 list != &header->freeSlabs;
00414 list = next, next = list->next) {
00415
00416 slab = DRMLISTENTRY(struct _DriSlab, list, head);
00417
00418 DRMLISTDELINIT(list);
00419 driSetKernelBOFree(fMan, slab->kbo);
00420 free(slab->buffers);
00421 free(slab);
00422 }
00423 }
00424 }
00425
00426 static void
00427 driSlabCheckFreeLocked(struct _DriSlabSizeHeader *header, int wait)
00428 {
00429 drmMMListHead *list, *prev, *first;
00430 struct _DriSlabBuffer *buf;
00431 struct _DriSlab *slab;
00432 int firstWasSignaled = 1;
00433 int signaled;
00434 int i;
00435 int ret;
00436
00437
00438
00439
00440
00441
00442
00443 while (firstWasSignaled) {
00444 firstWasSignaled = 0;
00445 signaled = 0;
00446 first = header->delayedBuffers.next;
00447
00448
00449
00450 if (header->numDelayed > 3) {
00451 for (i = 0; i < header->numDelayed; i += 3) {
00452 first = first->next;
00453 }
00454 }
00455
00456 for (list = first, prev = list->prev;
00457 list != &header->delayedBuffers;
00458 list = prev, prev = list->prev) {
00459 buf = DRMLISTENTRY(struct _DriSlabBuffer, list, head);
00460 slab = buf->parent;
00461
00462 if (!signaled) {
00463 if (wait) {
00464 ret = driFenceFinish(buf->fence, buf->fenceType, 0);
00465 if (ret)
00466 break;
00467 signaled = 1;
00468 wait = 0;
00469 } else {
00470 signaled = driFenceSignaled(buf->fence, buf->fenceType);
00471 }
00472 if (signaled) {
00473 if (list == first)
00474 firstWasSignaled = 1;
00475 driFenceUnReference(&buf->fence);
00476 header->numDelayed--;
00477 driSlabFreeBufferLocked(buf);
00478 }
00479 } else if (driFenceSignaledCached(buf->fence, buf->fenceType)) {
00480 driFenceUnReference(&buf->fence);
00481 header->numDelayed--;
00482 driSlabFreeBufferLocked(buf);
00483 }
00484 }
00485 }
00486 }
00487
00488
00489 static struct _DriSlabBuffer *
00490 driSlabAllocBuffer(struct _DriSlabSizeHeader *header)
00491 {
00492 static struct _DriSlabBuffer *buf;
00493 struct _DriSlab *slab;
00494 drmMMListHead *list;
00495 int count = DRI_SLABPOOL_ALLOC_RETRIES;
00496
00497 pipe_mutex_lock(header->mutex);
00498 while(header->slabs.next == &header->slabs && count > 0) {
00499 driSlabCheckFreeLocked(header, 0);
00500 if (header->slabs.next != &header->slabs)
00501 break;
00502
00503 pipe_mutex_unlock(header->mutex);
00504 if (count != DRI_SLABPOOL_ALLOC_RETRIES)
00505 usleep(1);
00506 pipe_mutex_lock(header->mutex);
00507 (void) driAllocSlab(header);
00508 count--;
00509 }
00510
00511 list = header->slabs.next;
00512 if (list == &header->slabs) {
00513 pipe_mutex_unlock(header->mutex);
00514 return NULL;
00515 }
00516 slab = DRMLISTENTRY(struct _DriSlab, list, head);
00517 if (--slab->numFree == 0)
00518 DRMLISTDELINIT(list);
00519
00520 list = slab->freeBuffers.next;
00521 DRMLISTDELINIT(list);
00522
00523 pipe_mutex_unlock(header->mutex);
00524 buf = DRMLISTENTRY(struct _DriSlabBuffer, list, head);
00525 return buf;
00526 }
00527
00528 static void *
00529 pool_create(struct _DriBufferPool *driPool, unsigned long size,
00530 uint64_t flags, unsigned hint, unsigned alignment)
00531 {
00532 struct _DriSlabPool *pool = (struct _DriSlabPool *) driPool->data;
00533 struct _DriSlabSizeHeader *header;
00534 struct _DriSlabBuffer *buf;
00535 void *dummy;
00536 int i;
00537 int ret;
00538
00539
00540
00541
00542
00543 header = pool->headers;
00544 for (i=0; i<pool->numBuckets; ++i) {
00545 if (header->bufSize >= size)
00546 break;
00547 header++;
00548 }
00549
00550 if (i < pool->numBuckets)
00551 return driSlabAllocBuffer(header);
00552
00553
00554
00555
00556
00557
00558
00559
00560 buf = calloc(1, sizeof(*buf));
00561
00562 if (!buf)
00563 return NULL;
00564
00565 buf->bo = calloc(1, sizeof(*buf->bo));
00566 if (!buf->bo)
00567 goto out_err0;
00568
00569 if (alignment) {
00570 if ((alignment < pool->pageSize) && (pool->pageSize % alignment))
00571 goto out_err1;
00572 if ((alignment > pool->pageSize) && (alignment % pool->pageSize))
00573 goto out_err1;
00574 }
00575
00576 ret = drmBOCreate(pool->fd, size, alignment / pool->pageSize, NULL,
00577 flags, hint, buf->bo);
00578 if (ret)
00579 goto out_err1;
00580
00581 ret = drmBOMap(pool->fd, buf->bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE,
00582 0, &dummy);
00583 if (ret)
00584 goto out_err2;
00585
00586 ret = drmBOUnmap(pool->fd, buf->bo);
00587 if (ret)
00588 goto out_err2;
00589
00590 return buf;
00591 out_err2:
00592 drmBOUnreference(pool->fd, buf->bo);
00593 out_err1:
00594 free(buf->bo);
00595 out_err0:
00596 free(buf);
00597 return NULL;
00598 }
00599
00600 static int
00601 pool_destroy(struct _DriBufferPool *driPool, void *private)
00602 {
00603 struct _DriSlabBuffer *buf =
00604 (struct _DriSlabBuffer *) private;
00605 struct _DriSlab *slab;
00606 struct _DriSlabSizeHeader *header;
00607
00608 if (!buf->isSlabBuffer) {
00609 struct _DriSlabPool *pool = (struct _DriSlabPool *) driPool->data;
00610 int ret;
00611
00612 ret = drmBOUnreference(pool->fd, buf->bo);
00613 free(buf->bo);
00614 free(buf);
00615 return ret;
00616 }
00617
00618 slab = buf->parent;
00619 header = slab->header;
00620
00621 pipe_mutex_lock(header->mutex);
00622 buf->unFenced = 0;
00623 buf->mapCount = 0;
00624
00625 if (buf->fence && !driFenceSignaledCached(buf->fence, buf->fenceType)) {
00626 DRMLISTADDTAIL(&buf->head, &header->delayedBuffers);
00627 header->numDelayed++;
00628 } else {
00629 if (buf->fence)
00630 driFenceUnReference(&buf->fence);
00631 driSlabFreeBufferLocked(buf);
00632 }
00633
00634 pipe_mutex_unlock(header->mutex);
00635 return 0;
00636 }
00637
00638 static int
00639 pool_waitIdle(struct _DriBufferPool *driPool, void *private,
00640 pipe_mutex *mutex, int lazy)
00641 {
00642 struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00643
00644 while(buf->unFenced)
00645 pipe_condvar_wait(buf->event, *mutex);
00646
00647 if (!buf->fence)
00648 return 0;
00649
00650 driFenceFinish(buf->fence, buf->fenceType, lazy);
00651 driFenceUnReference(&buf->fence);
00652
00653 return 0;
00654 }
00655
00656 static int
00657 pool_map(struct _DriBufferPool *pool, void *private, unsigned flags,
00658 int hint, pipe_mutex *mutex, void **virtual)
00659 {
00660 struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00661 int busy;
00662
00663 if (buf->isSlabBuffer)
00664 busy = buf->unFenced || (buf->fence && !driFenceSignaledCached(buf->fence, buf->fenceType));
00665 else
00666 busy = buf->fence && !driFenceSignaled(buf->fence, buf->fenceType);
00667
00668
00669 if (busy) {
00670 if (hint & DRM_BO_HINT_DONT_BLOCK)
00671 return -EBUSY;
00672 else {
00673 (void) pool_waitIdle(pool, private, mutex, 0);
00674 }
00675 }
00676
00677 ++buf->mapCount;
00678 *virtual = (buf->isSlabBuffer) ?
00679 (void *) ((uint8_t *) buf->parent->kbo->virtual + buf->start) :
00680 (void *) buf->bo->virtual;
00681
00682 return 0;
00683 }
00684
00685 static int
00686 pool_unmap(struct _DriBufferPool *pool, void *private)
00687 {
00688 struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00689
00690 --buf->mapCount;
00691 if (buf->mapCount == 0 && buf->isSlabBuffer)
00692 pipe_condvar_broadcast(buf->event);
00693
00694 return 0;
00695 }
00696
00697 static unsigned long
00698 pool_offset(struct _DriBufferPool *pool, void *private)
00699 {
00700 struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00701 struct _DriSlab *slab;
00702 struct _DriSlabSizeHeader *header;
00703
00704 if (!buf->isSlabBuffer) {
00705 assert(buf->bo->proposedFlags & DRM_BO_FLAG_NO_MOVE);
00706 return buf->bo->offset;
00707 }
00708
00709 slab = buf->parent;
00710 header = slab->header;
00711
00712 (void) header;
00713 assert(header->slabPool->proposedFlags & DRM_BO_FLAG_NO_MOVE);
00714 return slab->kbo->bo.offset + buf->start;
00715 }
00716
00717 static unsigned long
00718 pool_poolOffset(struct _DriBufferPool *pool, void *private)
00719 {
00720 struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00721
00722 return buf->start;
00723 }
00724
00725 static uint64_t
00726 pool_flags(struct _DriBufferPool *pool, void *private)
00727 {
00728 struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00729
00730 if (!buf->isSlabBuffer)
00731 return buf->bo->flags;
00732
00733 return buf->parent->kbo->bo.flags;
00734 }
00735
00736 static unsigned long
00737 pool_size(struct _DriBufferPool *pool, void *private)
00738 {
00739 struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00740 if (!buf->isSlabBuffer)
00741 return buf->bo->size;
00742
00743 return buf->parent->header->bufSize;
00744 }
00745
00746 static int
00747 pool_fence(struct _DriBufferPool *pool, void *private,
00748 struct _DriFenceObject *fence)
00749 {
00750 struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00751 drmBO *bo;
00752
00753 if (buf->fence)
00754 driFenceUnReference(&buf->fence);
00755
00756 buf->fence = driFenceReference(fence);
00757 bo = (buf->isSlabBuffer) ?
00758 &buf->parent->kbo->bo:
00759 buf->bo;
00760 buf->fenceType = bo->fenceFlags;
00761
00762 buf->unFenced = 0;
00763 pipe_condvar_broadcast(buf->event);
00764
00765 return 0;
00766 }
00767
00768 static drmBO *
00769 pool_kernel(struct _DriBufferPool *pool, void *private)
00770 {
00771 struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00772
00773 return (buf->isSlabBuffer) ? &buf->parent->kbo->bo : buf->bo;
00774 }
00775
00776 static int
00777 pool_validate(struct _DriBufferPool *pool, void *private,
00778 pipe_mutex *mutex)
00779 {
00780 struct _DriSlabBuffer *buf = (struct _DriSlabBuffer *) private;
00781
00782 if (!buf->isSlabBuffer)
00783 return 0;
00784
00785 while(buf->mapCount != 0)
00786 pipe_condvar_wait(buf->event, *mutex);
00787
00788 buf->unFenced = 1;
00789 return 0;
00790 }
00791
00792
00793 struct _DriFreeSlabManager *
00794 driInitFreeSlabManager(uint32_t checkIntervalMsec, uint32_t slabTimeoutMsec)
00795 {
00796 struct _DriFreeSlabManager *tmp;
00797
00798 tmp = calloc(1, sizeof(*tmp));
00799 if (!tmp)
00800 return NULL;
00801
00802 pipe_mutex_init(tmp->mutex);
00803 pipe_mutex_lock(tmp->mutex);
00804 tmp->slabTimeout.tv_usec = slabTimeoutMsec*1000;
00805 tmp->slabTimeout.tv_sec = tmp->slabTimeout.tv_usec / 1000000;
00806 tmp->slabTimeout.tv_usec -= tmp->slabTimeout.tv_sec*1000000;
00807
00808 tmp->checkInterval.tv_usec = checkIntervalMsec*1000;
00809 tmp->checkInterval.tv_sec = tmp->checkInterval.tv_usec / 1000000;
00810 tmp->checkInterval.tv_usec -= tmp->checkInterval.tv_sec*1000000;
00811
00812 gettimeofday(&tmp->nextCheck, NULL);
00813 driTimeAdd(&tmp->nextCheck, &tmp->checkInterval);
00814 DRMINITLISTHEAD(&tmp->timeoutList);
00815 DRMINITLISTHEAD(&tmp->unCached);
00816 DRMINITLISTHEAD(&tmp->cached);
00817 pipe_mutex_unlock(tmp->mutex);
00818
00819 return tmp;
00820 }
00821
00822 void
00823 driFinishFreeSlabManager(struct _DriFreeSlabManager *fMan)
00824 {
00825 struct timeval time;
00826
00827 time = fMan->nextCheck;
00828 driTimeAdd(&time, &fMan->checkInterval);
00829
00830 pipe_mutex_lock(fMan->mutex);
00831 driFreeTimeoutKBOsLocked(fMan, &time);
00832 pipe_mutex_unlock(fMan->mutex);
00833
00834 assert(fMan->timeoutList.next == &fMan->timeoutList);
00835 assert(fMan->unCached.next == &fMan->unCached);
00836 assert(fMan->cached.next == &fMan->cached);
00837
00838 free(fMan);
00839 }
00840
00841 static void
00842 driInitSizeHeader(struct _DriSlabPool *pool, uint32_t size,
00843 struct _DriSlabSizeHeader *header)
00844 {
00845 pipe_mutex_init(header->mutex);
00846 pipe_mutex_lock(header->mutex);
00847
00848 DRMINITLISTHEAD(&header->slabs);
00849 DRMINITLISTHEAD(&header->freeSlabs);
00850 DRMINITLISTHEAD(&header->delayedBuffers);
00851
00852 header->numDelayed = 0;
00853 header->slabPool = pool;
00854 header->bufSize = size;
00855
00856 pipe_mutex_unlock(header->mutex);
00857 }
00858
00859 static void
00860 driFinishSizeHeader(struct _DriSlabSizeHeader *header)
00861 {
00862 drmMMListHead *list, *next;
00863 struct _DriSlabBuffer *buf;
00864
00865 pipe_mutex_lock(header->mutex);
00866 for (list = header->delayedBuffers.next, next = list->next;
00867 list != &header->delayedBuffers;
00868 list = next, next = list->next) {
00869
00870 buf = DRMLISTENTRY(struct _DriSlabBuffer, list , head);
00871 if (buf->fence) {
00872 (void) driFenceFinish(buf->fence, buf->fenceType, 0);
00873 driFenceUnReference(&buf->fence);
00874 }
00875 header->numDelayed--;
00876 driSlabFreeBufferLocked(buf);
00877 }
00878 pipe_mutex_unlock(header->mutex);
00879 }
00880
00881 static void
00882 pool_takedown(struct _DriBufferPool *driPool)
00883 {
00884 struct _DriSlabPool *pool = driPool->data;
00885 int i;
00886
00887 for (i=0; i<pool->numBuckets; ++i) {
00888 driFinishSizeHeader(&pool->headers[i]);
00889 }
00890
00891 free(pool->headers);
00892 free(pool->bucketSizes);
00893 free(pool);
00894 free(driPool);
00895 }
00896
00897 struct _DriBufferPool *
00898 driSlabPoolInit(int fd, uint64_t flags,
00899 uint64_t validMask,
00900 uint32_t smallestSize,
00901 uint32_t numSizes,
00902 uint32_t desiredNumBuffers,
00903 uint32_t maxSlabSize,
00904 uint32_t pageAlignment,
00905 struct _DriFreeSlabManager *fMan)
00906 {
00907 struct _DriBufferPool *driPool;
00908 struct _DriSlabPool *pool;
00909 uint32_t i;
00910
00911 driPool = calloc(1, sizeof(*driPool));
00912 if (!driPool)
00913 return NULL;
00914
00915 pool = calloc(1, sizeof(*pool));
00916 if (!pool)
00917 goto out_err0;
00918
00919 pool->bucketSizes = calloc(numSizes, sizeof(*pool->bucketSizes));
00920 if (!pool->bucketSizes)
00921 goto out_err1;
00922
00923 pool->headers = calloc(numSizes, sizeof(*pool->headers));
00924 if (!pool->headers)
00925 goto out_err2;
00926
00927 pool->fMan = fMan;
00928 pool->proposedFlags = flags;
00929 pool->validMask = validMask;
00930 pool->numBuckets = numSizes;
00931 pool->pageSize = getpagesize();
00932 pool->fd = fd;
00933 pool->pageAlignment = pageAlignment;
00934 pool->maxSlabSize = maxSlabSize;
00935 pool->desiredNumBuffers = desiredNumBuffers;
00936
00937 for (i=0; i<pool->numBuckets; ++i) {
00938 pool->bucketSizes[i] = (smallestSize << i);
00939 driInitSizeHeader(pool, pool->bucketSizes[i],
00940 &pool->headers[i]);
00941 }
00942
00943 driPool->data = (void *) pool;
00944 driPool->map = &pool_map;
00945 driPool->unmap = &pool_unmap;
00946 driPool->destroy = &pool_destroy;
00947 driPool->offset = &pool_offset;
00948 driPool->poolOffset = &pool_poolOffset;
00949 driPool->flags = &pool_flags;
00950 driPool->size = &pool_size;
00951 driPool->create = &pool_create;
00952 driPool->fence = &pool_fence;
00953 driPool->kernel = &pool_kernel;
00954 driPool->validate = &pool_validate;
00955 driPool->waitIdle = &pool_waitIdle;
00956 driPool->takeDown = &pool_takedown;
00957
00958 return driPool;
00959
00960 out_err2:
00961 free(pool->bucketSizes);
00962 out_err1:
00963 free(pool);
00964 out_err0:
00965 free(driPool);
00966
00967 return NULL;
00968 }