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