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