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