sis_mm.c revision 126525
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 * 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 126525 2004-03-03 06:20:36Z obrien $
30 */
31
32#include "dev/drm/sis.h"
33#include "dev/drm/drmP.h"
34#include "dev/drm/sis_drm.h"
35#include "dev/drm/sis_drv.h"
36#include "dev/drm/sis_ds.h"
37#if defined(__linux__) && defined(CONFIG_FB_SIS)
38#include <linux/sisfb.h>
39#endif
40
41#define MAX_CONTEXT 100
42#define VIDEO_TYPE 0
43#define AGP_TYPE 1
44
45typedef struct {
46	int used;
47	int context;
48	set_t *sets[2]; /* 0 for video, 1 for AGP */
49} sis_context_t;
50
51static sis_context_t global_ppriv[MAX_CONTEXT];
52
53
54static int add_alloc_set(int context, int type, unsigned int val)
55{
56	int i, retval = 0;
57
58	for (i = 0; i < MAX_CONTEXT; i++) {
59		if (global_ppriv[i].used && global_ppriv[i].context == context)
60		{
61			retval = setAdd(global_ppriv[i].sets[type], val);
62			break;
63		}
64	}
65	return retval;
66}
67
68static int del_alloc_set(int context, int type, unsigned int val)
69{
70	int i, retval = 0;
71
72	for (i = 0; i < MAX_CONTEXT; i++) {
73		if (global_ppriv[i].used && global_ppriv[i].context == context)
74		{
75			retval = setDel(global_ppriv[i].sets[type], val);
76			break;
77		}
78	}
79	return retval;
80}
81
82/* fb management via fb device */
83#if defined(__linux__) && defined(CONFIG_FB_SIS)
84
85int sis_fb_init( DRM_IOCTL_ARGS )
86{
87	return 0;
88}
89
90int sis_fb_alloc( DRM_IOCTL_ARGS )
91{
92	drm_sis_mem_t fb;
93	struct sis_memreq req;
94	int retval = 0;
95
96	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb));
97
98	req.size = fb.size;
99	sis_malloc(&req);
100	if (req.offset) {
101		/* TODO */
102		fb.offset = req.offset;
103		fb.free = req.offset;
104		if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
105			DRM_DEBUG("adding to allocation set fails\n");
106			sis_free(req.offset);
107			retval = DRM_ERR(EINVAL);
108		}
109	} else {
110		fb.offset = 0;
111		fb.size = 0;
112		fb.free = 0;
113	}
114
115	DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb));
116
117	DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset);
118
119	return retval;
120}
121
122int sis_fb_free( DRM_IOCTL_ARGS )
123{
124	drm_sis_mem_t fb;
125	int retval = 0;
126
127	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb));
128
129	if (!fb.free)
130		return DRM_ERR(EINVAL);
131
132	if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
133		retval = DRM_ERR(EINVAL);
134	sis_free(fb.free);
135
136	DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
137
138	return retval;
139}
140
141#else
142
143/* Called by the X Server to initialize the FB heap.  Allocations will fail
144 * unless this is called.  Offset is the beginning of the heap from the
145 * framebuffer offset (MaxXFBMem in XFree86).
146 *
147 * Memory layout according to Thomas Winischofer:
148 * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC|
149 *
150 *    X driver/sisfb                                  HW-   Command-
151 *  framebuffer memory           DRI heap           Cursor   queue
152 */
153int sis_fb_init( DRM_IOCTL_ARGS )
154{
155	DRM_DEVICE;
156	drm_sis_private_t *dev_priv = dev->dev_private;
157	drm_sis_fb_t fb;
158
159	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t *)data, sizeof(fb));
160
161	if (dev_priv == NULL) {
162		dev->dev_private = DRM(calloc)(1, sizeof(drm_sis_private_t),
163		    DRM_MEM_DRIVER);
164		dev_priv = dev->dev_private;
165		if (dev_priv == NULL)
166			return ENOMEM;
167	}
168
169	if (dev_priv->FBHeap != NULL)
170		return DRM_ERR(EINVAL);
171
172	dev_priv->FBHeap = mmInit(fb.offset, fb.size);
173
174	DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
175
176	return 0;
177}
178
179int sis_fb_alloc( DRM_IOCTL_ARGS )
180{
181	DRM_DEVICE;
182	drm_sis_private_t *dev_priv = dev->dev_private;
183	drm_sis_mem_t fb;
184	PMemBlock block;
185	int retval = 0;
186
187	if (dev_priv == NULL || dev_priv->FBHeap == NULL)
188		return DRM_ERR(EINVAL);
189
190	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb));
191
192	block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0);
193	if (block) {
194		/* TODO */
195		fb.offset = block->ofs;
196		fb.free = (unsigned long)block;
197		if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
198			DRM_DEBUG("adding to allocation set fails\n");
199			mmFreeMem((PMemBlock)fb.free);
200			retval = DRM_ERR(EINVAL);
201		}
202	} else {
203		fb.offset = 0;
204		fb.size = 0;
205		fb.free = 0;
206	}
207
208	DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb));
209
210	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset);
211
212	return retval;
213}
214
215int sis_fb_free( DRM_IOCTL_ARGS )
216{
217	DRM_DEVICE;
218	drm_sis_private_t *dev_priv = dev->dev_private;
219	drm_sis_mem_t fb;
220
221	if (dev_priv == NULL || dev_priv->FBHeap == NULL)
222		return DRM_ERR(EINVAL);
223
224	DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb));
225
226	if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock)fb.free))
227		return DRM_ERR(EINVAL);
228
229	if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
230		return DRM_ERR(EINVAL);
231	mmFreeMem((PMemBlock)fb.free);
232
233	DRM_DEBUG("free fb, free = 0x%lx\n", fb.free);
234
235	return 0;
236}
237
238#endif
239
240/* agp memory management */
241
242int sis_ioctl_agp_init( DRM_IOCTL_ARGS )
243{
244	DRM_DEVICE;
245	drm_sis_private_t *dev_priv = dev->dev_private;
246	drm_sis_agp_t agp;
247
248	if (dev_priv == NULL) {
249		dev->dev_private = DRM(calloc)(1, sizeof(drm_sis_private_t),
250		    DRM_MEM_DRIVER);
251		dev_priv = dev->dev_private;
252		if (dev_priv == NULL)
253			return ENOMEM;
254	}
255
256	if (dev_priv->AGPHeap != NULL)
257		return DRM_ERR(EINVAL);
258
259	DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t *)data, sizeof(agp));
260
261	dev_priv->AGPHeap = mmInit(agp.offset, agp.size);
262
263	DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
264
265	return 0;
266}
267
268int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS )
269{
270	DRM_DEVICE;
271	drm_sis_private_t *dev_priv = dev->dev_private;
272	drm_sis_mem_t agp;
273	PMemBlock block;
274	int retval = 0;
275
276	if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
277		return DRM_ERR(EINVAL);
278
279	DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t *)data, sizeof(agp));
280
281	block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0);
282	if (block) {
283		/* TODO */
284		agp.offset = block->ofs;
285		agp.free = (unsigned long)block;
286		if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) {
287			DRM_DEBUG("adding to allocation set fails\n");
288			mmFreeMem((PMemBlock)agp.free);
289			retval = -1;
290		}
291	} else {
292		agp.offset = 0;
293		agp.size = 0;
294		agp.free = 0;
295	}
296
297	DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, agp, sizeof(agp));
298
299	DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
300
301	return retval;
302}
303
304int sis_ioctl_agp_free( DRM_IOCTL_ARGS )
305{
306	DRM_DEVICE;
307	drm_sis_private_t *dev_priv = dev->dev_private;
308	drm_sis_mem_t agp;
309
310	if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
311		return DRM_ERR(EINVAL);
312
313	DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t *)data, sizeof(agp));
314
315	if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock)agp.free))
316		return DRM_ERR(EINVAL);
317
318	mmFreeMem((PMemBlock)agp.free);
319	if (!del_alloc_set(agp.context, AGP_TYPE, agp.free))
320		return DRM_ERR(EINVAL);
321
322	DRM_DEBUG("free agp, free = 0x%lx\n", agp.free);
323
324	return 0;
325}
326
327int sis_init_context(int context)
328{
329	int i;
330
331	for (i = 0; i < MAX_CONTEXT ; i++) {
332		if (global_ppriv[i].used &&
333		    (global_ppriv[i].context == context))
334			break;
335	}
336
337	if (i >= MAX_CONTEXT) {
338		for (i = 0; i < MAX_CONTEXT ; i++) {
339			if (!global_ppriv[i].used) {
340				global_ppriv[i].context = context;
341				global_ppriv[i].used = 1;
342				global_ppriv[i].sets[0] = setInit();
343				global_ppriv[i].sets[1] = setInit();
344				DRM_DEBUG("init allocation set, socket=%d, "
345				    "context = %d\n", i, context);
346				break;
347			}
348		}
349		if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
350		    (global_ppriv[i].sets[1] == NULL))
351		{
352			return 0;
353		}
354	}
355
356	return 1;
357}
358
359int sis_final_context(int context)
360{
361	int i;
362
363	for (i=0; i<MAX_CONTEXT; i++) {
364		if (global_ppriv[i].used &&
365		    (global_ppriv[i].context == context))
366			break;
367	}
368
369	if (i < MAX_CONTEXT) {
370		set_t *set;
371		ITEM_TYPE item;
372		int retval;
373
374		DRM_DEBUG("find socket %d, context = %d\n", i, context);
375
376		/* Video Memory */
377		set = global_ppriv[i].sets[0];
378		retval = setFirst(set, &item);
379		while (retval) {
380			DRM_DEBUG("free video memory 0x%lx\n", item);
381#if defined(__linux__) && defined(CONFIG_FB_SIS)
382			sis_free(item);
383#else
384			mmFreeMem((PMemBlock)item);
385#endif
386			retval = setNext(set, &item);
387		}
388		setDestroy(set);
389
390		/* AGP Memory */
391		set = global_ppriv[i].sets[1];
392		retval = setFirst(set, &item);
393		while (retval) {
394			DRM_DEBUG("free agp memory 0x%lx\n", item);
395			mmFreeMem((PMemBlock)item);
396			retval = setNext(set, &item);
397		}
398		setDestroy(set);
399
400		global_ppriv[i].used = 0;
401        }
402
403	return 1;
404}
405