1119895Sanholt/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*-
2152909Sanholt * Created: Mon Jan  4 10:05:05 1999 by sclin@sis.com.tw
3152909Sanholt *
4119895Sanholt * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
5119895Sanholt * All rights reserved.
6119895Sanholt *
7119895Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
8119895Sanholt * copy of this software and associated documentation files (the "Software"),
9119895Sanholt * to deal in the Software without restriction, including without limitation
10119895Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11119895Sanholt * and/or sell copies of the Software, and to permit persons to whom the
12119895Sanholt * Software is furnished to do so, subject to the following conditions:
13145132Sanholt *
14119895Sanholt * The above copyright notice and this permission notice (including the next
15119895Sanholt * paragraph) shall be included in all copies or substantial portions of the
16119895Sanholt * Software.
17145132Sanholt *
18119895Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19119895Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20119895Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21119895Sanholt * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22119895Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23119895Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24119895Sanholt * DEALINGS IN THE SOFTWARE.
25145132Sanholt *
26119895Sanholt * Authors:
27119895Sanholt *    Sung-Ching Lin <sclin@sis.com.tw>
28145132Sanholt *
29119895Sanholt */
30119895Sanholt
31152909Sanholt#include <sys/cdefs.h>
32152909Sanholt__FBSDID("$FreeBSD$");
33152909Sanholt
34119895Sanholt#if defined(__linux__) && defined(CONFIG_FB_SIS)
35130331Sanholt#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
36130331Sanholt#include <video/sisfb.h>
37130331Sanholt#else
38119895Sanholt#include <linux/sisfb.h>
39119895Sanholt#endif
40130331Sanholt#endif
41145132Sanholt#include "dev/drm/drmP.h"
42145132Sanholt#include "dev/drm/sis_drm.h"
43145132Sanholt#include "dev/drm/sis_drv.h"
44145132Sanholt#include "dev/drm/sis_ds.h"
45119895Sanholt
46119895Sanholt#define MAX_CONTEXT 100
47145132Sanholt#define VIDEO_TYPE 0
48119895Sanholt#define AGP_TYPE 1
49119895Sanholt
50119895Sanholttypedef struct {
51119895Sanholt	int used;
52119895Sanholt	int context;
53145132Sanholt	set_t *sets[2];		/* 0 for video, 1 for AGP */
54119895Sanholt} sis_context_t;
55119895Sanholt
56119895Sanholtstatic sis_context_t global_ppriv[MAX_CONTEXT];
57119895Sanholt
58119895Sanholtstatic int add_alloc_set(int context, int type, unsigned int val)
59119895Sanholt{
60119895Sanholt	int i, retval = 0;
61145132Sanholt
62119895Sanholt	for (i = 0; i < MAX_CONTEXT; i++) {
63145132Sanholt		if (global_ppriv[i].used && global_ppriv[i].context == context) {
64119895Sanholt			retval = setAdd(global_ppriv[i].sets[type], val);
65119895Sanholt			break;
66119895Sanholt		}
67119895Sanholt	}
68119895Sanholt	return retval;
69119895Sanholt}
70119895Sanholt
71119895Sanholtstatic int del_alloc_set(int context, int type, unsigned int val)
72145132Sanholt{
73119895Sanholt	int i, retval = 0;
74119895Sanholt
75119895Sanholt	for (i = 0; i < MAX_CONTEXT; i++) {
76145132Sanholt		if (global_ppriv[i].used && global_ppriv[i].context == context) {
77119895Sanholt			retval = setDel(global_ppriv[i].sets[type], val);
78119895Sanholt			break;
79119895Sanholt		}
80119895Sanholt	}
81119895Sanholt	return retval;
82119895Sanholt}
83119895Sanholt
84145132Sanholt/* fb management via fb device */
85119895Sanholt#if defined(__linux__) && defined(CONFIG_FB_SIS)
86119895Sanholt
87182080Srnolandstatic int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
88119895Sanholt{
89119895Sanholt	return 0;
90119895Sanholt}
91119895Sanholt
92182080Srnolandstatic int sis_fb_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
93119895Sanholt{
94182080Srnoland	drm_sis_mem_t *fb = data;
95119895Sanholt	struct sis_memreq req;
96119895Sanholt	int retval = 0;
97119895Sanholt
98182080Srnoland	req.size = fb->size;
99119895Sanholt	sis_malloc(&req);
100119895Sanholt	if (req.offset) {
101119895Sanholt		/* TODO */
102182080Srnoland		fb->offset = req.offset;
103182080Srnoland		fb->free = req.offset;
104182080Srnoland		if (!add_alloc_set(fb->context, VIDEO_TYPE, fb->free)) {
105119895Sanholt			DRM_DEBUG("adding to allocation set fails\n");
106119895Sanholt			sis_free(req.offset);
107182080Srnoland			retval = -EINVAL;
108119895Sanholt		}
109145132Sanholt	} else {
110182080Srnoland		fb->offset = 0;
111182080Srnoland		fb->size = 0;
112182080Srnoland		fb->free = 0;
113119895Sanholt	}
114119895Sanholt
115182080Srnoland	DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb->size, req.offset);
116119895Sanholt
117119895Sanholt	return retval;
118119895Sanholt}
119119895Sanholt
120182080Srnolandstatic int sis_fb_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
121119895Sanholt{
122119895Sanholt	drm_sis_mem_t fb;
123119895Sanholt	int retval = 0;
124119895Sanholt
125182080Srnoland	if (!fb->free)
126182080Srnoland		return -EINVAL;
127119895Sanholt
128182080Srnoland	if (!del_alloc_set(fb->context, VIDEO_TYPE, fb->free))
129182080Srnoland		retval = -EINVAL;
130182080Srnoland	sis_free(fb->free);
131119895Sanholt
132182080Srnoland	DRM_DEBUG("free fb, offset = 0x%lx\n", fb->free);
133119895Sanholt
134119895Sanholt	return retval;
135119895Sanholt}
136119895Sanholt
137119895Sanholt#else
138119895Sanholt
139119895Sanholt/* Called by the X Server to initialize the FB heap.  Allocations will fail
140119895Sanholt * unless this is called.  Offset is the beginning of the heap from the
141119895Sanholt * framebuffer offset (MaxXFBMem in XFree86).
142119895Sanholt *
143119895Sanholt * Memory layout according to Thomas Winischofer:
144119895Sanholt * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC|
145119895Sanholt *
146119895Sanholt *    X driver/sisfb                                  HW-   Command-
147119895Sanholt *  framebuffer memory           DRI heap           Cursor   queue
148119895Sanholt */
149182080Srnolandstatic int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
150119895Sanholt{
151119895Sanholt	drm_sis_private_t *dev_priv = dev->dev_private;
152182080Srnoland	drm_sis_fb_t *fb = data;
153119895Sanholt
154119895Sanholt	if (dev_priv == NULL) {
155145132Sanholt		dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
156145132Sanholt					      DRM_MEM_DRIVER);
157119895Sanholt		dev_priv = dev->dev_private;
158119895Sanholt		if (dev_priv == NULL)
159119895Sanholt			return ENOMEM;
160119895Sanholt	}
161119895Sanholt
162119895Sanholt	if (dev_priv->FBHeap != NULL)
163182080Srnoland		return -EINVAL;
164119895Sanholt
165182080Srnoland	dev_priv->FBHeap = mmInit(fb->offset, fb->size);
166119895Sanholt
167182080Srnoland	DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size);
168119895Sanholt
169119895Sanholt	return 0;
170119895Sanholt}
171119895Sanholt
172182080Srnolandstatic int sis_fb_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
173119895Sanholt{
174119895Sanholt	drm_sis_private_t *dev_priv = dev->dev_private;
175182080Srnoland	drm_sis_mem_t *fb = data;
176119895Sanholt	PMemBlock block;
177119895Sanholt	int retval = 0;
178119895Sanholt
179119895Sanholt	if (dev_priv == NULL || dev_priv->FBHeap == NULL)
180182080Srnoland		return -EINVAL;
181145132Sanholt
182182080Srnoland	block = mmAllocMem(dev_priv->FBHeap, fb->size, 0, 0);
183119895Sanholt	if (block) {
184119895Sanholt		/* TODO */
185182080Srnoland		fb->offset = block->ofs;
186182080Srnoland		fb->free = (unsigned long)block;
187182080Srnoland		if (!add_alloc_set(fb->context, VIDEO_TYPE, fb->free)) {
188119895Sanholt			DRM_DEBUG("adding to allocation set fails\n");
189182080Srnoland			mmFreeMem((PMemBlock) fb->free);
190182080Srnoland			retval = -EINVAL;
191119895Sanholt		}
192119895Sanholt	} else {
193182080Srnoland		fb->offset = 0;
194182080Srnoland		fb->size = 0;
195182080Srnoland		fb->free = 0;
196119895Sanholt	}
197119895Sanholt
198182080Srnoland	DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb->size, fb->offset);
199119895Sanholt
200119895Sanholt	return retval;
201119895Sanholt}
202119895Sanholt
203182080Srnolandstatic int sis_fb_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
204119895Sanholt{
205119895Sanholt	drm_sis_private_t *dev_priv = dev->dev_private;
206182080Srnoland	drm_sis_mem_t *fb = data;
207119895Sanholt
208119895Sanholt	if (dev_priv == NULL || dev_priv->FBHeap == NULL)
209182080Srnoland		return -EINVAL;
210119895Sanholt
211182080Srnoland	if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock) fb->free))
212182080Srnoland		return -EINVAL;
213119895Sanholt
214182080Srnoland	if (!del_alloc_set(fb->context, VIDEO_TYPE, fb->free))
215182080Srnoland		return -EINVAL;
216182080Srnoland	mmFreeMem((PMemBlock) fb->free);
217119895Sanholt
218182080Srnoland	DRM_DEBUG("free fb, free = 0x%lx\n", fb->free);
219119895Sanholt
220119895Sanholt	return 0;
221119895Sanholt}
222119895Sanholt
223119895Sanholt#endif
224119895Sanholt
225145132Sanholt/* agp memory management */
226119895Sanholt
227182080Srnolandstatic int sis_ioctl_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
228119895Sanholt{
229119895Sanholt	drm_sis_private_t *dev_priv = dev->dev_private;
230182080Srnoland	drm_sis_agp_t *agp = data;
231119895Sanholt
232119895Sanholt	if (dev_priv == NULL) {
233145132Sanholt		dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
234145132Sanholt					      DRM_MEM_DRIVER);
235119895Sanholt		dev_priv = dev->dev_private;
236119895Sanholt		if (dev_priv == NULL)
237119895Sanholt			return ENOMEM;
238119895Sanholt	}
239119895Sanholt
240119895Sanholt	if (dev_priv->AGPHeap != NULL)
241182080Srnoland		return -EINVAL;
242119895Sanholt
243182080Srnoland	dev_priv->AGPHeap = mmInit(agp->offset, agp->size);
244119895Sanholt
245182080Srnoland	DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size);
246119895Sanholt
247119895Sanholt	return 0;
248119895Sanholt}
249119895Sanholt
250182080Srnolandstatic int sis_ioctl_agp_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
251119895Sanholt{
252119895Sanholt	drm_sis_private_t *dev_priv = dev->dev_private;
253182080Srnoland	drm_sis_mem_t *agp = data;
254119895Sanholt	PMemBlock block;
255119895Sanholt	int retval = 0;
256145132Sanholt
257119895Sanholt	if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
258182080Srnoland		return -EINVAL;
259145132Sanholt
260182080Srnoland	block = mmAllocMem(dev_priv->AGPHeap, agp->size, 0, 0);
261119895Sanholt	if (block) {
262119895Sanholt		/* TODO */
263182080Srnoland		agp->offset = block->ofs;
264182080Srnoland		agp->free = (unsigned long)block;
265182080Srnoland		if (!add_alloc_set(agp->context, AGP_TYPE, agp->free)) {
266119895Sanholt			DRM_DEBUG("adding to allocation set fails\n");
267182080Srnoland			mmFreeMem((PMemBlock) agp->free);
268119895Sanholt			retval = -1;
269119895Sanholt		}
270145132Sanholt	} else {
271182080Srnoland		agp->offset = 0;
272182080Srnoland		agp->size = 0;
273182080Srnoland		agp->free = 0;
274119895Sanholt	}
275119895Sanholt
276182080Srnoland	DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp->size,
277182080Srnoland	    agp->offset);
278119895Sanholt
279119895Sanholt	return retval;
280119895Sanholt}
281119895Sanholt
282182080Srnolandstatic int sis_ioctl_agp_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
283119895Sanholt{
284119895Sanholt	drm_sis_private_t *dev_priv = dev->dev_private;
285182080Srnoland	drm_sis_mem_t *agp = data;
286119895Sanholt
287119895Sanholt	if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
288182080Srnoland		return -EINVAL;
289119895Sanholt
290182080Srnoland	if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock) agp->free))
291182080Srnoland		return -EINVAL;
292119895Sanholt
293182080Srnoland	mmFreeMem((PMemBlock) agp->free);
294182080Srnoland	if (!del_alloc_set(agp->context, AGP_TYPE, agp->free))
295182080Srnoland		return -EINVAL;
296119895Sanholt
297182080Srnoland	DRM_DEBUG("free agp, free = 0x%lx\n", agp->free);
298119895Sanholt
299119895Sanholt	return 0;
300119895Sanholt}
301119895Sanholt
302145132Sanholtint sis_init_context(struct drm_device *dev, int context)
303119895Sanholt{
304119895Sanholt	int i;
305119895Sanholt
306145132Sanholt	for (i = 0; i < MAX_CONTEXT; i++) {
307119895Sanholt		if (global_ppriv[i].used &&
308119895Sanholt		    (global_ppriv[i].context == context))
309119895Sanholt			break;
310119895Sanholt	}
311119895Sanholt
312119895Sanholt	if (i >= MAX_CONTEXT) {
313145132Sanholt		for (i = 0; i < MAX_CONTEXT; i++) {
314119895Sanholt			if (!global_ppriv[i].used) {
315119895Sanholt				global_ppriv[i].context = context;
316119895Sanholt				global_ppriv[i].used = 1;
317119895Sanholt				global_ppriv[i].sets[0] = setInit();
318119895Sanholt				global_ppriv[i].sets[1] = setInit();
319119895Sanholt				DRM_DEBUG("init allocation set, socket=%d, "
320145132Sanholt					  "context = %d\n", i, context);
321119895Sanholt				break;
322119895Sanholt			}
323119895Sanholt		}
324119895Sanholt		if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
325145132Sanholt		    (global_ppriv[i].sets[1] == NULL)) {
326119895Sanholt			return 0;
327119895Sanholt		}
328119895Sanholt	}
329145132Sanholt
330119895Sanholt	return 1;
331119895Sanholt}
332119895Sanholt
333145132Sanholtint sis_final_context(struct drm_device *dev, int context)
334119895Sanholt{
335119895Sanholt	int i;
336119895Sanholt
337145132Sanholt	for (i = 0; i < MAX_CONTEXT; i++) {
338119895Sanholt		if (global_ppriv[i].used &&
339119895Sanholt		    (global_ppriv[i].context == context))
340119895Sanholt			break;
341119895Sanholt	}
342119895Sanholt
343119895Sanholt	if (i < MAX_CONTEXT) {
344119895Sanholt		set_t *set;
345126525Sobrien		ITEM_TYPE item;
346119895Sanholt		int retval;
347119895Sanholt
348119895Sanholt		DRM_DEBUG("find socket %d, context = %d\n", i, context);
349119895Sanholt
350119895Sanholt		/* Video Memory */
351119895Sanholt		set = global_ppriv[i].sets[0];
352119895Sanholt		retval = setFirst(set, &item);
353119895Sanholt		while (retval) {
354126525Sobrien			DRM_DEBUG("free video memory 0x%lx\n", item);
355119895Sanholt#if defined(__linux__) && defined(CONFIG_FB_SIS)
356119895Sanholt			sis_free(item);
357119895Sanholt#else
358145132Sanholt			mmFreeMem((PMemBlock) item);
359119895Sanholt#endif
360119895Sanholt			retval = setNext(set, &item);
361119895Sanholt		}
362119895Sanholt		setDestroy(set);
363119895Sanholt
364119895Sanholt		/* AGP Memory */
365119895Sanholt		set = global_ppriv[i].sets[1];
366119895Sanholt		retval = setFirst(set, &item);
367119895Sanholt		while (retval) {
368126525Sobrien			DRM_DEBUG("free agp memory 0x%lx\n", item);
369145132Sanholt			mmFreeMem((PMemBlock) item);
370119895Sanholt			retval = setNext(set, &item);
371119895Sanholt		}
372119895Sanholt		setDestroy(set);
373119895Sanholt
374145132Sanholt		global_ppriv[i].used = 0;
375145132Sanholt	}
376145132Sanholt
377119895Sanholt	return 1;
378119895Sanholt}
379145132Sanholt
380145132Sanholtdrm_ioctl_desc_t sis_ioctls[] = {
381182080Srnoland	DRM_IOCTL_DEF(DRM_SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH),
382182080Srnoland	DRM_IOCTL_DEF(DRM_SIS_FB_FREE, sis_fb_free, DRM_AUTH),
383182080Srnoland	DRM_IOCTL_DEF(DRM_SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
384182080Srnoland	DRM_IOCTL_DEF(DRM_SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH),
385182080Srnoland	DRM_IOCTL_DEF(DRM_SIS_AGP_FREE, sis_ioctl_agp_free, DRM_AUTH),
386182080Srnoland	DRM_IOCTL_DEF(DRM_SIS_FB_INIT, sis_fb_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY)
387145132Sanholt};
388145132Sanholt
389145132Sanholtint sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
390