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 *
userPool(struct _WsbmUserBuffer * buf)109 userPool(struct _WsbmUserBuffer *buf)
110 {
111     return containerOf(buf->buf.pool, struct _WsbmUserPool, pool);
112 }
113 
114 static inline struct _WsbmUserBuffer *
userBuf(struct _WsbmBufStorage * buf)115 userBuf(struct _WsbmBufStorage *buf)
116 {
117     return containerOf(buf, struct _WsbmUserBuffer, buf);
118 }
119 
120 static void
waitIdleLocked(struct _WsbmBufStorage * buf,int lazy)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
pool_waitIdle(struct _WsbmBufStorage * buf,int lazy)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
evict_lru(struct _WsbmListHead * lru)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 *
pool_create(struct _WsbmBufferPool * pool,unsigned long size,uint32_t placement,unsigned alignment)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
pool_validate(struct _WsbmBufStorage * buf,uint64_t set_flags,uint64_t clr_flags)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 && vBuf->node) {
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
pool_setStatus(struct _WsbmBufStorage * buf,uint32_t set_placement,uint32_t clr_placement)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
release_delayed_buffers(struct _WsbmUserPool * p)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
pool_destroy(struct _WsbmBufStorage ** buf)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
pool_map(struct _WsbmBufStorage * buf,unsigned mode,void ** virtual)451 pool_map(struct _WsbmBufStorage *buf, unsigned mode __attribute__ ((unused)), void **virtual)
452 {
453     struct _WsbmUserBuffer *vBuf = userBuf(buf);
454 
455     *virtual = vBuf->map;
456     return 0;
457 }
458 
459 static void
pool_unmap(struct _WsbmBufStorage * buf)460 pool_unmap(struct _WsbmBufStorage *buf __attribute__ ((unused)))
461 {
462     ;
463 }
464 
465 static void
pool_releaseFromCpu(struct _WsbmBufStorage * buf,unsigned mode)466 pool_releaseFromCpu(struct _WsbmBufStorage *buf, unsigned mode __attribute__ ((unused)))
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
pool_syncForCpu(struct _WsbmBufStorage * buf,unsigned mode)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
pool_offset(struct _WsbmBufStorage * buf)507 pool_offset(struct _WsbmBufStorage *buf)
508 {
509     return userBuf(buf)->kBuf.gpuOffset;
510 }
511 
512 static unsigned long
pool_poolOffset(struct _WsbmBufStorage * buf)513 pool_poolOffset(struct _WsbmBufStorage *buf __attribute__ ((unused)))
514 {
515     return 0UL;
516 }
517 
518 static unsigned long
pool_size(struct _WsbmBufStorage * buf)519 pool_size(struct _WsbmBufStorage *buf)
520 {
521     return userBuf(buf)->size;
522 }
523 
524 static void
pool_fence(struct _WsbmBufStorage * buf,struct _WsbmFenceObject * fence)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
pool_unvalidate(struct _WsbmBufStorage * buf)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 *
pool_kernel(struct _WsbmBufStorage * buf)575 pool_kernel(struct _WsbmBufStorage *buf)
576 {
577     struct _WsbmUserBuffer *vBuf = userBuf(buf);
578 
579     return &vBuf->kBuf;
580 }
581 
582 static void
pool_takedown(struct _WsbmBufferPool * pool)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
wsbmUserPoolClean(struct _WsbmBufferPool * pool,int cleanVram,int cleanAgp)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 *
wsbmUserPoolInit(void * vramAddr,unsigned long vramStart,unsigned long vramSize,void * agpAddr,unsigned long agpStart,unsigned long agpSize,uint32_t (* fenceTypes)(uint64_t set_flags))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 }
690