Merge branch 'master'
[linux-2.6] / drivers / char / drm / via_ds.c
1 /*
2  * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3  * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
4  * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sub license,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portions
15  * of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20  * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 #include <linux/module.h>
26 #include <linux/delay.h>
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
29 #include <linux/slab.h>
30 #include <linux/poll.h>
31 #include <linux/pci.h>
32 #include <asm/io.h>
33
34 #include "via_ds.h"
35 extern unsigned int VIA_DEBUG;
36
37 set_t *via_setInit(void)
38 {
39         int i;
40         set_t *set;
41         set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
42         for (i = 0; i < SET_SIZE; i++) {
43                 set->list[i].free_next = i + 1;
44                 set->list[i].alloc_next = -1;
45         }
46         set->list[SET_SIZE - 1].free_next = -1;
47         set->free = 0;
48         set->alloc = -1;
49         set->trace = -1;
50         return set;
51 }
52
53 int via_setAdd(set_t * set, ITEM_TYPE item)
54 {
55         int free = set->free;
56         if (free != -1) {
57                 set->list[free].val = item;
58                 set->free = set->list[free].free_next;
59         } else {
60                 return 0;
61         }
62         set->list[free].alloc_next = set->alloc;
63         set->alloc = free;
64         set->list[free].free_next = -1;
65         return 1;
66 }
67
68 int via_setDel(set_t * set, ITEM_TYPE item)
69 {
70         int alloc = set->alloc;
71         int prev = -1;
72
73         while (alloc != -1) {
74                 if (set->list[alloc].val == item) {
75                         if (prev != -1)
76                                 set->list[prev].alloc_next =
77                                     set->list[alloc].alloc_next;
78                         else
79                                 set->alloc = set->list[alloc].alloc_next;
80                         break;
81                 }
82                 prev = alloc;
83                 alloc = set->list[alloc].alloc_next;
84         }
85
86         if (alloc == -1)
87                 return 0;
88
89         set->list[alloc].free_next = set->free;
90         set->free = alloc;
91         set->list[alloc].alloc_next = -1;
92
93         return 1;
94 }
95
96 /* setFirst -> setAdd -> setNext is wrong */
97
98 int via_setFirst(set_t * set, ITEM_TYPE * item)
99 {
100         if (set->alloc == -1)
101                 return 0;
102
103         *item = set->list[set->alloc].val;
104         set->trace = set->list[set->alloc].alloc_next;
105
106         return 1;
107 }
108
109 int via_setNext(set_t * set, ITEM_TYPE * item)
110 {
111         if (set->trace == -1)
112                 return 0;
113
114         *item = set->list[set->trace].val;
115         set->trace = set->list[set->trace].alloc_next;
116
117         return 1;
118 }
119
120 int via_setDestroy(set_t * set)
121 {
122         drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
123
124         return 1;
125 }
126
127 #define ISFREE(bptr) ((bptr)->free)
128
129 #define fprintf(fmt, arg...) do{}while(0)
130
131 memHeap_t *via_mmInit(int ofs, int size)
132 {
133         PMemBlock blocks;
134
135         if (size <= 0)
136                 return NULL;
137
138         blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
139
140         if (blocks) {
141                 blocks->ofs = ofs;
142                 blocks->size = size;
143                 blocks->free = 1;
144                 return (memHeap_t *) blocks;
145         } else
146                 return NULL;
147 }
148
149 static TMemBlock *SliceBlock(TMemBlock * p,
150                              int startofs, int size,
151                              int reserved, int alignment)
152 {
153         TMemBlock *newblock;
154
155         /* break left */
156         if (startofs > p->ofs) {
157                 newblock =
158                     (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
159                                              DRM_MEM_DRIVER);
160                 newblock->ofs = startofs;
161                 newblock->size = p->size - (startofs - p->ofs);
162                 newblock->free = 1;
163                 newblock->next = p->next;
164                 p->size -= newblock->size;
165                 p->next = newblock;
166                 p = newblock;
167         }
168
169         /* break right */
170         if (size < p->size) {
171                 newblock =
172                     (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
173                                              DRM_MEM_DRIVER);
174                 newblock->ofs = startofs + size;
175                 newblock->size = p->size - size;
176                 newblock->free = 1;
177                 newblock->next = p->next;
178                 p->size = size;
179                 p->next = newblock;
180         }
181
182         /* p = middle block */
183         p->align = alignment;
184         p->free = 0;
185         p->reserved = reserved;
186         return p;
187 }
188
189 PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
190                          int startSearch)
191 {
192         int mask, startofs, endofs;
193         TMemBlock *p;
194
195         if (!heap || align2 < 0 || size <= 0)
196                 return NULL;
197
198         mask = (1 << align2) - 1;
199         startofs = 0;
200         p = (TMemBlock *) heap;
201
202         while (p) {
203                 if (ISFREE(p)) {
204                         startofs = (p->ofs + mask) & ~mask;
205
206                         if (startofs < startSearch)
207                                 startofs = startSearch;
208
209                         endofs = startofs + size;
210
211                         if (endofs <= (p->ofs + p->size))
212                                 break;
213                 }
214
215                 p = p->next;
216         }
217
218         if (!p)
219                 return NULL;
220
221         p = SliceBlock(p, startofs, size, 0, mask + 1);
222         p->heap = heap;
223
224         return p;
225 }
226
227 static __inline__ int Join2Blocks(TMemBlock * p)
228 {
229         if (p->free && p->next && p->next->free) {
230                 TMemBlock *q = p->next;
231                 p->size += q->size;
232                 p->next = q->next;
233                 drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);
234
235                 return 1;
236         }
237
238         return 0;
239 }
240
241 int via_mmFreeMem(PMemBlock b)
242 {
243         TMemBlock *p, *prev;
244
245         if (!b)
246                 return 0;
247
248         if (!b->heap) {
249                 fprintf(stderr, "no heap\n");
250
251                 return -1;
252         }
253
254         p = b->heap;
255         prev = NULL;
256
257         while (p && p != b) {
258                 prev = p;
259                 p = p->next;
260         }
261
262         if (!p || p->free || p->reserved) {
263                 if (!p)
264                         fprintf(stderr, "block not found in heap\n");
265                 else if (p->free)
266                         fprintf(stderr, "block already free\n");
267                 else
268                         fprintf(stderr, "block is reserved\n");
269
270                 return -1;
271         }
272
273         p->free = 1;
274         Join2Blocks(p);
275
276         if (prev)
277                 Join2Blocks(prev);
278
279         return 0;
280 }