merge with master
[platform/upstream/libwsbm.git] / src / wsbm_userpool.c
1 /**************************************************************************
2  *
3  * Copyright 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 Hellstrom <thomas-at-tungstengraphics-dot-com>
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <stdint.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <assert.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include "wsbm_pool.h"
44 #include "wsbm_fencemgr.h"
45 #include "wsbm_manager.h"
46 #include "wsbm_mm.h"
47 #include "wsbm_priv.h"
48
49 /*
50  * Malloced memory must be aligned to 16 bytes, since that's what
51  * the DMA bitblt requires.
52  */
53
54 #define WSBM_USER_ALIGN_ADD 16
55 #define WSBM_USER_ALIGN_SYSMEM(_val) \
56     ((void *)(((unsigned long) (_val) + 15) & ~15))
57
58 struct _WsbmUserBuffer
59 {
60     struct _WsbmBufStorage buf;
61     struct _WsbmKernelBuf kBuf;
62
63     /* Protected by the pool mutex */
64
65     struct _WsbmListHead lru;
66     struct _WsbmListHead delayed;
67
68     /* Protected by the buffer mutex */
69
70     unsigned long size;
71     unsigned long alignment;
72
73     struct _WsbmCond event;
74     uint32_t proposedPlacement;
75     uint32_t newFenceType;
76
77     void *map;
78     void *sysmem;
79     int unFenced;
80     struct _WsbmFenceObject *fence;
81     struct _WsbmMMNode *node;
82
83     struct _WsbmAtomic writers;
84 };
85
86 struct _WsbmUserPool
87 {
88     /*
89      * Constant after initialization.
90      */
91
92     struct _WsbmBufferPool pool;
93     unsigned long agpOffset;
94     unsigned long agpMap;
95     unsigned long agpSize;
96     unsigned long vramOffset;
97     unsigned long vramMap;
98     unsigned long vramSize;
99     struct _WsbmMutex mutex;
100     struct _WsbmListHead delayed;
101     struct _WsbmListHead vramLRU;
102     struct _WsbmListHead agpLRU;
103     struct _WsbmMM vramMM;
104     struct _WsbmMM agpMM;
105         uint32_t(*fenceTypes) (uint64_t);
106 };
107
108 static inline struct _WsbmUserPool *
109 userPool(struct _WsbmUserBuffer *buf)
110 {
111     return containerOf(buf->buf.pool, struct _WsbmUserPool, pool);
112 }
113
114 static inline struct _WsbmUserBuffer *
115 userBuf(struct _WsbmBufStorage *buf)
116 {
117     return containerOf(buf, struct _WsbmUserBuffer, buf);
118 }
119
120 static void
121 waitIdleLocked(struct _WsbmBufStorage *buf, int lazy)
122 {
123     struct _WsbmUserBuffer *vBuf = userBuf(buf);
124
125     while (vBuf->unFenced || vBuf->fence != NULL) {
126         if (vBuf->unFenced)
127             WSBM_COND_WAIT(&vBuf->event, &buf->mutex);
128
129         if (vBuf->fence != NULL) {
130             if (!wsbmFenceSignaled(vBuf->fence, vBuf->kBuf.fence_type_mask)) {
131                 struct _WsbmFenceObject *fence =
132                     wsbmFenceReference(vBuf->fence);
133
134                 WSBM_MUTEX_UNLOCK(&buf->mutex);
135                 (void)wsbmFenceFinish(fence, vBuf->kBuf.fence_type_mask,
136                                       lazy);
137                 WSBM_MUTEX_LOCK(&buf->mutex);
138
139                 if (vBuf->fence == fence)
140                     wsbmFenceUnreference(&vBuf->fence);
141
142                 wsbmFenceUnreference(&fence);
143             } else {
144                 wsbmFenceUnreference(&vBuf->fence);
145             }
146         }
147     }
148 }
149
150 static int
151 pool_waitIdle(struct _WsbmBufStorage *buf, int lazy)
152 {
153     WSBM_MUTEX_UNLOCK(&buf->mutex);
154     waitIdleLocked(buf, lazy);
155     WSBM_MUTEX_UNLOCK(&buf->mutex);
156
157     return 0;
158 }
159
160 static int
161 evict_lru(struct _WsbmListHead *lru)
162 {
163     struct _WsbmUserBuffer *vBuf;
164     struct _WsbmUserPool *p;
165     struct _WsbmListHead *list = lru->next;
166     int err;
167
168     if (list == lru) {
169         return -ENOMEM;
170     }
171
172     vBuf = WSBMLISTENTRY(list, struct _WsbmUserBuffer, lru);
173     p = userPool(vBuf);
174     WSBM_MUTEX_UNLOCK(&p->mutex);
175     WSBM_MUTEX_LOCK(&vBuf->buf.mutex);
176     WSBM_MUTEX_LOCK(&p->mutex);
177
178     vBuf->sysmem = malloc(vBuf->size + WSBM_USER_ALIGN_ADD);
179
180     if (!vBuf->sysmem) {
181         err = -ENOMEM;
182         goto out_unlock;
183     }
184
185     (void)wsbmFenceFinish(vBuf->fence, vBuf->kBuf.fence_type_mask, 0);
186     wsbmFenceUnreference(&vBuf->fence);
187
188     memcpy(WSBM_USER_ALIGN_SYSMEM(vBuf->sysmem), vBuf->map, vBuf->size);
189     WSBMLISTDELINIT(&vBuf->lru);
190     vBuf->kBuf.placement = WSBM_PL_FLAG_SYSTEM;
191     vBuf->map = WSBM_USER_ALIGN_SYSMEM(vBuf->sysmem);
192
193     /*
194      * FIXME: Free memory.
195      */
196
197     err = 0;
198   out_unlock:
199     WSBM_MUTEX_UNLOCK(&vBuf->buf.mutex);
200     return err;
201 }
202
203 static struct _WsbmBufStorage *
204 pool_create(struct _WsbmBufferPool *pool,
205             unsigned long size, uint32_t placement, unsigned alignment)
206 {
207     struct _WsbmUserPool *p = containerOf(pool, struct _WsbmUserPool, pool);
208     struct _WsbmUserBuffer *vBuf = calloc(1, sizeof(*vBuf));
209
210     if (!vBuf)
211         return NULL;
212
213     wsbmBufStorageInit(&vBuf->buf, pool);
214     vBuf->sysmem = NULL;
215     vBuf->proposedPlacement = placement;
216     vBuf->size = size;
217     vBuf->alignment = alignment;
218
219     WSBMINITLISTHEAD(&vBuf->lru);
220     WSBMINITLISTHEAD(&vBuf->delayed);
221     WSBM_MUTEX_LOCK(&p->mutex);
222
223     if (placement & WSBM_PL_FLAG_TT) {
224         vBuf->node = wsbmMMSearchFree(&p->agpMM, size, alignment, 1);
225         if (vBuf->node)
226             vBuf->node = wsbmMMGetBlock(vBuf->node, size, alignment);
227
228         if (vBuf->node) {
229             vBuf->kBuf.placement = WSBM_PL_FLAG_TT;
230             vBuf->kBuf.gpuOffset = p->agpOffset + vBuf->node->start;
231             vBuf->map = (void *)(p->agpMap + vBuf->node->start);
232             WSBMLISTADDTAIL(&vBuf->lru, &p->agpLRU);
233             goto have_mem;
234         }
235     }
236
237     if (placement & WSBM_PL_FLAG_VRAM) {
238         vBuf->node = wsbmMMSearchFree(&p->vramMM, size, alignment, 1);
239         if (vBuf->node)
240             vBuf->node = wsbmMMGetBlock(vBuf->node, size, alignment);
241
242         if (vBuf->node) {
243             vBuf->kBuf.placement = WSBM_PL_FLAG_VRAM;
244             vBuf->kBuf.gpuOffset = p->vramOffset + vBuf->node->start;
245             vBuf->map = (void *)(p->vramMap + vBuf->node->start);
246             WSBMLISTADDTAIL(&vBuf->lru, &p->vramLRU);
247             goto have_mem;
248         }
249     }
250
251     if ((placement & WSBM_PL_FLAG_NO_EVICT)
252         && !(placement & WSBM_PL_FLAG_SYSTEM)) {
253         WSBM_MUTEX_UNLOCK(&p->mutex);
254         goto out_err;
255     }
256
257     vBuf->sysmem = malloc(size + WSBM_USER_ALIGN_ADD);
258     vBuf->kBuf.placement = WSBM_PL_FLAG_SYSTEM;
259     vBuf->map = WSBM_USER_ALIGN_SYSMEM(vBuf->sysmem);
260
261   have_mem:
262
263     WSBM_MUTEX_UNLOCK(&p->mutex);
264     if (vBuf->sysmem != NULL
265         || (!(vBuf->kBuf.placement & WSBM_PL_FLAG_SYSTEM)))
266         return &vBuf->buf;
267   out_err:
268     free(vBuf);
269     return NULL;
270 }
271
272 static int
273 pool_validate(struct _WsbmBufStorage *buf, uint64_t set_flags,
274               uint64_t clr_flags)
275 {
276     struct _WsbmUserBuffer *vBuf = userBuf(buf);
277     struct _WsbmUserPool *p = userPool(vBuf);
278     int err = -ENOMEM;
279
280     WSBM_MUTEX_LOCK(&buf->mutex);
281
282     while (wsbmAtomicRead(&vBuf->writers) != 0)
283         WSBM_COND_WAIT(&vBuf->event, &buf->mutex);
284
285     vBuf->unFenced = 1;
286
287     WSBM_MUTEX_LOCK(&p->mutex);
288     WSBMLISTDELINIT(&vBuf->lru);
289
290     vBuf->proposedPlacement =
291         (vBuf->proposedPlacement | set_flags) & ~clr_flags;
292
293     if ((vBuf->proposedPlacement & vBuf->kBuf.placement & WSBM_PL_MASK_MEM) ==
294         vBuf->kBuf.placement) {
295         err = 0;
296         goto have_mem;
297     }
298
299     /*
300      * We're moving to another memory region, so evict first and we'll
301      * do a sw copy to the other region.
302      */
303
304     if (!(vBuf->kBuf.placement & WSBM_PL_FLAG_SYSTEM)) {
305         struct _WsbmListHead tmpLRU;
306
307         WSBMINITLISTHEAD(&tmpLRU);
308         WSBMLISTADDTAIL(&tmpLRU, &vBuf->lru);
309         err = evict_lru(&tmpLRU);
310         if (err)
311             goto have_mem;
312     }
313
314     if (vBuf->proposedPlacement & WSBM_PL_FLAG_TT) {
315         do {
316             vBuf->node =
317                 wsbmMMSearchFree(&p->agpMM, vBuf->size, vBuf->alignment, 1);
318             if (vBuf->node)
319                 vBuf->node =
320                     wsbmMMGetBlock(vBuf->node, vBuf->size, vBuf->alignment);
321
322             if (vBuf->node) {
323                 vBuf->kBuf.placement = WSBM_PL_FLAG_TT;
324                 vBuf->kBuf.gpuOffset = p->agpOffset + vBuf->node->start;
325                 vBuf->map = (void *)(p->agpMap + vBuf->node->start);
326                 memcpy(vBuf->map, WSBM_USER_ALIGN_SYSMEM(vBuf->sysmem),
327                        vBuf->size);
328                 free(vBuf->sysmem);
329                 goto have_mem;
330             }
331         } while (evict_lru(&p->agpLRU) == 0);
332     }
333
334     if (vBuf->proposedPlacement & WSBM_PL_FLAG_VRAM) {
335         do {
336             vBuf->node =
337                 wsbmMMSearchFree(&p->vramMM, vBuf->size, vBuf->alignment, 1);
338             if (vBuf->node)
339                 vBuf->node =
340                     wsbmMMGetBlock(vBuf->node, vBuf->size, vBuf->alignment);
341
342             if (!err) {
343                 vBuf->kBuf.placement = WSBM_PL_FLAG_VRAM;
344                 vBuf->kBuf.gpuOffset = p->vramOffset + vBuf->node->start;
345                 vBuf->map = (void *)(p->vramMap + vBuf->node->start);
346                 memcpy(vBuf->map, WSBM_USER_ALIGN_SYSMEM(vBuf->sysmem),
347                        vBuf->size);
348                 free(vBuf->sysmem);
349                 goto have_mem;
350             }
351         } while (evict_lru(&p->vramLRU) == 0);
352     }
353
354     if (vBuf->proposedPlacement & WSBM_PL_FLAG_SYSTEM)
355         goto have_mem;
356
357     err = -ENOMEM;
358
359   have_mem:
360     vBuf->newFenceType = p->fenceTypes(set_flags);
361     WSBM_MUTEX_UNLOCK(&p->mutex);
362     WSBM_MUTEX_UNLOCK(&buf->mutex);
363     return err;
364 }
365
366 static int
367 pool_setStatus(struct _WsbmBufStorage *buf,
368                uint32_t set_placement, uint32_t clr_placement)
369 {
370     struct _WsbmUserBuffer *vBuf = userBuf(buf);
371     int ret;
372
373     ret = pool_validate(buf, set_placement, clr_placement);
374     vBuf->unFenced = 0;
375     return ret;
376 }
377
378 void
379 release_delayed_buffers(struct _WsbmUserPool *p)
380 {
381     struct _WsbmUserBuffer *vBuf;
382     struct _WsbmListHead *list, *next;
383
384     WSBM_MUTEX_LOCK(&p->mutex);
385
386     /*
387      * We don't need to take the buffer mutexes in this loop, since
388      * the only other user is the evict_lru function, which has the
389      * pool mutex held when accessing the buffer fence member.
390      */
391
392     WSBMLISTFOREACHSAFE(list, next, &p->delayed) {
393         vBuf = WSBMLISTENTRY(list, struct _WsbmUserBuffer, delayed);
394
395         if (!vBuf->fence
396             || wsbmFenceSignaled(vBuf->fence, vBuf->kBuf.fence_type_mask)) {
397             if (vBuf->fence)
398                 wsbmFenceUnreference(&vBuf->fence);
399
400             WSBMLISTDEL(&vBuf->delayed);
401             WSBMLISTDEL(&vBuf->lru);
402
403             if ((vBuf->kBuf.placement & WSBM_PL_FLAG_SYSTEM) == 0)
404                 wsbmMMPutBlock(vBuf->node);
405             else
406                 free(vBuf->sysmem);
407
408             free(vBuf);
409         } else
410             break;
411
412     }
413     WSBM_MUTEX_UNLOCK(&p->mutex);
414 }
415
416 static void
417 pool_destroy(struct _WsbmBufStorage **buf)
418 {
419     struct _WsbmUserBuffer *vBuf = userBuf(*buf);
420     struct _WsbmUserPool *p = userPool(vBuf);
421
422     *buf = NULL;
423
424     WSBM_MUTEX_LOCK(&vBuf->buf.mutex);
425     if ((vBuf->fence
426          && !wsbmFenceSignaled(vBuf->fence, vBuf->kBuf.fence_type_mask))) {
427         WSBM_MUTEX_LOCK(&p->mutex);
428         WSBMLISTADDTAIL(&vBuf->delayed, &p->delayed);
429         WSBM_MUTEX_UNLOCK(&p->mutex);
430         WSBM_MUTEX_UNLOCK(&vBuf->buf.mutex);
431         return;
432     }
433
434     if (vBuf->fence)
435         wsbmFenceUnreference(&vBuf->fence);
436
437     WSBM_MUTEX_LOCK(&p->mutex);
438     WSBMLISTDEL(&vBuf->lru);
439     WSBM_MUTEX_UNLOCK(&p->mutex);
440
441     if (!(vBuf->kBuf.placement & WSBM_PL_FLAG_SYSTEM))
442         wsbmMMPutBlock(vBuf->node);
443     else
444         free(vBuf->sysmem);
445
446     free(vBuf);
447     return;
448 }
449
450 static int
451 pool_map(struct _WsbmBufStorage *buf, unsigned mode, void **virtual)
452 {
453     struct _WsbmUserBuffer *vBuf = userBuf(buf);
454
455     *virtual = vBuf->map;
456     return 0;
457 }
458
459 static void
460 pool_unmap(struct _WsbmBufStorage *buf)
461 {
462     ;
463 }
464
465 static void
466 pool_releaseFromCpu(struct _WsbmBufStorage *buf, unsigned mode)
467 {
468     struct _WsbmUserBuffer *vBuf = userBuf(buf);
469
470     if (wsbmAtomicDecZero(&vBuf->writers))
471         WSBM_COND_BROADCAST(&vBuf->event);
472
473 }
474
475 static int
476 pool_syncForCpu(struct _WsbmBufStorage *buf, unsigned mode)
477 {
478     struct _WsbmUserBuffer *vBuf = userBuf(buf);
479     int ret = 0;
480
481     WSBM_MUTEX_LOCK(&buf->mutex);
482     if ((mode & WSBM_SYNCCPU_DONT_BLOCK)) {
483
484         if (vBuf->unFenced) {
485             ret = -EBUSY;
486             goto out_unlock;
487         }
488
489         ret = 0;
490         if ((vBuf->fence == NULL) ||
491             wsbmFenceSignaled(vBuf->fence, vBuf->kBuf.fence_type_mask)) {
492             wsbmFenceUnreference(&vBuf->fence);
493             wsbmAtomicInc(&vBuf->writers);
494         } else
495             ret = -EBUSY;
496
497         goto out_unlock;
498     }
499     waitIdleLocked(buf, 0);
500     wsbmAtomicInc(&vBuf->writers);
501   out_unlock:
502     WSBM_MUTEX_UNLOCK(&buf->mutex);
503     return ret;
504 }
505
506 static unsigned long
507 pool_offset(struct _WsbmBufStorage *buf)
508 {
509     return userBuf(buf)->kBuf.gpuOffset;
510 }
511
512 static unsigned long
513 pool_poolOffset(struct _WsbmBufStorage *buf)
514 {
515     return 0UL;
516 }
517
518 static unsigned long
519 pool_size(struct _WsbmBufStorage *buf)
520 {
521     return userBuf(buf)->size;
522 }
523
524 static void
525 pool_fence(struct _WsbmBufStorage *buf, struct _WsbmFenceObject *fence)
526 {
527     struct _WsbmUserBuffer *vBuf = userBuf(buf);
528     struct _WsbmUserPool *p = userPool(vBuf);
529
530     WSBM_MUTEX_LOCK(&buf->mutex);
531
532     if (vBuf->fence)
533         wsbmFenceUnreference(&vBuf->fence);
534
535     vBuf->fence = wsbmFenceReference(fence);
536     vBuf->unFenced = 0;
537     vBuf->kBuf.fence_type_mask = vBuf->newFenceType;
538
539     WSBM_COND_BROADCAST(&vBuf->event);
540     WSBM_MUTEX_LOCK(&p->mutex);
541     if (vBuf->kBuf.placement & WSBM_PL_FLAG_VRAM)
542         WSBMLISTADDTAIL(&vBuf->lru, &p->vramLRU);
543     else if (vBuf->kBuf.placement & WSBM_PL_FLAG_TT)
544         WSBMLISTADDTAIL(&vBuf->lru, &p->agpLRU);
545     WSBM_MUTEX_UNLOCK(&p->mutex);
546     WSBM_MUTEX_UNLOCK(&buf->mutex);
547 }
548
549 static void
550 pool_unvalidate(struct _WsbmBufStorage *buf)
551 {
552     struct _WsbmUserBuffer *vBuf = userBuf(buf);
553     struct _WsbmUserPool *p = userPool(vBuf);
554
555     WSBM_MUTEX_LOCK(&buf->mutex);
556
557     if (!vBuf->unFenced)
558         goto out_unlock;
559
560     vBuf->unFenced = 0;
561     WSBM_COND_BROADCAST(&vBuf->event);
562     WSBM_MUTEX_LOCK(&p->mutex);
563     if (vBuf->kBuf.placement & WSBM_PL_FLAG_VRAM)
564         WSBMLISTADDTAIL(&vBuf->lru, &p->vramLRU);
565     else if (vBuf->kBuf.placement & WSBM_PL_FLAG_TT)
566         WSBMLISTADDTAIL(&vBuf->lru, &p->agpLRU);
567     WSBM_MUTEX_UNLOCK(&p->mutex);
568
569   out_unlock:
570
571     WSBM_MUTEX_UNLOCK(&buf->mutex);
572 }
573
574 static struct _WsbmKernelBuf *
575 pool_kernel(struct _WsbmBufStorage *buf)
576 {
577     struct _WsbmUserBuffer *vBuf = userBuf(buf);
578
579     return &vBuf->kBuf;
580 }
581
582 static void
583 pool_takedown(struct _WsbmBufferPool *pool)
584 {
585     struct _WsbmUserPool *p = containerOf(pool, struct _WsbmUserPool, pool);
586     int empty;
587
588     do {
589         release_delayed_buffers(p);
590         WSBM_MUTEX_LOCK(&p->mutex);
591         empty = (p->delayed.next == &p->delayed);
592         WSBM_MUTEX_UNLOCK(&p->mutex);
593
594         if (!empty)
595             usleep(1000);
596
597     } while (!empty);
598     WSBM_MUTEX_LOCK(&p->mutex);
599
600     while (evict_lru(&p->vramLRU) == 0) ;
601     while (evict_lru(&p->agpLRU) == 0) ;
602
603     WSBM_MUTEX_UNLOCK(&p->mutex);
604
605     wsbmMMtakedown(&p->agpMM);
606     wsbmMMtakedown(&p->vramMM);
607
608     free(p);
609 }
610
611 void
612 wsbmUserPoolClean(struct _WsbmBufferPool *pool, int cleanVram, int cleanAgp)
613 {
614     struct _WsbmUserPool *p = containerOf(pool, struct _WsbmUserPool, pool);
615
616     WSBM_MUTEX_LOCK(&p->mutex);
617     if (cleanVram)
618         while (evict_lru(&p->vramLRU) == 0) ;
619     if (cleanAgp)
620         while (evict_lru(&p->agpLRU) == 0) ;
621     WSBM_MUTEX_UNLOCK(&p->mutex);
622 }
623
624 struct _WsbmBufferPool *
625 wsbmUserPoolInit(void *vramAddr,
626                  unsigned long vramStart, unsigned long vramSize,
627                  void *agpAddr, unsigned long agpStart,
628                  unsigned long agpSize,
629                  uint32_t(*fenceTypes) (uint64_t set_flags))
630 {
631     struct _WsbmBufferPool *pool;
632     struct _WsbmUserPool *uPool;
633     int ret;
634
635     uPool = calloc(1, sizeof(*uPool));
636     if (!uPool)
637         goto out_err0;
638
639     ret = WSBM_MUTEX_INIT(&uPool->mutex);
640     if (ret)
641         goto out_err0;
642
643     ret = wsbmMMinit(&uPool->vramMM, 0, vramSize);
644     if (ret)
645         goto out_err1;
646
647     ret = wsbmMMinit(&uPool->agpMM, 0, agpSize);
648     if (ret)
649         goto out_err2;
650
651     WSBMINITLISTHEAD(&uPool->delayed);
652     WSBMINITLISTHEAD(&uPool->vramLRU);
653     WSBMINITLISTHEAD(&uPool->agpLRU);
654
655     uPool->agpOffset = agpStart;
656     uPool->agpMap = (unsigned long)agpAddr;
657     uPool->vramOffset = vramStart;
658     uPool->vramMap = (unsigned long)vramAddr;
659     uPool->fenceTypes = fenceTypes;
660
661     pool = &uPool->pool;
662     pool->map = &pool_map;
663     pool->unmap = &pool_unmap;
664     pool->destroy = &pool_destroy;
665     pool->offset = &pool_offset;
666     pool->poolOffset = &pool_poolOffset;
667     pool->size = &pool_size;
668     pool->create = &pool_create;
669     pool->fence = &pool_fence;
670     pool->unvalidate = &pool_unvalidate;
671     pool->kernel = &pool_kernel;
672     pool->validate = &pool_validate;
673     pool->waitIdle = &pool_waitIdle;
674     pool->takeDown = &pool_takedown;
675     pool->setStatus = &pool_setStatus;
676     pool->syncforcpu = &pool_syncForCpu;
677     pool->releasefromcpu = &pool_releaseFromCpu;
678
679     return pool;
680
681   out_err2:
682     wsbmMMtakedown(&uPool->vramMM);
683   out_err1:
684     WSBM_MUTEX_FREE(&uPool->mutex);
685   out_err0:
686     free(uPool);
687
688     return NULL;
689 }