FreeBSD/Linux Kernel Cross Reference
sys/dev/drm/sis_mm.c
1 /* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*-
2 * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw *
3 */
4 /*-
5 * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
6 * All rights reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * Authors:
28 * Sung-Ching Lin <sclin@sis.com.tw>
29 *
30 * $FreeBSD$
31 */
32
33 #include "dev/drm/sis.h"
34 #include "dev/drm/drmP.h"
35 #include "dev/drm/sis_drm.h"
36 #include "dev/drm/sis_drv.h"
37 #include "dev/drm/sis_ds.h"
38 #if defined(__linux__) && defined(CONFIG_FB_SIS)
39 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
40 #include <video/sisfb.h>
41 #else
42 #include <linux/sisfb.h>
43 #endif
44 #endif
45
46 #define MAX_CONTEXT 100
47 #define VIDEO_TYPE 0
48 #define AGP_TYPE 1
49
50 typedef struct {
51 int used;
52 int context;
53 set_t *sets[2]; /* 0 for video, 1 for AGP */
54 } sis_context_t;
55
56 static sis_context_t global_ppriv[MAX_CONTEXT];
57
58
59 static int add_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 {
66 retval = setAdd(global_ppriv[i].sets[type], val);
67 break;
68 }
69 }
70 return retval;
71 }
72
73 static int del_alloc_set(int context, int type, unsigned int val)
74 {
75 int i, retval = 0;
76
77 for (i = 0; i < MAX_CONTEXT; i++) {
78 if (global_ppriv[i].used && global_ppriv[i].context == context)
79 {
80 retval = setDel(global_ppriv[i].sets[type], val);
81 break;
82 }
83 }
84 return retval;
85 }
86
87 /* fb management via fb device */
88 #if defined(__linux__) && defined(CONFIG_FB_SIS)
89
90 int sis_fb_init( DRM_IOCTL_ARGS )
91 {
92 return 0;
93 }
94
95 int sis_fb_alloc( DRM_IOCTL_ARGS )
96 {
97 drm_sis_mem_t fb;
98 struct sis_memreq req;
99 int retval = 0;
100
101 DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb));
102
103 req.size = fb.size;
104 sis_malloc(&req);
105 if (req.offset) {
106 /* TODO */
107 fb.offset = req.offset;
108 fb.free = req.offset;
109 if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
110 DRM_DEBUG("adding to allocation set fails\n");
111 sis_free(req.offset);
112 retval = DRM_ERR(EINVAL);
113 }
114 } else {
115 fb.offset = 0;
116 fb.size = 0;
117 fb.free = 0;
118 }
119
120 DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb));
121
122 DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset);
123
124 return retval;
125 }
126
127 int sis_fb_free( DRM_IOCTL_ARGS )
128 {
129 drm_sis_mem_t fb;
130 int retval = 0;
131
132 DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb));
133
134 if (!fb.free)
135 return DRM_ERR(EINVAL);
136
137 if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
138 retval = DRM_ERR(EINVAL);
139 sis_free(fb.free);
140
141 DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
142
143 return retval;
144 }
145
146 #else
147
148 /* Called by the X Server to initialize the FB heap. Allocations will fail
149 * unless this is called. Offset is the beginning of the heap from the
150 * framebuffer offset (MaxXFBMem in XFree86).
151 *
152 * Memory layout according to Thomas Winischofer:
153 * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC|
154 *
155 * X driver/sisfb HW- Command-
156 * framebuffer memory DRI heap Cursor queue
157 */
158 int sis_fb_init( DRM_IOCTL_ARGS )
159 {
160 DRM_DEVICE;
161 drm_sis_private_t *dev_priv = dev->dev_private;
162 drm_sis_fb_t fb;
163
164 DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t *)data, sizeof(fb));
165
166 if (dev_priv == NULL) {
167 dev->dev_private = DRM(calloc)(1, sizeof(drm_sis_private_t),
168 DRM_MEM_DRIVER);
169 dev_priv = dev->dev_private;
170 if (dev_priv == NULL)
171 return ENOMEM;
172 }
173
174 if (dev_priv->FBHeap != NULL)
175 return DRM_ERR(EINVAL);
176
177 dev_priv->FBHeap = mmInit(fb.offset, fb.size);
178
179 DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
180
181 return 0;
182 }
183
184 int sis_fb_alloc( DRM_IOCTL_ARGS )
185 {
186 DRM_DEVICE;
187 drm_sis_private_t *dev_priv = dev->dev_private;
188 drm_sis_mem_t fb;
189 PMemBlock block;
190 int retval = 0;
191
192 if (dev_priv == NULL || dev_priv->FBHeap == NULL)
193 return DRM_ERR(EINVAL);
194
195 DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb));
196
197 block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0);
198 if (block) {
199 /* TODO */
200 fb.offset = block->ofs;
201 fb.free = (unsigned long)block;
202 if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
203 DRM_DEBUG("adding to allocation set fails\n");
204 mmFreeMem((PMemBlock)fb.free);
205 retval = DRM_ERR(EINVAL);
206 }
207 } else {
208 fb.offset = 0;
209 fb.size = 0;
210 fb.free = 0;
211 }
212
213 DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb));
214
215 DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset);
216
217 return retval;
218 }
219
220 int sis_fb_free( DRM_IOCTL_ARGS )
221 {
222 DRM_DEVICE;
223 drm_sis_private_t *dev_priv = dev->dev_private;
224 drm_sis_mem_t fb;
225
226 if (dev_priv == NULL || dev_priv->FBHeap == NULL)
227 return DRM_ERR(EINVAL);
228
229 DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb));
230
231 if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock)fb.free))
232 return DRM_ERR(EINVAL);
233
234 if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
235 return DRM_ERR(EINVAL);
236 mmFreeMem((PMemBlock)fb.free);
237
238 DRM_DEBUG("free fb, free = 0x%lx\n", fb.free);
239
240 return 0;
241 }
242
243 #endif
244
245 /* agp memory management */
246
247 int sis_ioctl_agp_init( DRM_IOCTL_ARGS )
248 {
249 DRM_DEVICE;
250 drm_sis_private_t *dev_priv = dev->dev_private;
251 drm_sis_agp_t agp;
252
253 if (dev_priv == NULL) {
254 dev->dev_private = DRM(calloc)(1, sizeof(drm_sis_private_t),
255 DRM_MEM_DRIVER);
256 dev_priv = dev->dev_private;
257 if (dev_priv == NULL)
258 return ENOMEM;
259 }
260
261 if (dev_priv->AGPHeap != NULL)
262 return DRM_ERR(EINVAL);
263
264 DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t *)data, sizeof(agp));
265
266 dev_priv->AGPHeap = mmInit(agp.offset, agp.size);
267
268 DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
269
270 return 0;
271 }
272
273 int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS )
274 {
275 DRM_DEVICE;
276 drm_sis_private_t *dev_priv = dev->dev_private;
277 drm_sis_mem_t agp;
278 PMemBlock block;
279 int retval = 0;
280
281 if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
282 return DRM_ERR(EINVAL);
283
284 DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t *)data, sizeof(agp));
285
286 block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0);
287 if (block) {
288 /* TODO */
289 agp.offset = block->ofs;
290 agp.free = (unsigned long)block;
291 if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) {
292 DRM_DEBUG("adding to allocation set fails\n");
293 mmFreeMem((PMemBlock)agp.free);
294 retval = -1;
295 }
296 } else {
297 agp.offset = 0;
298 agp.size = 0;
299 agp.free = 0;
300 }
301
302 DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, agp, sizeof(agp));
303
304 DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
305
306 return retval;
307 }
308
309 int sis_ioctl_agp_free( DRM_IOCTL_ARGS )
310 {
311 DRM_DEVICE;
312 drm_sis_private_t *dev_priv = dev->dev_private;
313 drm_sis_mem_t agp;
314
315 if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
316 return DRM_ERR(EINVAL);
317
318 DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t *)data, sizeof(agp));
319
320 if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock)agp.free))
321 return DRM_ERR(EINVAL);
322
323 mmFreeMem((PMemBlock)agp.free);
324 if (!del_alloc_set(agp.context, AGP_TYPE, agp.free))
325 return DRM_ERR(EINVAL);
326
327 DRM_DEBUG("free agp, free = 0x%lx\n", agp.free);
328
329 return 0;
330 }
331
332 int sis_init_context(int context)
333 {
334 int i;
335
336 for (i = 0; i < MAX_CONTEXT ; i++) {
337 if (global_ppriv[i].used &&
338 (global_ppriv[i].context == context))
339 break;
340 }
341
342 if (i >= MAX_CONTEXT) {
343 for (i = 0; i < MAX_CONTEXT ; i++) {
344 if (!global_ppriv[i].used) {
345 global_ppriv[i].context = context;
346 global_ppriv[i].used = 1;
347 global_ppriv[i].sets[0] = setInit();
348 global_ppriv[i].sets[1] = setInit();
349 DRM_DEBUG("init allocation set, socket=%d, "
350 "context = %d\n", i, context);
351 break;
352 }
353 }
354 if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
355 (global_ppriv[i].sets[1] == NULL))
356 {
357 return 0;
358 }
359 }
360
361 return 1;
362 }
363
364 int sis_final_context(int context)
365 {
366 int i;
367
368 for (i=0; i<MAX_CONTEXT; i++) {
369 if (global_ppriv[i].used &&
370 (global_ppriv[i].context == context))
371 break;
372 }
373
374 if (i < MAX_CONTEXT) {
375 set_t *set;
376 ITEM_TYPE item;
377 int retval;
378
379 DRM_DEBUG("find socket %d, context = %d\n", i, context);
380
381 /* Video Memory */
382 set = global_ppriv[i].sets[0];
383 retval = setFirst(set, &item);
384 while (retval) {
385 DRM_DEBUG("free video memory 0x%lx\n", item);
386 #if defined(__linux__) && defined(CONFIG_FB_SIS)
387 sis_free(item);
388 #else
389 mmFreeMem((PMemBlock)item);
390 #endif
391 retval = setNext(set, &item);
392 }
393 setDestroy(set);
394
395 /* AGP Memory */
396 set = global_ppriv[i].sets[1];
397 retval = setFirst(set, &item);
398 while (retval) {
399 DRM_DEBUG("free agp memory 0x%lx\n", item);
400 mmFreeMem((PMemBlock)item);
401 retval = setNext(set, &item);
402 }
403 setDestroy(set);
404
405 global_ppriv[i].used = 0;
406 }
407
408 return 1;
409 }
Cache object: 440ff381428a4feaa1b16932e6e4e28d
|