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