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