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 
25 #define __NO_VERSION__
26 #include "via.h"
27 #include "drmP.h"
28 #include "via_drm.h"
29 #include "via_drv.h"
30 #include "via_ds.h"
31 #include "via_mm.h"
32 
33 #define MAX_CONTEXT 100
34 
35 unsigned int VIA_DEBUG = 1;
36 
37 typedef struct {
38 	int used;
39 	int context;
40 	set_t *sets[2]; /* 0 for frame buffer, 1 for AGP , 2 for System*/
41 } via_context_t;
42 
43 static via_context_t global_ppriv[MAX_CONTEXT];
44 
add_alloc_set(int context,int type,unsigned int val)45 static int add_alloc_set(int context, int type, unsigned int val)
46 {
47 	int i, retval = 0;
48 
49 	for (i = 0; i < MAX_CONTEXT; i++)
50 	{
51 		if (global_ppriv[i].used && global_ppriv[i].context == context)
52 		{
53 			retval = via_set_add(global_ppriv[i].sets[type], val);
54 			break;
55 		}
56 	}
57   	return retval;
58 }
59 
del_alloc_set(int context,int type,unsigned int val)60 static int del_alloc_set(int context, int type, unsigned int val)
61 {
62 	int i, retval = 0;
63 
64 	for (i = 0; i < MAX_CONTEXT; i++)
65 		if (global_ppriv[i].used && global_ppriv[i].context == context)
66 		{
67 			retval = via_set_del(global_ppriv[i].sets[type], val);
68 			break;
69 		}
70 	return retval;
71 }
72 
73 /* agp memory management */
74 
75 static memHeap_t *AgpHeap = NULL;
76 
77 #warning "FIXME: heap re-init cases ?"
via_agp_init(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)78 int via_agp_init(struct inode *inode, struct file *filp, unsigned int cmd,
79 		  unsigned long arg)
80 {
81 	drm_via_agp_t agp;
82 
83 	if (copy_from_user(&agp, (drm_via_agp_t *)arg, sizeof(agp)))
84 		return -EFAULT;
85 
86 	AgpHeap = via_mmInit(agp.offset, agp.size);
87 
88 	DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
89 	return 0;
90 }
91 
92 /* fb memory management */
93 static memHeap_t *FBHeap = NULL;
94 
via_fb_init(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)95 int via_fb_init(struct inode *inode, struct file *filp, unsigned int cmd,
96 		  unsigned long arg)
97 {
98 	drm_via_fb_t fb;
99 
100 	if  (copy_from_user(&fb, (drm_via_fb_t *)arg, sizeof(fb)))
101 		return -EFAULT;
102 
103 	FBHeap = via_mmInit(fb.offset, fb.size);
104 	DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
105 
106 	return 0;
107 }
108 
via_init_context(int context)109 int via_init_context(int context)
110 {
111 	int i;
112 
113 	for (i = 0; i < MAX_CONTEXT ; i++)
114 		if (global_ppriv[i].used && (global_ppriv[i].context == context))
115 			break;
116 
117 	if (i >= MAX_CONTEXT) {
118 		for (i = 0; i < MAX_CONTEXT ; i++) {
119 			if (!global_ppriv[i].used) {
120 				global_ppriv[i].context = context;
121 			    	global_ppriv[i].used = 1;
122 			    	global_ppriv[i].sets[0] = via_set_init();
123 			    	global_ppriv[i].sets[1] = via_set_init();
124 			    	DRM_DEBUG("init allocation set, socket=%d, context = %d\n",
125 			                 i, context);
126 				break;
127 			}
128 		}
129 
130 		if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
131 			(global_ppriv[i].sets[1] == NULL)) {
132 			return 0;
133 		}
134 	}
135 
136 	return 1;
137 }
138 
via_final_context(int context)139 int via_final_context(int context)
140 {
141 	int i;
142 	for (i=0; i<MAX_CONTEXT; i++)
143 		if (global_ppriv[i].used && (global_ppriv[i].context == context))
144 			break;
145 
146 	if (i < MAX_CONTEXT) {
147 		set_t *set;
148 		unsigned int item;
149 		int retval;
150 
151 	  	DRM_DEBUG("find socket %d, context = %d\n", i, context);
152 
153 		/* Video Memory */
154 		set = global_ppriv[i].sets[0];
155 		retval = via_set_first(set, &item);
156 		while (retval) {
157 			DRM_DEBUG("free video memory 0x%x\n", item);
158 			via_mmFreeMem((PMemBlock)item);
159 			retval = via_set_next(set, &item);
160 		}
161 		via_set_destroy(set);
162 
163 		/* AGP Memory */
164 		set = global_ppriv[i].sets[1];
165 		retval = via_set_first(set, &item);
166 		while (retval) {
167 			DRM_DEBUG("free agp memory 0x%x\n", item);
168 			via_mmFreeMem((PMemBlock)item);
169 			retval = via_set_next(set, &item);
170 		}
171 		via_set_destroy(set);
172 
173 		global_ppriv[i].used = 0;
174 	}
175     	return 1;
176 }
177 
via_mem_alloc(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)178 int via_mem_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
179 		  unsigned long arg)
180 {
181 	drm_via_mem_t mem;
182 
183 	if (copy_from_user(&mem, (drm_via_mem_t *)arg, sizeof(mem)))
184 		return -EFAULT;
185 
186 	switch (mem.type) {
187 		case VIDEO :
188 			if (via_fb_alloc(&mem) < 0)
189 				return -ENOMEM;
190 			if (copy_to_user((drm_via_mem_t *)arg, &mem, sizeof(mem)))
191 				return -EFAULT;
192 			return 0;
193 		case AGP :
194 			if (via_agp_alloc(&mem) < 0)
195 				return -ENOMEM;
196 			if (copy_to_user((drm_via_mem_t *)arg, &mem, sizeof(mem)))
197 				return -EFAULT;
198 			return 0;
199 	}
200 	return -EINVAL;
201 }
202 
via_fb_alloc(drm_via_mem_t * mem)203 int via_fb_alloc(drm_via_mem_t* mem)
204 {
205 	drm_via_mm_t fb;
206 	PMemBlock block;
207 	int retval = 0;
208 
209 	if (!FBHeap)
210 		return -1;
211 
212 	fb.size = mem->size;
213 	fb.context = mem->context;
214 
215 	block = via_mmAllocMem(FBHeap, fb.size, 5, 0);
216 	if (block) {
217 		fb.offset = block->ofs;
218 		fb.free = (unsigned int)block;
219 		if (!add_alloc_set(fb.context, VIDEO, fb.free)) {
220     			DRM_DEBUG("adding to allocation set fails\n");
221 			via_mmFreeMem((PMemBlock)fb.free);
222 			retval = -1;
223 		}
224 	} else {
225 		fb.offset = 0;
226 		fb.size = 0;
227 		fb.free = 0;
228 	}
229 
230 	mem->offset = fb.offset;
231 	mem->index = fb.free;
232 
233 	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, (int)fb.offset);
234 
235 	return retval;
236 }
237 
via_agp_alloc(drm_via_mem_t * mem)238 int via_agp_alloc(drm_via_mem_t* mem)
239 {
240 	drm_via_mm_t agp;
241 	PMemBlock block;
242 	int retval = 0;
243 
244 	if (!AgpHeap)
245 		return -1;
246 
247 	agp.size = mem->size;
248 	agp.context = mem->context;
249 
250 	block = via_mmAllocMem(AgpHeap, agp.size, 5, 0);
251 	if (block) {
252 		agp.offset = block->ofs;
253 		agp.free = (unsigned int)block;
254 		if (!add_alloc_set(agp.context, AGP, agp.free)) {
255 			DRM_DEBUG("adding to allocation set fails\n");
256 			via_mmFreeMem((PMemBlock)agp.free);
257 			retval = -1;
258 		}
259 	} else {
260 		agp.offset = 0;
261 		agp.size = 0;
262 		agp.free = 0;
263 	}
264 
265 	mem->offset = agp.offset;
266 	mem->index = agp.free;
267 
268 	DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, (unsigned int)agp.offset);
269 	return retval;
270 }
271 
via_mem_free(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)272 int via_mem_free(struct inode *inode, struct file *filp, unsigned int cmd,
273 		  unsigned long arg)
274 {
275 	drm_via_mem_t mem;
276 
277 	if (copy_from_user(&mem, (drm_via_mem_t *)arg, sizeof(mem)))
278 		return -EFAULT;
279 
280 	switch (mem.type)
281 	{
282 	case VIDEO :
283 	    if (via_fb_free(&mem) == 0)
284 		return 0;
285 	    break;
286 	case AGP :
287 	    if (via_agp_free(&mem) == 0)
288 		return 0;
289 	    break;
290 	}
291 	return -EINVAL;
292 }
293 
via_fb_free(drm_via_mem_t * mem)294 int via_fb_free(drm_via_mem_t* mem)
295 {
296 	drm_via_mm_t fb;
297 	int retval = 0;
298 
299 
300 	if (!FBHeap)
301 		return -1;
302 
303 	fb.free = mem->index;
304 	fb.context = mem->context;
305 
306 	if (!fb.free)
307 		return -1;
308 
309 	via_mmFreeMem((PMemBlock)fb.free);
310 
311 	if (!del_alloc_set(fb.context, VIDEO, fb.free))
312 		retval = -1;
313 
314 	DRM_DEBUG("free fb, free = %d\n", fb.free);
315 
316 	return retval;
317 }
318 
via_agp_free(drm_via_mem_t * mem)319 int via_agp_free(drm_via_mem_t* mem)
320 {
321 	drm_via_mm_t agp;
322 
323 	int retval = 0;
324 
325 	agp.free = mem->index;
326 	agp.context = mem->context;
327 
328 	if (!agp.free)
329 		return -1;
330 
331 	via_mmFreeMem((PMemBlock)agp.free);
332 
333 	if (!del_alloc_set(agp.context, AGP, agp.free))
334 		retval = -1;
335 
336 	DRM_DEBUG("free agp, free = %d\n", agp.free);
337 	return retval;
338 }
339