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