1 /*
2  * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3  * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sub license,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19  * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Fixes:
25  *	Changed to use via_ prefixes on globals
26  *	Fixed malloc failure paths
27  *	Reformatted to Linux style
28  *	Removed ITEM_TYPE typedef, FREE/MALLOC and other macro bits
29  */
30 
31 #define __NO_VERSION__
32 #include <linux/module.h>
33 #include <linux/delay.h>
34 #include <linux/errno.h>
35 #include <linux/kernel.h>
36 #include <linux/slab.h>
37 #include <linux/poll.h>
38 #include <asm/io.h>
39 #include <linux/pci.h>
40 
41 #include "via_ds.h"
42 
43 #warning "Fix variable/global names to use via_"
44 
45 extern unsigned int VIA_DEBUG;
46 
via_set_init(void)47 set_t *via_set_init(void)
48 {
49 	int i;
50 	set_t *set;
51 	set = (set_t *)kmalloc(sizeof(set_t), GFP_KERNEL);
52 	if(set == NULL)
53 		return NULL;
54 	for (i = 0; i < SET_SIZE; i++) {
55 		set->list[i].free_next = i + 1;
56 		set->list[i].alloc_next = -1;
57 	}
58 	set->list[SET_SIZE - 1].free_next = -1;
59 	set->free = 0;
60 	set->alloc = -1;
61 	set->trace = -1;
62 	return set;
63 }
64 
via_set_add(set_t * set,unsigned int item)65 int via_set_add(set_t * set, unsigned int item)
66 {
67 	int free = set->free;
68 	if (free != -1) {
69 		set->list[free].val = item;
70 		set->free = set->list[free].free_next;
71 	} else {
72 		return 0;
73 	}
74 	set->list[free].alloc_next = set->alloc;
75 	set->alloc = free;
76 	set->list[free].free_next = -1;
77 	return 1;
78 }
79 
via_set_del(set_t * set,unsigned int item)80 int via_set_del(set_t * set, unsigned int item)
81 {
82 	int alloc = set->alloc;
83 	int prev = -1;
84 
85 	while (alloc != -1) {
86 		if (set->list[alloc].val == item) {
87 			if (prev != -1)
88 				set->list[prev].alloc_next = set->list[alloc].alloc_next;
89 			else
90 				set->alloc = set->list[alloc].alloc_next;
91 			break;
92 		}
93 		prev = alloc;
94 		alloc = set->list[alloc].alloc_next;
95 	}
96 
97 	if (alloc == -1)
98 		return 0;
99 
100 	set->list[alloc].free_next = set->free;
101 	set->free = alloc;
102 	set->list[alloc].alloc_next = -1;
103 
104 	return 1;
105 }
106 
107 /* setFirst -> setAdd -> setNext is wrong */
108 
via_set_first(set_t * set,unsigned int * item)109 int via_set_first(set_t * set, unsigned int * item)
110 {
111 	if (set->alloc == -1)
112 		return 0;
113 
114 	*item = set->list[set->alloc].val;
115 	set->trace = set->list[set->alloc].alloc_next;
116 
117 
118 	return 1;
119 }
120 
via_set_next(set_t * set,unsigned int * item)121 int via_set_next(set_t * set, unsigned int * item)
122 {
123 	if (set->trace == -1)
124 		return 0;
125 
126 	*item = set->list[set->trace].val;
127 	set->trace = set->list[set->trace].alloc_next;
128 
129 	return 1;
130 }
131 
via_set_destroy(set_t * set)132 int via_set_destroy(set_t * set)
133 {
134 	kfree(set);
135 	return 1;
136 }
137 
138 #define ISFREE(bptr) ((bptr)->free)
139 
140 #define PRINTF(fmt, arg...) do{}while(0)
141 
via_mmDumpMemInfo(memHeap_t * heap)142 void via_mmDumpMemInfo(memHeap_t * heap)
143 {
144 	TMemBlock *p;
145 
146 	PRINTF("Memory heap %p:\n", heap);
147 
148 	if (heap == 0)
149 		PRINTF("  heap == 0\n");
150 	else {
151 		p = (TMemBlock *) heap;
152 
153 		while (p) {
154 			PRINTF("  Offset:%08x, Size:%08x, %c%c\n", p->ofs, p->size, p->free ? '.' : 'U', p->reserved ? 'R' : '.');
155 			p = p->next;
156 		}
157 	}
158 
159 	PRINTF("End of memory blocks\n");
160 }
161 
via_mmInit(int ofs,int size)162 memHeap_t *via_mmInit(int ofs, int size)
163 {
164 	PMemBlock blocks;
165 
166 	if (size <= 0)
167 		return 0;
168 
169 
170 	blocks = (TMemBlock *) kmalloc(sizeof(TMemBlock), GFP_KERNEL);
171 
172 	if (blocks) {
173 		memset(blocks, 0, sizeof(TMemBlock));
174 		blocks->ofs = ofs;
175 		blocks->size = size;
176 		blocks->free = 1;
177 		return (memHeap_t *) blocks;
178 	} else
179 		return NULL;
180 }
181 
via_mmAddRange(memHeap_t * heap,int ofs,int size)182 memHeap_t *via_mmAddRange(memHeap_t * heap, int ofs, int size)
183 {
184 	PMemBlock blocks;
185 	blocks = (TMemBlock *) kmalloc(2 *  sizeof(TMemBlock), GFP_KERNEL);
186 
187 	if (blocks) {
188 		memset(blocks, 0, 2 * sizeof(TMemBlock));
189 		blocks[0].size = size;
190 		blocks[0].free = 1;
191 		blocks[0].ofs = ofs;
192 		blocks[0].next = &blocks[1];
193 
194 		/* Discontinuity - stops JoinBlock from trying to join non-adjacent
195 		 * ranges.
196 		 */
197 		blocks[1].size = 0;
198 		blocks[1].free = 0;
199 		blocks[1].ofs = ofs + size;
200 		blocks[1].next = (PMemBlock) heap;
201 		return (memHeap_t *) blocks;
202 	} else
203 		return heap;
204 }
205 
SliceBlock(TMemBlock * p,int startofs,int size,int reserved,int alignment)206 static TMemBlock *SliceBlock(TMemBlock * p, int startofs, int size, int reserved, int alignment)
207 {
208 	TMemBlock *newblock;
209 
210 	/* break left */
211 	if (startofs > p->ofs) {
212 		newblock = (TMemBlock *) kmalloc(sizeof(TMemBlock), GFP_KERNEL);
213 		if(newblock == NULL)
214 			return NULL;
215 		memset(newblock, 0, sizeof(TMemBlock));
216 		newblock->ofs = startofs;
217 		newblock->size = p->size - (startofs - p->ofs);
218 		newblock->free = 1;
219 		newblock->next = p->next;
220 		p->size -= newblock->size;
221 		p->next = newblock;
222 		p = newblock;
223 	}
224 
225 	/* break right */
226 	if (size < p->size) {
227 		newblock = (TMemBlock *) kmalloc(sizeof(TMemBlock), GFP_KERNEL);
228 		if(newblock == NULL)
229 			return NULL;
230 		memset(newblock, 0, sizeof(TMemBlock));
231 		newblock->ofs = startofs + size;
232 		newblock->size = p->size - size;
233 		newblock->free = 1;
234 		newblock->next = p->next;
235 		p->size = size;
236 		p->next = newblock;
237 	}
238 
239 	/* p = middle block */
240 	p->align = alignment;
241 	p->free = 0;
242 	p->reserved = reserved;
243 	return p;
244 }
245 
via_mmAllocMem(memHeap_t * heap,int size,int align2,int startSearch)246 PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch)
247 {
248 	int mask, startofs, endofs;
249 	TMemBlock *p;
250 
251 	if (!heap || align2 < 0 || size <= 0)
252 		return NULL;
253 
254 	mask = (1 << align2) - 1;
255 	startofs = 0;
256 	p = (TMemBlock *) heap;
257 
258 	while (p) {
259 		if (ISFREE(p)) {
260 			startofs = (p->ofs + mask) & ~mask;
261 
262 			if (startofs < startSearch)
263 				startofs = startSearch;
264 
265 			endofs = startofs + size;
266 
267 			if (endofs <= (p->ofs + p->size))
268 				break;
269 		}
270 
271 		p = p->next;
272 	}
273 
274 	if (!p)
275 		return NULL;
276 
277 	p = SliceBlock(p, startofs, size, 0, mask + 1);
278 	p->heap = heap;
279 
280 	return p;
281 }
282 
Join2Blocks(TMemBlock * p)283 static __inline__ int Join2Blocks(TMemBlock * p)
284 {
285 	if (p->free && p->next && p->next->free) {
286 		TMemBlock *q = p->next;
287 		p->size += q->size;
288 		p->next = q->next;
289 		kfree(q);
290 
291 		return 1;
292 	}
293 
294 	return 0;
295 }
296 
via_mmFreeMem(PMemBlock b)297 int via_mmFreeMem(PMemBlock b)
298 {
299 	TMemBlock *p, *prev;
300 
301 	if (!b)
302 		return 0;
303 
304 	if (!b->heap) {
305 		return -1;
306 	}
307 
308 	p = b->heap;
309 	prev = NULL;
310 
311 	while (p && p != b) {
312 		prev = p;
313 		p = p->next;
314 	}
315 
316 	if (!p || p->free || p->reserved) {
317 		if (!p)
318 			BUG();
319 		else if (p->free)
320 			BUG();
321 		else
322 			BUG();
323 		return -1;
324 	}
325 
326 	p->free = 1;
327 	Join2Blocks(p);
328 
329 	if (prev)
330 		Join2Blocks(prev);
331 
332 	return 0;
333 }
334 
via_mm_ReserveMem(memHeap_t * heap,int offset,int size)335 int via_mm_ReserveMem(memHeap_t * heap, int offset, int size)
336 {
337 	int endofs;
338 	TMemBlock *p;
339 
340 	if (!heap || size <= 0)
341 		return -1;
342 	endofs = offset + size;
343 	p = (TMemBlock *) heap;
344 
345 	while (p && p->ofs <= offset) {
346 		if (ISFREE(p) && endofs <= (p->ofs + p->size)) {
347 			SliceBlock(p, offset, size, 1, 1);
348 			return 0;
349 		}
350 		p = p->next;
351 	}
352 	return -1;
353 }
354 
via_mm_FreeReserved(memHeap_t * heap,int offset)355 int via_mm_FreeReserved(memHeap_t * heap, int offset)
356 {
357 	TMemBlock *p, *prev;
358 
359 	if (!heap)
360 		return -1;
361 
362 	p = (TMemBlock *) heap;
363 	prev = NULL;
364 
365 	while (p && p->ofs != offset) {
366 		prev = p;
367 		p = p->next;
368 	}
369 
370 	if (!p || !p->reserved)
371 		return -1;
372 	p->free = 1;
373 	p->reserved = 0;
374 	Join2Blocks(p);
375 
376 	if (prev)
377 		Join2Blocks(prev);
378 
379 	return 0;
380 }
381 
via_mm_Destroy(memHeap_t * heap)382 void via_mm_Destroy(memHeap_t * heap)
383 {
384 	TMemBlock *p, *q;
385 
386 	if (!heap)
387 		return;
388 	p = (TMemBlock *) heap;
389 
390 	while (p) {
391 		q = p->next;
392 		kfree(p);
393 		p = q;
394 	}
395 }
396