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