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 */ 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 47typedef struct { 48 int used; 49 int context; 50 set_t *sets[2]; /* 0 for video, 1 for AGP */ 51} sis_context_t; 52 53static sis_context_t global_ppriv[MAX_CONTEXT]; 54 55static 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 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 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 84static int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) 85{ 86 return 0; 87} 88 89static 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 117static 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 */ 146static 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 169static 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 200static 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 224static 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 247static 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 279static 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 299int 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 330int 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 377drm_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 386int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls); 387