diff options
Diffstat (limited to 'drivers/char/drm/via_mm.c')
-rw-r--r-- | drivers/char/drm/via_mm.c | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c new file mode 100644 index 000000000000..c22712f44d42 --- /dev/null +++ b/drivers/char/drm/via_mm.c | |||
@@ -0,0 +1,358 @@ | |||
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 | } | ||