167754Smsmith/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*- 267754Smsmith * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw 3249112Sjkim * 467754Smsmith * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. 567754Smsmith * All rights reserved. 667754Smsmith * 7217365Sjkim * Permission is hereby granted, free of charge, to any person obtaining a 8245582Sjkim * copy of this software and associated documentation files (the "Software"), 970243Smsmith * to deal in the Software without restriction, including without limitation 1067754Smsmith * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11217365Sjkim * and/or sell copies of the Software, and to permit persons to whom the 12217365Sjkim * Software is furnished to do so, subject to the following conditions: 13217365Sjkim * 14217365Sjkim * The above copyright notice and this permission notice (including the next 15217365Sjkim * paragraph) shall be included in all copies or substantial portions of the 16217365Sjkim * Software. 17217365Sjkim * 18217365Sjkim * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19217365Sjkim * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20217365Sjkim * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21217365Sjkim * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22217365Sjkim * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23217365Sjkim * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24217365Sjkim * DEALINGS IN THE SOFTWARE. 2567754Smsmith * 26217365Sjkim * Authors: 27217365Sjkim * Sung-Ching Lin <sclin@sis.com.tw> 28217365Sjkim * 2967754Smsmith */ 30217365Sjkim 31217365Sjkim#include <sys/cdefs.h> 32217365Sjkim__FBSDID("$FreeBSD: releng/11.0/sys/dev/drm/sis_mm.c 182080 2008-08-23 20:59:12Z rnoland $"); 33217365Sjkim 34217365Sjkim#if defined(__linux__) && defined(CONFIG_FB_SIS) 35217365Sjkim#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) 36217365Sjkim#include <video/sisfb.h> 37217365Sjkim#else 38217365Sjkim#include <linux/sisfb.h> 39217365Sjkim#endif 40217365Sjkim#endif 41217365Sjkim#include "dev/drm/drmP.h" 42217365Sjkim#include "dev/drm/sis_drm.h" 4367754Smsmith#include "dev/drm/sis_drv.h" 4467754Smsmith#include "dev/drm/sis_ds.h" 4567754Smsmith 46193341Sjkim#define MAX_CONTEXT 100 47193341Sjkim#define VIDEO_TYPE 0 48193341Sjkim#define AGP_TYPE 1 49193341Sjkim 50193341Sjkimtypedef struct { 51193341Sjkim int used; 52193341Sjkim int context; 53193341Sjkim set_t *sets[2]; /* 0 for video, 1 for AGP */ 54193341Sjkim} sis_context_t; 5567754Smsmith 5677424Smsmithstatic sis_context_t global_ppriv[MAX_CONTEXT]; 5791116Smsmith 5867754Smsmithstatic int add_alloc_set(int context, int type, unsigned int val) 59151937Sjkim{ 6067754Smsmith int i, retval = 0; 61151937Sjkim 62151937Sjkim for (i = 0; i < MAX_CONTEXT; i++) { 63151937Sjkim if (global_ppriv[i].used && global_ppriv[i].context == context) { 64151937Sjkim retval = setAdd(global_ppriv[i].sets[type], val); 65151937Sjkim break; 66151937Sjkim } 67151937Sjkim } 68151937Sjkim return retval; 69151937Sjkim} 70151937Sjkim 71151937Sjkimstatic int del_alloc_set(int context, int type, unsigned int val) 7267754Smsmith{ 7367754Smsmith int i, retval = 0; 7467754Smsmith 75151937Sjkim for (i = 0; i < MAX_CONTEXT; i++) { 7667754Smsmith if (global_ppriv[i].used && global_ppriv[i].context == context) { 7767754Smsmith retval = setDel(global_ppriv[i].sets[type], val); 7867754Smsmith break; 7999679Siwasaki } 8067754Smsmith } 81151937Sjkim return retval; 8267754Smsmith} 8367754Smsmith 8467754Smsmith/* fb management via fb device */ 8567754Smsmith#if defined(__linux__) && defined(CONFIG_FB_SIS) 8667754Smsmith 8767754Smsmithstatic int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) 8867754Smsmith{ 8967754Smsmith return 0; 9067754Smsmith} 9167754Smsmith 9267754Smsmithstatic int sis_fb_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) 9367754Smsmith{ 9467754Smsmith drm_sis_mem_t *fb = data; 9567754Smsmith struct sis_memreq req; 9667754Smsmith int retval = 0; 9767754Smsmith 9867754Smsmith req.size = fb->size; 9967754Smsmith sis_malloc(&req); 100151937Sjkim if (req.offset) { 10167754Smsmith /* TODO */ 10299679Siwasaki fb->offset = req.offset; 10367754Smsmith fb->free = req.offset; 10499679Siwasaki if (!add_alloc_set(fb->context, VIDEO_TYPE, fb->free)) { 10599679Siwasaki DRM_DEBUG("adding to allocation set fails\n"); 10699679Siwasaki sis_free(req.offset); 10799679Siwasaki retval = -EINVAL; 108151937Sjkim } 109151937Sjkim } else { 11067754Smsmith fb->offset = 0; 11167754Smsmith fb->size = 0; 11267754Smsmith fb->free = 0; 11399679Siwasaki } 11467754Smsmith 115151937Sjkim DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb->size, req.offset); 11667754Smsmith 117151937Sjkim return retval; 11899679Siwasaki} 11999679Siwasaki 12099679Siwasakistatic int sis_fb_free(struct drm_device *dev, void *data, struct drm_file *file_priv) 12199679Siwasaki{ 12299679Siwasaki drm_sis_mem_t fb; 12399679Siwasaki int retval = 0; 12499679Siwasaki 12567754Smsmith if (!fb->free) 12667754Smsmith return -EINVAL; 12767754Smsmith 12877424Smsmith if (!del_alloc_set(fb->context, VIDEO_TYPE, fb->free)) 12977424Smsmith retval = -EINVAL; 13099679Siwasaki sis_free(fb->free); 13167754Smsmith 13267754Smsmith DRM_DEBUG("free fb, offset = 0x%lx\n", fb->free); 133167802Sjkim 13467754Smsmith return retval; 13567754Smsmith} 13699679Siwasaki 13767754Smsmith#else 138193267Sjkim 13967754Smsmith/* Called by the X Server to initialize the FB heap. Allocations will fail 140167802Sjkim * unless this is called. Offset is the beginning of the heap from the 141167802Sjkim * framebuffer offset (MaxXFBMem in XFree86). 14299679Siwasaki * 14367754Smsmith * Memory layout according to Thomas Winischofer: 14499679Siwasaki * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC| 14584491Smsmith * 14684491Smsmith * X driver/sisfb HW- Command- 14784491Smsmith * framebuffer memory DRI heap Cursor queue 14867754Smsmith */ 14999679Siwasakistatic int sis_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) 15099679Siwasaki{ 151102550Siwasaki drm_sis_private_t *dev_priv = dev->dev_private; 15267754Smsmith drm_sis_fb_t *fb = data; 15399679Siwasaki 15467754Smsmith if (dev_priv == NULL) { 155167802Sjkim dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t), 156167802Sjkim DRM_MEM_DRIVER); 157167802Sjkim dev_priv = dev->dev_private; 158167802Sjkim if (dev_priv == NULL) 15967754Smsmith return ENOMEM; 16067754Smsmith } 16167754Smsmith 16267754Smsmith if (dev_priv->FBHeap != NULL) 16367754Smsmith return -EINVAL; 16499679Siwasaki 16599679Siwasaki dev_priv->FBHeap = mmInit(fb->offset, fb->size); 16667754Smsmith 16767754Smsmith DRM_DEBUG("offset = %u, size = %u", fb->offset, fb->size); 16867754Smsmith 16999679Siwasaki return 0; 17067754Smsmith} 17177424Smsmith 17277424Smsmithstatic int sis_fb_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) 17377424Smsmith{ 17477424Smsmith drm_sis_private_t *dev_priv = dev->dev_private; 175151937Sjkim drm_sis_mem_t *fb = data; 17699679Siwasaki PMemBlock block; 17799679Siwasaki int retval = 0; 178151937Sjkim 179151937Sjkim if (dev_priv == NULL || dev_priv->FBHeap == NULL) 180151937Sjkim return -EINVAL; 181151937Sjkim 182151937Sjkim block = mmAllocMem(dev_priv->FBHeap, fb->size, 0, 0); 183167802Sjkim if (block) { 184167802Sjkim /* TODO */ 185151937Sjkim fb->offset = block->ofs; 186151937Sjkim fb->free = (unsigned long)block; 187151937Sjkim if (!add_alloc_set(fb->context, VIDEO_TYPE, fb->free)) { 18877424Smsmith DRM_DEBUG("adding to allocation set fails\n"); 18977424Smsmith mmFreeMem((PMemBlock) fb->free); 19077424Smsmith retval = -EINVAL; 19167754Smsmith } 19277424Smsmith } else { 19367754Smsmith fb->offset = 0; 19499679Siwasaki fb->size = 0; 19599679Siwasaki fb->free = 0; 19699679Siwasaki } 19767754Smsmith 19867754Smsmith DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb->size, fb->offset); 19977424Smsmith 20067754Smsmith return retval; 20177424Smsmith} 20267754Smsmith 20399679Siwasakistatic int sis_fb_free(struct drm_device *dev, void *data, struct drm_file *file_priv) 20499679Siwasaki{ 20599679Siwasaki drm_sis_private_t *dev_priv = dev->dev_private; 20667754Smsmith drm_sis_mem_t *fb = data; 20767754Smsmith 20877424Smsmith if (dev_priv == NULL || dev_priv->FBHeap == NULL) 20967754Smsmith return -EINVAL; 21077424Smsmith 21167754Smsmith if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock) fb->free)) 21299679Siwasaki return -EINVAL; 21399679Siwasaki 21499679Siwasaki if (!del_alloc_set(fb->context, VIDEO_TYPE, fb->free)) 21567754Smsmith return -EINVAL; 21667754Smsmith mmFreeMem((PMemBlock) fb->free); 21777424Smsmith 21867754Smsmith DRM_DEBUG("free fb, free = 0x%lx\n", fb->free); 21977424Smsmith 22067754Smsmith return 0; 22199679Siwasaki} 22299679Siwasaki 22399679Siwasaki#endif 22467754Smsmith 22567754Smsmith/* agp memory management */ 22677424Smsmith 22767754Smsmithstatic int sis_ioctl_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv) 22877424Smsmith{ 22967754Smsmith drm_sis_private_t *dev_priv = dev->dev_private; 23099679Siwasaki drm_sis_agp_t *agp = data; 23199679Siwasaki 23299679Siwasaki if (dev_priv == NULL) { 23367754Smsmith dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t), 23467754Smsmith DRM_MEM_DRIVER); 23567754Smsmith dev_priv = dev->dev_private; 23667754Smsmith if (dev_priv == NULL) 237167802Sjkim return ENOMEM; 238204773Sjkim } 23999679Siwasaki 24067754Smsmith if (dev_priv->AGPHeap != NULL) 24167754Smsmith return -EINVAL; 24267754Smsmith 24367754Smsmith dev_priv->AGPHeap = mmInit(agp->offset, agp->size); 24499679Siwasaki 24599679Siwasaki DRM_DEBUG("offset = %u, size = %u", agp->offset, agp->size); 24699679Siwasaki 24799679Siwasaki return 0; 24899679Siwasaki} 249167802Sjkim 250204773Sjkimstatic int sis_ioctl_agp_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) 251167802Sjkim{ 252167802Sjkim drm_sis_private_t *dev_priv = dev->dev_private; 253167802Sjkim drm_sis_mem_t *agp = data; 254167802Sjkim PMemBlock block; 25599679Siwasaki int retval = 0; 25699679Siwasaki 25799679Siwasaki if (dev_priv == NULL || dev_priv->AGPHeap == NULL) 25899679Siwasaki return -EINVAL; 25967754Smsmith 26099679Siwasaki block = mmAllocMem(dev_priv->AGPHeap, agp->size, 0, 0); 261151937Sjkim if (block) { 262151937Sjkim /* TODO */ 26367754Smsmith agp->offset = block->ofs; 26499679Siwasaki agp->free = (unsigned long)block; 26599679Siwasaki if (!add_alloc_set(agp->context, AGP_TYPE, agp->free)) { 26699679Siwasaki DRM_DEBUG("adding to allocation set fails\n"); 26767754Smsmith mmFreeMem((PMemBlock) agp->free); 26899679Siwasaki retval = -1; 26999679Siwasaki } 27067754Smsmith } else { 27199679Siwasaki agp->offset = 0; 27267754Smsmith agp->size = 0; 27399679Siwasaki agp->free = 0; 27467754Smsmith } 275151937Sjkim 276151937Sjkim DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp->size, 27767754Smsmith agp->offset); 27867754Smsmith 27999679Siwasaki return retval; 28067754Smsmith} 28199679Siwasaki 28267754Smsmithstatic int sis_ioctl_agp_free(struct drm_device *dev, void *data, struct drm_file *file_priv) 28399679Siwasaki{ 28499679Siwasaki drm_sis_private_t *dev_priv = dev->dev_private; 28567754Smsmith drm_sis_mem_t *agp = data; 28699679Siwasaki 28799679Siwasaki if (dev_priv == NULL || dev_priv->AGPHeap == NULL) 28899679Siwasaki return -EINVAL; 28999679Siwasaki 29067754Smsmith if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock) agp->free)) 29199679Siwasaki return -EINVAL; 29267754Smsmith 29399679Siwasaki mmFreeMem((PMemBlock) agp->free); 29499679Siwasaki if (!del_alloc_set(agp->context, AGP_TYPE, agp->free)) 29599679Siwasaki return -EINVAL; 29699679Siwasaki 29799679Siwasaki DRM_DEBUG("free agp, free = 0x%lx\n", agp->free); 29899679Siwasaki 29999679Siwasaki return 0; 30067754Smsmith} 30199679Siwasaki 30267754Smsmithint sis_init_context(struct drm_device *dev, int context) 30367754Smsmith{ 30499679Siwasaki int i; 30599679Siwasaki 30667754Smsmith for (i = 0; i < MAX_CONTEXT; i++) { 30767754Smsmith if (global_ppriv[i].used && 308151937Sjkim (global_ppriv[i].context == context)) 30999679Siwasaki break; 31099679Siwasaki } 31199679Siwasaki 31299679Siwasaki if (i >= MAX_CONTEXT) { 31399679Siwasaki for (i = 0; i < MAX_CONTEXT; i++) { 31499679Siwasaki if (!global_ppriv[i].used) { 31599679Siwasaki global_ppriv[i].context = context; 31699679Siwasaki global_ppriv[i].used = 1; 31799679Siwasaki global_ppriv[i].sets[0] = setInit(); 31899679Siwasaki global_ppriv[i].sets[1] = setInit(); 31999679Siwasaki DRM_DEBUG("init allocation set, socket=%d, " 320151937Sjkim "context = %d\n", i, context); 32167754Smsmith break; 32299679Siwasaki } 32399679Siwasaki } 32499679Siwasaki if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || 32599679Siwasaki (global_ppriv[i].sets[1] == NULL)) { 32699679Siwasaki return 0; 32799679Siwasaki } 32899679Siwasaki } 32999679Siwasaki 33099679Siwasaki return 1; 33167754Smsmith} 33267754Smsmith 333167802Sjkimint sis_final_context(struct drm_device *dev, int context) 33467754Smsmith{ 33567754Smsmith int i; 33699679Siwasaki 33799679Siwasaki for (i = 0; i < MAX_CONTEXT; i++) { 33899679Siwasaki if (global_ppriv[i].used && 33999679Siwasaki (global_ppriv[i].context == context)) 34099679Siwasaki break; 34199679Siwasaki } 34299679Siwasaki 34399679Siwasaki if (i < MAX_CONTEXT) { 34499679Siwasaki set_t *set; 34599679Siwasaki ITEM_TYPE item; 34699679Siwasaki int retval; 34799679Siwasaki 34899679Siwasaki DRM_DEBUG("find socket %d, context = %d\n", i, context); 34999679Siwasaki 35067754Smsmith /* Video Memory */ 35199679Siwasaki set = global_ppriv[i].sets[0]; 35267754Smsmith retval = setFirst(set, &item); 35367754Smsmith while (retval) { 35499679Siwasaki DRM_DEBUG("free video memory 0x%lx\n", item); 35599679Siwasaki#if defined(__linux__) && defined(CONFIG_FB_SIS) 35699679Siwasaki sis_free(item); 35799679Siwasaki#else 35899679Siwasaki mmFreeMem((PMemBlock) item); 35967754Smsmith#endif 36099679Siwasaki retval = setNext(set, &item); 36199679Siwasaki } 362102550Siwasaki setDestroy(set); 36399679Siwasaki 36467754Smsmith /* AGP Memory */ 36567754Smsmith set = global_ppriv[i].sets[1]; 366204773Sjkim retval = setFirst(set, &item); 36799679Siwasaki while (retval) { 36899679Siwasaki DRM_DEBUG("free agp memory 0x%lx\n", item); 36999679Siwasaki mmFreeMem((PMemBlock) item); 37067754Smsmith retval = setNext(set, &item); 37199679Siwasaki } 37299679Siwasaki setDestroy(set); 37399679Siwasaki 37499679Siwasaki global_ppriv[i].used = 0; 37599679Siwasaki } 37699679Siwasaki 37799679Siwasaki return 1; 378102550Siwasaki} 379102550Siwasaki 38099679Siwasakidrm_ioctl_desc_t sis_ioctls[] = { 38199679Siwasaki DRM_IOCTL_DEF(DRM_SIS_FB_ALLOC, sis_fb_alloc, DRM_AUTH), 38267754Smsmith DRM_IOCTL_DEF(DRM_SIS_FB_FREE, sis_fb_free, DRM_AUTH), 38367754Smsmith DRM_IOCTL_DEF(DRM_SIS_AGP_INIT, sis_ioctl_agp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 38499679Siwasaki DRM_IOCTL_DEF(DRM_SIS_AGP_ALLOC, sis_ioctl_agp_alloc, DRM_AUTH), 38567754Smsmith DRM_IOCTL_DEF(DRM_SIS_AGP_FREE, sis_ioctl_agp_free, DRM_AUTH), 386102550Siwasaki DRM_IOCTL_DEF(DRM_SIS_FB_INIT, sis_fb_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY) 387102550Siwasaki}; 38899679Siwasaki 38967754Smsmithint sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls); 39067754Smsmith