| /************************************************************************** |
| * |
| * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, TX., USA |
| * All Rights Reserved. |
| * Copyright 2009 VMware, Inc., Palo Alto, CA., USA |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
| * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, |
| * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| * USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| **************************************************************************/ |
| /* |
| * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <stdint.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <assert.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include "wsbm_pool.h" |
| #include "wsbm_fencemgr.h" |
| #include "wsbm_manager.h" |
| #include "wsbm_mm.h" |
| #include "wsbm_priv.h" |
| |
| /* |
| * Malloced memory must be aligned to 16 bytes, since that's what |
| * the DMA bitblt requires. |
| */ |
| |
| #define WSBM_USER_ALIGN_ADD 16 |
| #define WSBM_USER_ALIGN_SYSMEM(_val) \ |
| ((void *)(((unsigned long) (_val) + 15) & ~15)) |
| |
| struct _WsbmUserBuffer |
| { |
| struct _WsbmBufStorage buf; |
| struct _WsbmKernelBuf kBuf; |
| |
| /* Protected by the pool mutex */ |
| |
| struct _WsbmListHead lru; |
| struct _WsbmListHead delayed; |
| |
| /* Protected by the buffer mutex */ |
| |
| unsigned long size; |
| unsigned long alignment; |
| |
| struct _WsbmCond event; |
| uint32_t proposedPlacement; |
| uint32_t newFenceType; |
| |
| void *map; |
| void *sysmem; |
| int unFenced; |
| struct _WsbmFenceObject *fence; |
| struct _WsbmMMNode *node; |
| |
| struct _WsbmAtomic writers; |
| }; |
| |
| struct _WsbmUserPool |
| { |
| /* |
| * Constant after initialization. |
| */ |
| |
| struct _WsbmBufferPool pool; |
| unsigned long agpOffset; |
| unsigned long agpMap; |
| unsigned long agpSize; |
| unsigned long vramOffset; |
| unsigned long vramMap; |
| unsigned long vramSize; |
| struct _WsbmMutex mutex; |
| struct _WsbmListHead delayed; |
| struct _WsbmListHead vramLRU; |
| struct _WsbmListHead agpLRU; |
| struct _WsbmMM vramMM; |
| struct _WsbmMM agpMM; |
| uint32_t(*fenceTypes) (uint64_t); |
| }; |
| |
| static inline struct _WsbmUserPool * |
| userPool(struct _WsbmUserBuffer *buf) |
| { |
| return containerOf(buf->buf.pool, struct _WsbmUserPool, pool); |
| } |
| |
| static inline struct _WsbmUserBuffer * |
| userBuf(struct _WsbmBufStorage *buf) |
| { |
| return containerOf(buf, struct _WsbmUserBuffer, buf); |
| } |
| |
| static void |
| waitIdleLocked(struct _WsbmBufStorage *buf, int lazy) |
| { |
| struct _WsbmUserBuffer *vBuf = userBuf(buf); |
| |
| while (vBuf->unFenced || vBuf->fence != NULL) { |
| if (vBuf->unFenced) |
| WSBM_COND_WAIT(&vBuf->event, &buf->mutex); |
| |
| if (vBuf->fence != NULL) { |
| if (!wsbmFenceSignaled(vBuf->fence, vBuf->kBuf.fence_type_mask)) { |
| struct _WsbmFenceObject *fence = |
| wsbmFenceReference(vBuf->fence); |
| |
| WSBM_MUTEX_UNLOCK(&buf->mutex); |
| (void)wsbmFenceFinish(fence, vBuf->kBuf.fence_type_mask, |
| lazy); |
| WSBM_MUTEX_LOCK(&buf->mutex); |
| |
| if (vBuf->fence == fence) |
| wsbmFenceUnreference(&vBuf->fence); |
| |
| wsbmFenceUnreference(&fence); |
| } else { |
| wsbmFenceUnreference(&vBuf->fence); |
| } |
| } |
| } |
| } |
| |
| static int |
| pool_waitIdle(struct _WsbmBufStorage *buf, int lazy) |
| { |
| WSBM_MUTEX_UNLOCK(&buf->mutex); |
| waitIdleLocked(buf, lazy); |
| WSBM_MUTEX_UNLOCK(&buf->mutex); |
| |
| return 0; |
| } |
| |
| static int |
| evict_lru(struct _WsbmListHead *lru) |
| { |
| struct _WsbmUserBuffer *vBuf; |
| struct _WsbmUserPool *p; |
| struct _WsbmListHead *list = lru->next; |
| int err; |
| |
| if (list == lru) { |
| return -ENOMEM; |
| } |
| |
| vBuf = WSBMLISTENTRY(list, struct _WsbmUserBuffer, lru); |
| p = userPool(vBuf); |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| WSBM_MUTEX_LOCK(&vBuf->buf.mutex); |
| WSBM_MUTEX_LOCK(&p->mutex); |
| |
| vBuf->sysmem = malloc(vBuf->size + WSBM_USER_ALIGN_ADD); |
| |
| if (!vBuf->sysmem) { |
| err = -ENOMEM; |
| goto out_unlock; |
| } |
| |
| (void)wsbmFenceFinish(vBuf->fence, vBuf->kBuf.fence_type_mask, 0); |
| wsbmFenceUnreference(&vBuf->fence); |
| |
| memcpy(WSBM_USER_ALIGN_SYSMEM(vBuf->sysmem), vBuf->map, vBuf->size); |
| WSBMLISTDELINIT(&vBuf->lru); |
| vBuf->kBuf.placement = WSBM_PL_FLAG_SYSTEM; |
| vBuf->map = WSBM_USER_ALIGN_SYSMEM(vBuf->sysmem); |
| |
| /* |
| * FIXME: Free memory. |
| */ |
| |
| err = 0; |
| out_unlock: |
| WSBM_MUTEX_UNLOCK(&vBuf->buf.mutex); |
| return err; |
| } |
| |
| static struct _WsbmBufStorage * |
| pool_create(struct _WsbmBufferPool *pool, |
| unsigned long size, uint32_t placement, unsigned alignment) |
| { |
| struct _WsbmUserPool *p = containerOf(pool, struct _WsbmUserPool, pool); |
| struct _WsbmUserBuffer *vBuf = calloc(1, sizeof(*vBuf)); |
| |
| if (!vBuf) |
| return NULL; |
| |
| wsbmBufStorageInit(&vBuf->buf, pool); |
| vBuf->sysmem = NULL; |
| vBuf->proposedPlacement = placement; |
| vBuf->size = size; |
| vBuf->alignment = alignment; |
| |
| WSBMINITLISTHEAD(&vBuf->lru); |
| WSBMINITLISTHEAD(&vBuf->delayed); |
| WSBM_MUTEX_LOCK(&p->mutex); |
| |
| if (placement & WSBM_PL_FLAG_TT) { |
| vBuf->node = wsbmMMSearchFree(&p->agpMM, size, alignment, 1); |
| if (vBuf->node) |
| vBuf->node = wsbmMMGetBlock(vBuf->node, size, alignment); |
| |
| if (vBuf->node) { |
| vBuf->kBuf.placement = WSBM_PL_FLAG_TT; |
| vBuf->kBuf.gpuOffset = p->agpOffset + vBuf->node->start; |
| vBuf->map = (void *)(p->agpMap + vBuf->node->start); |
| WSBMLISTADDTAIL(&vBuf->lru, &p->agpLRU); |
| goto have_mem; |
| } |
| } |
| |
| if (placement & WSBM_PL_FLAG_VRAM) { |
| vBuf->node = wsbmMMSearchFree(&p->vramMM, size, alignment, 1); |
| if (vBuf->node) |
| vBuf->node = wsbmMMGetBlock(vBuf->node, size, alignment); |
| |
| if (vBuf->node) { |
| vBuf->kBuf.placement = WSBM_PL_FLAG_VRAM; |
| vBuf->kBuf.gpuOffset = p->vramOffset + vBuf->node->start; |
| vBuf->map = (void *)(p->vramMap + vBuf->node->start); |
| WSBMLISTADDTAIL(&vBuf->lru, &p->vramLRU); |
| goto have_mem; |
| } |
| } |
| |
| if ((placement & WSBM_PL_FLAG_NO_EVICT) |
| && !(placement & WSBM_PL_FLAG_SYSTEM)) { |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| goto out_err; |
| } |
| |
| vBuf->sysmem = malloc(size + WSBM_USER_ALIGN_ADD); |
| vBuf->kBuf.placement = WSBM_PL_FLAG_SYSTEM; |
| vBuf->map = WSBM_USER_ALIGN_SYSMEM(vBuf->sysmem); |
| |
| have_mem: |
| |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| if (vBuf->sysmem != NULL |
| || (!(vBuf->kBuf.placement & WSBM_PL_FLAG_SYSTEM))) |
| return &vBuf->buf; |
| out_err: |
| free(vBuf); |
| return NULL; |
| } |
| |
| static int |
| pool_validate(struct _WsbmBufStorage *buf, uint64_t set_flags, |
| uint64_t clr_flags) |
| { |
| struct _WsbmUserBuffer *vBuf = userBuf(buf); |
| struct _WsbmUserPool *p = userPool(vBuf); |
| int err = -ENOMEM; |
| |
| WSBM_MUTEX_LOCK(&buf->mutex); |
| |
| while (wsbmAtomicRead(&vBuf->writers) != 0) |
| WSBM_COND_WAIT(&vBuf->event, &buf->mutex); |
| |
| vBuf->unFenced = 1; |
| |
| WSBM_MUTEX_LOCK(&p->mutex); |
| WSBMLISTDELINIT(&vBuf->lru); |
| |
| vBuf->proposedPlacement = |
| (vBuf->proposedPlacement | set_flags) & ~clr_flags; |
| |
| if ((vBuf->proposedPlacement & vBuf->kBuf.placement & WSBM_PL_MASK_MEM) == |
| vBuf->kBuf.placement) { |
| err = 0; |
| goto have_mem; |
| } |
| |
| /* |
| * We're moving to another memory region, so evict first and we'll |
| * do a sw copy to the other region. |
| */ |
| |
| if (!(vBuf->kBuf.placement & WSBM_PL_FLAG_SYSTEM)) { |
| struct _WsbmListHead tmpLRU; |
| |
| WSBMINITLISTHEAD(&tmpLRU); |
| WSBMLISTADDTAIL(&tmpLRU, &vBuf->lru); |
| err = evict_lru(&tmpLRU); |
| if (err) |
| goto have_mem; |
| } |
| |
| if (vBuf->proposedPlacement & WSBM_PL_FLAG_TT) { |
| do { |
| vBuf->node = |
| wsbmMMSearchFree(&p->agpMM, vBuf->size, vBuf->alignment, 1); |
| if (vBuf->node) |
| vBuf->node = |
| wsbmMMGetBlock(vBuf->node, vBuf->size, vBuf->alignment); |
| |
| if (vBuf->node) { |
| vBuf->kBuf.placement = WSBM_PL_FLAG_TT; |
| vBuf->kBuf.gpuOffset = p->agpOffset + vBuf->node->start; |
| vBuf->map = (void *)(p->agpMap + vBuf->node->start); |
| memcpy(vBuf->map, WSBM_USER_ALIGN_SYSMEM(vBuf->sysmem), |
| vBuf->size); |
| free(vBuf->sysmem); |
| goto have_mem; |
| } |
| } while (evict_lru(&p->agpLRU) == 0); |
| } |
| |
| if (vBuf->proposedPlacement & WSBM_PL_FLAG_VRAM) { |
| do { |
| vBuf->node = |
| wsbmMMSearchFree(&p->vramMM, vBuf->size, vBuf->alignment, 1); |
| if (vBuf->node) |
| vBuf->node = |
| wsbmMMGetBlock(vBuf->node, vBuf->size, vBuf->alignment); |
| |
| if (!err && vBuf->node) { |
| vBuf->kBuf.placement = WSBM_PL_FLAG_VRAM; |
| vBuf->kBuf.gpuOffset = p->vramOffset + vBuf->node->start; |
| vBuf->map = (void *)(p->vramMap + vBuf->node->start); |
| memcpy(vBuf->map, WSBM_USER_ALIGN_SYSMEM(vBuf->sysmem), |
| vBuf->size); |
| free(vBuf->sysmem); |
| goto have_mem; |
| } |
| } while (evict_lru(&p->vramLRU) == 0); |
| } |
| |
| if (vBuf->proposedPlacement & WSBM_PL_FLAG_SYSTEM) |
| goto have_mem; |
| |
| err = -ENOMEM; |
| |
| have_mem: |
| vBuf->newFenceType = p->fenceTypes(set_flags); |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| WSBM_MUTEX_UNLOCK(&buf->mutex); |
| return err; |
| } |
| |
| static int |
| pool_setStatus(struct _WsbmBufStorage *buf, |
| uint32_t set_placement, uint32_t clr_placement) |
| { |
| struct _WsbmUserBuffer *vBuf = userBuf(buf); |
| int ret; |
| |
| ret = pool_validate(buf, set_placement, clr_placement); |
| vBuf->unFenced = 0; |
| return ret; |
| } |
| |
| void |
| release_delayed_buffers(struct _WsbmUserPool *p) |
| { |
| struct _WsbmUserBuffer *vBuf; |
| struct _WsbmListHead *list, *next; |
| |
| WSBM_MUTEX_LOCK(&p->mutex); |
| |
| /* |
| * We don't need to take the buffer mutexes in this loop, since |
| * the only other user is the evict_lru function, which has the |
| * pool mutex held when accessing the buffer fence member. |
| */ |
| |
| WSBMLISTFOREACHSAFE(list, next, &p->delayed) { |
| vBuf = WSBMLISTENTRY(list, struct _WsbmUserBuffer, delayed); |
| |
| if (!vBuf->fence |
| || wsbmFenceSignaled(vBuf->fence, vBuf->kBuf.fence_type_mask)) { |
| if (vBuf->fence) |
| wsbmFenceUnreference(&vBuf->fence); |
| |
| WSBMLISTDEL(&vBuf->delayed); |
| WSBMLISTDEL(&vBuf->lru); |
| |
| if ((vBuf->kBuf.placement & WSBM_PL_FLAG_SYSTEM) == 0) |
| wsbmMMPutBlock(vBuf->node); |
| else |
| free(vBuf->sysmem); |
| |
| free(vBuf); |
| } else |
| break; |
| |
| } |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| } |
| |
| static void |
| pool_destroy(struct _WsbmBufStorage **buf) |
| { |
| struct _WsbmUserBuffer *vBuf = userBuf(*buf); |
| struct _WsbmUserPool *p = userPool(vBuf); |
| |
| *buf = NULL; |
| |
| WSBM_MUTEX_LOCK(&vBuf->buf.mutex); |
| if ((vBuf->fence |
| && !wsbmFenceSignaled(vBuf->fence, vBuf->kBuf.fence_type_mask))) { |
| WSBM_MUTEX_LOCK(&p->mutex); |
| WSBMLISTADDTAIL(&vBuf->delayed, &p->delayed); |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| WSBM_MUTEX_UNLOCK(&vBuf->buf.mutex); |
| return; |
| } |
| |
| if (vBuf->fence) |
| wsbmFenceUnreference(&vBuf->fence); |
| |
| WSBM_MUTEX_LOCK(&p->mutex); |
| WSBMLISTDEL(&vBuf->lru); |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| |
| if (!(vBuf->kBuf.placement & WSBM_PL_FLAG_SYSTEM)) |
| wsbmMMPutBlock(vBuf->node); |
| else |
| free(vBuf->sysmem); |
| |
| free(vBuf); |
| return; |
| } |
| |
| static int |
| pool_map(struct _WsbmBufStorage *buf, unsigned mode __attribute__ ((unused)), void **virtual) |
| { |
| struct _WsbmUserBuffer *vBuf = userBuf(buf); |
| |
| *virtual = vBuf->map; |
| return 0; |
| } |
| |
| static void |
| pool_unmap(struct _WsbmBufStorage *buf __attribute__ ((unused))) |
| { |
| ; |
| } |
| |
| static void |
| pool_releaseFromCpu(struct _WsbmBufStorage *buf, unsigned mode __attribute__ ((unused))) |
| { |
| struct _WsbmUserBuffer *vBuf = userBuf(buf); |
| |
| if (wsbmAtomicDecZero(&vBuf->writers)) |
| WSBM_COND_BROADCAST(&vBuf->event); |
| |
| } |
| |
| static int |
| pool_syncForCpu(struct _WsbmBufStorage *buf, unsigned mode) |
| { |
| struct _WsbmUserBuffer *vBuf = userBuf(buf); |
| int ret = 0; |
| |
| WSBM_MUTEX_LOCK(&buf->mutex); |
| if ((mode & WSBM_SYNCCPU_DONT_BLOCK)) { |
| |
| if (vBuf->unFenced) { |
| ret = -EBUSY; |
| goto out_unlock; |
| } |
| |
| ret = 0; |
| if ((vBuf->fence == NULL) || |
| wsbmFenceSignaled(vBuf->fence, vBuf->kBuf.fence_type_mask)) { |
| wsbmFenceUnreference(&vBuf->fence); |
| wsbmAtomicInc(&vBuf->writers); |
| } else |
| ret = -EBUSY; |
| |
| goto out_unlock; |
| } |
| waitIdleLocked(buf, 0); |
| wsbmAtomicInc(&vBuf->writers); |
| out_unlock: |
| WSBM_MUTEX_UNLOCK(&buf->mutex); |
| return ret; |
| } |
| |
| static unsigned long |
| pool_offset(struct _WsbmBufStorage *buf) |
| { |
| return userBuf(buf)->kBuf.gpuOffset; |
| } |
| |
| static unsigned long |
| pool_poolOffset(struct _WsbmBufStorage *buf __attribute__ ((unused))) |
| { |
| return 0UL; |
| } |
| |
| static unsigned long |
| pool_size(struct _WsbmBufStorage *buf) |
| { |
| return userBuf(buf)->size; |
| } |
| |
| static void |
| pool_fence(struct _WsbmBufStorage *buf, struct _WsbmFenceObject *fence) |
| { |
| struct _WsbmUserBuffer *vBuf = userBuf(buf); |
| struct _WsbmUserPool *p = userPool(vBuf); |
| |
| WSBM_MUTEX_LOCK(&buf->mutex); |
| |
| if (vBuf->fence) |
| wsbmFenceUnreference(&vBuf->fence); |
| |
| vBuf->fence = wsbmFenceReference(fence); |
| vBuf->unFenced = 0; |
| vBuf->kBuf.fence_type_mask = vBuf->newFenceType; |
| |
| WSBM_COND_BROADCAST(&vBuf->event); |
| WSBM_MUTEX_LOCK(&p->mutex); |
| if (vBuf->kBuf.placement & WSBM_PL_FLAG_VRAM) |
| WSBMLISTADDTAIL(&vBuf->lru, &p->vramLRU); |
| else if (vBuf->kBuf.placement & WSBM_PL_FLAG_TT) |
| WSBMLISTADDTAIL(&vBuf->lru, &p->agpLRU); |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| WSBM_MUTEX_UNLOCK(&buf->mutex); |
| } |
| |
| static void |
| pool_unvalidate(struct _WsbmBufStorage *buf) |
| { |
| struct _WsbmUserBuffer *vBuf = userBuf(buf); |
| struct _WsbmUserPool *p = userPool(vBuf); |
| |
| WSBM_MUTEX_LOCK(&buf->mutex); |
| |
| if (!vBuf->unFenced) |
| goto out_unlock; |
| |
| vBuf->unFenced = 0; |
| WSBM_COND_BROADCAST(&vBuf->event); |
| WSBM_MUTEX_LOCK(&p->mutex); |
| if (vBuf->kBuf.placement & WSBM_PL_FLAG_VRAM) |
| WSBMLISTADDTAIL(&vBuf->lru, &p->vramLRU); |
| else if (vBuf->kBuf.placement & WSBM_PL_FLAG_TT) |
| WSBMLISTADDTAIL(&vBuf->lru, &p->agpLRU); |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| |
| out_unlock: |
| |
| WSBM_MUTEX_UNLOCK(&buf->mutex); |
| } |
| |
| static struct _WsbmKernelBuf * |
| pool_kernel(struct _WsbmBufStorage *buf) |
| { |
| struct _WsbmUserBuffer *vBuf = userBuf(buf); |
| |
| return &vBuf->kBuf; |
| } |
| |
| static void |
| pool_takedown(struct _WsbmBufferPool *pool) |
| { |
| struct _WsbmUserPool *p = containerOf(pool, struct _WsbmUserPool, pool); |
| int empty; |
| |
| do { |
| release_delayed_buffers(p); |
| WSBM_MUTEX_LOCK(&p->mutex); |
| empty = (p->delayed.next == &p->delayed); |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| |
| if (!empty) |
| usleep(1000); |
| |
| } while (!empty); |
| WSBM_MUTEX_LOCK(&p->mutex); |
| |
| while (evict_lru(&p->vramLRU) == 0) ; |
| while (evict_lru(&p->agpLRU) == 0) ; |
| |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| |
| wsbmMMtakedown(&p->agpMM); |
| wsbmMMtakedown(&p->vramMM); |
| |
| free(p); |
| } |
| |
| void |
| wsbmUserPoolClean(struct _WsbmBufferPool *pool, int cleanVram, int cleanAgp) |
| { |
| struct _WsbmUserPool *p = containerOf(pool, struct _WsbmUserPool, pool); |
| |
| WSBM_MUTEX_LOCK(&p->mutex); |
| if (cleanVram) |
| while (evict_lru(&p->vramLRU) == 0) ; |
| if (cleanAgp) |
| while (evict_lru(&p->agpLRU) == 0) ; |
| WSBM_MUTEX_UNLOCK(&p->mutex); |
| } |
| |
| struct _WsbmBufferPool * |
| wsbmUserPoolInit(void *vramAddr, |
| unsigned long vramStart, unsigned long vramSize, |
| void *agpAddr, unsigned long agpStart, |
| unsigned long agpSize, |
| uint32_t(*fenceTypes) (uint64_t set_flags)) |
| { |
| struct _WsbmBufferPool *pool; |
| struct _WsbmUserPool *uPool; |
| int ret; |
| |
| uPool = calloc(1, sizeof(*uPool)); |
| if (!uPool) |
| goto out_err0; |
| |
| ret = WSBM_MUTEX_INIT(&uPool->mutex); |
| if (ret) |
| goto out_err0; |
| |
| ret = wsbmMMinit(&uPool->vramMM, 0, vramSize); |
| if (ret) |
| goto out_err1; |
| |
| ret = wsbmMMinit(&uPool->agpMM, 0, agpSize); |
| if (ret) |
| goto out_err2; |
| |
| WSBMINITLISTHEAD(&uPool->delayed); |
| WSBMINITLISTHEAD(&uPool->vramLRU); |
| WSBMINITLISTHEAD(&uPool->agpLRU); |
| |
| uPool->agpOffset = agpStart; |
| uPool->agpMap = (unsigned long)agpAddr; |
| uPool->vramOffset = vramStart; |
| uPool->vramMap = (unsigned long)vramAddr; |
| uPool->fenceTypes = fenceTypes; |
| |
| pool = &uPool->pool; |
| pool->map = &pool_map; |
| pool->unmap = &pool_unmap; |
| pool->destroy = &pool_destroy; |
| pool->offset = &pool_offset; |
| pool->poolOffset = &pool_poolOffset; |
| pool->size = &pool_size; |
| pool->create = &pool_create; |
| pool->fence = &pool_fence; |
| pool->unvalidate = &pool_unvalidate; |
| pool->kernel = &pool_kernel; |
| pool->validate = &pool_validate; |
| pool->waitIdle = &pool_waitIdle; |
| pool->takeDown = &pool_takedown; |
| pool->setStatus = &pool_setStatus; |
| pool->syncforcpu = &pool_syncForCpu; |
| pool->releasefromcpu = &pool_releaseFromCpu; |
| |
| return pool; |
| |
| out_err2: |
| wsbmMMtakedown(&uPool->vramMM); |
| out_err1: |
| WSBM_MUTEX_FREE(&uPool->mutex); |
| out_err0: |
| free(uPool); |
| |
| return NULL; |
| } |