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