682f56b073df62bb429865094085720415892b4e
[profile/ivi/libdrm.git] / bsd / drm_lists.h
1 /* drm_lists.h -- Buffer list handling routines -*- linux-c -*-
2  * Created: Mon Apr 19 20:54:22 1999 by faith@valinux.com
3  *
4  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
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 "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the next
16  * paragraph) shall be included in all copies or substantial portions of the
17  * Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * Authors:
28  *    Rickard E. (Rik) Faith <faith@valinux.com>
29  *    Gareth Hughes <gareth@valinux.com>
30  */
31
32 #define __NO_VERSION__
33 #include "drmP.h"
34
35 #if __HAVE_DMA_WAITLIST
36
37 int DRM(waitlist_create)(drm_waitlist_t *bl, int count)
38 {
39         if (bl->count)
40                 DRM_OS_RETURN( EINVAL );
41
42         bl->bufs       = DRM(alloc)((bl->count + 2) * sizeof(*bl->bufs),
43                                     DRM_MEM_BUFLISTS);
44
45         if(!bl->bufs) DRM_OS_RETURN(ENOMEM);
46
47         memset(bl->bufs, 0, sizeof(*bl->bufs));
48
49         bl->count      = count;
50         bl->rp         = bl->bufs;
51         bl->wp         = bl->bufs;
52         bl->end        = &bl->bufs[bl->count+1];
53         DRM_OS_SPININIT( bl->write_lock, "writelock" );
54         DRM_OS_SPININIT( bl->read_lock, "readlock" );
55         return 0;
56 }
57
58 int DRM(waitlist_destroy)(drm_waitlist_t *bl)
59 {
60         if (bl->rp != bl->wp)
61                 DRM_OS_RETURN( EINVAL );
62         if (bl->bufs) DRM(free)(bl->bufs,
63                                 (bl->count + 2) * sizeof(*bl->bufs),
64                                 DRM_MEM_BUFLISTS);
65         bl->count = 0;
66         bl->bufs  = NULL;
67         bl->rp    = NULL;
68         bl->wp    = NULL;
69         bl->end   = NULL;
70         return 0;
71 }
72
73 int DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf)
74 {
75         int           left;
76         int             s;
77         left = DRM_LEFTCOUNT(bl);
78         if (!left) {
79                 DRM_ERROR("Overflow while adding buffer %d from pid %d\n",
80                           buf->idx, buf->pid);
81                 DRM_OS_RETURN( EINVAL );
82         }
83 #if __HAVE_DMA_HISTOGRAM
84         getnanotime(&buf->time_queued);
85 #endif
86         buf->list        = DRM_LIST_WAIT;
87
88         DRM_OS_SPINLOCK(&bl->write_lock);
89         s = spldrm();
90         *bl->wp = buf;
91         if (++bl->wp >= bl->end) bl->wp = bl->bufs;
92         splx(s);
93         DRM_OS_SPINUNLOCK(&bl->write_lock);
94
95         return 0;
96 }
97
98 drm_buf_t *DRM(waitlist_get)(drm_waitlist_t *bl)
99 {
100         drm_buf_t     *buf;
101         int             s;
102
103         DRM_OS_SPINLOCK(&bl->read_lock);
104         s = spldrm();
105         buf = *bl->rp;
106         if (bl->rp == bl->wp) {
107                 splx(s);
108                 DRM_OS_SPINUNLOCK(&bl->read_lock);
109                 return NULL;
110         }                                    
111         if (++bl->rp >= bl->end) bl->rp = bl->bufs;
112         splx(s);
113         DRM_OS_SPINUNLOCK(&bl->read_lock);
114         
115         return buf;
116 }
117
118 #endif /* __HAVE_DMA_WAITLIST */
119
120
121 #if __HAVE_DMA_FREELIST
122
123 int DRM(freelist_create)(drm_freelist_t *bl, int count)
124 {
125         atomic_set(&bl->count, 0);
126         bl->next      = NULL;
127         bl->waiting = 0;
128
129         bl->low_mark  = 0;
130         bl->high_mark = 0;
131         atomic_set(&bl->wfh,   0);
132         DRM_OS_SPININIT( bl->lock, "freelistlock" );
133         ++bl->initialized;
134         return 0;
135 }
136
137 int DRM(freelist_destroy)(drm_freelist_t *bl)
138 {
139         atomic_set(&bl->count, 0);
140         bl->next = NULL;
141         return 0;
142 }
143
144 int DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf)
145 {
146         drm_device_dma_t *dma  = dev->dma;
147
148         if (!dma) {
149                 DRM_ERROR("No DMA support\n");
150                 return 1;
151         }
152
153         if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) {
154                 DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n",
155                           buf->idx, buf->waiting, buf->pending, buf->list);
156         }
157         if (!bl) return 1;
158 #if __HAVE_DMA_HISTOGRAM
159         getnanotime(&buf->time_queued);
160         DRM(histogram_compute)(dev, buf);
161 #endif
162         buf->list       = DRM_LIST_FREE;
163
164         DRM_OS_SPINLOCK( &bl->lock );
165         buf->next       = bl->next;
166         bl->next        = buf;
167         DRM_OS_SPINUNLOCK( &bl->lock );
168
169         atomic_inc(&bl->count);
170         if (atomic_read(&bl->count) > dma->buf_count) {
171                 DRM_ERROR("%ld of %d buffers free after addition of %d\n",
172                           (unsigned long)atomic_read(&bl->count), 
173                                 dma->buf_count, buf->idx);
174                 return 1;
175         }
176                                 /* Check for high water mark */
177         if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) {
178                 atomic_set(&bl->wfh, 0);
179                 DRM_OS_WAKEUP_INT(&bl->waiting);
180         }
181         return 0;
182 }
183
184 static drm_buf_t *DRM(freelist_try)(drm_freelist_t *bl)
185 {
186         drm_buf_t         *buf;
187
188         if (!bl) return NULL;
189
190                                 /* Get buffer */
191         DRM_OS_SPINLOCK(&bl->lock);
192         if (!bl->next) {
193                 DRM_OS_SPINUNLOCK(&bl->lock);
194                 return NULL;
195         }
196         buf       = bl->next;
197         bl->next  = bl->next->next;
198         DRM_OS_SPINUNLOCK(&bl->lock);
199
200         atomic_dec(&bl->count);
201         buf->next = NULL;
202         buf->list = DRM_LIST_NONE;
203         if (buf->waiting || buf->pending) {
204                 DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n",
205                           buf->idx, buf->waiting, buf->pending, buf->list);
206         }
207
208         return buf;
209 }
210
211 drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block)
212 {
213         drm_buf_t         *buf  = NULL;
214         int     error;
215
216         if (!bl || !bl->initialized) return NULL;
217
218                                 /* Check for low water mark */
219         if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */
220                 atomic_set(&bl->wfh, 1);
221         if (atomic_read(&bl->wfh)) {
222                 if (block) {
223                         for (;;) {
224                                 if (!atomic_read(&bl->wfh)
225                                     && (buf = DRM(freelist_try(bl)))) break;
226                                 error = tsleep(&bl->waiting, PZERO|PCATCH,
227                                                "drmfg", 0);
228                                 if (error)
229                                         break;
230                         }
231                 }
232                 return buf;
233         }
234
235         return DRM(freelist_try)(bl);
236 }
237
238 #endif /* __HAVE_DMA_FREELIST */