diff options
author | Eric Anholt <anholt@freebsd.org> | 2003-08-29 19:24:36 +0000 |
---|---|---|
committer | Eric Anholt <anholt@freebsd.org> | 2003-08-29 19:24:36 +0000 |
commit | fabc64dd573f01a2160be474b4abc65a3a9aa5ea (patch) | |
tree | 03d8b6a2a7a7b3ea0348a320aa4e44841ff6dd51 /shared | |
parent | a7aebb6dac3287374721dd2101a4584f12c63c82 (diff) |
Port the SiS DRM to FreeBSD. This includes the ability for the DRM to
allocate framebuffer memory without sisfb, and a new ioctl to be used
by the X Server which tells the DRM what region of framebuffer memory
to allocate from. Also fixes a possibility to panic the kernel I
believe. Tested on linux with sisfb and FreeBSD (without sisfb) with
new DRI only.
Diffstat (limited to 'shared')
-rw-r--r-- | shared/sis.h | 78 | ||||
-rw-r--r-- | shared/sis_drm.h | 33 | ||||
-rw-r--r-- | shared/sis_drv.h | 47 | ||||
-rw-r--r-- | shared/sis_ds.c | 386 | ||||
-rw-r--r-- | shared/sis_ds.h | 164 | ||||
-rw-r--r-- | shared/sis_mm.c | 403 |
6 files changed, 1111 insertions, 0 deletions
diff --git a/shared/sis.h b/shared/sis.h new file mode 100644 index 00000000..7bdc99c0 --- /dev/null +++ b/shared/sis.h @@ -0,0 +1,78 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.3 2002/10/30 12:52:38 alanh Exp $ */ + +#ifndef __SIS_H__ +#define __SIS_H__ + +/* This remains constant for all DRM template files. + * Name it sisdrv_##x as there's a conflict with sis_free/malloc in the kernel + * that's used for fb devices + */ +#ifdef __linux__ +#define DRM(x) sisdrv_##x +#else +#define DRM(x) sis_##x +#endif + +/* General customization: + */ +#define __HAVE_AGP 1 +#define __MUST_HAVE_AGP 0 +#define __HAVE_MTRR 1 +#define __HAVE_CTX_BITMAP 1 + +#define DRIVER_AUTHOR "SIS" +#define DRIVER_NAME "sis" +#define DRIVER_DESC "SIS 300/630/540" +#define DRIVER_DATE "20030826" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 1 +#define DRIVER_PATCHLEVEL 0 + +#define DRIVER_IOCTLS \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_FB_ALLOC)] = { sis_fb_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_FB_FREE)] = { sis_fb_free, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_INIT)] = { sis_ioctl_agp_init, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_ALLOC)] = { sis_ioctl_agp_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_FREE)] = { sis_ioctl_agp_free, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_FB_INIT)] = { sis_fb_init, 1, 1 } + +#define __HAVE_COUNTERS 5 + +/* Buffer customization: + */ +#define DRIVER_AGP_BUFFERS_MAP( dev ) \ + ((drm_sis_private_t *)((dev)->dev_private))->buffers + +extern int sis_init_context(int context); +extern int sis_final_context(int context); + +#define DRIVER_CTX_CTOR sis_init_context +#define DRIVER_CTX_DTOR sis_final_context + +#endif diff --git a/shared/sis_drm.h b/shared/sis_drm.h new file mode 100644 index 00000000..49505719 --- /dev/null +++ b/shared/sis_drm.h @@ -0,0 +1,33 @@ + +#ifndef __SIS_DRM_H__ +#define __SIS_DRM_H__ + +/* SiS specific ioctls */ +#define DRM_IOCTL_SIS_FB_ALLOC DRM_IOWR(0x44, drm_sis_mem_t) +#define DRM_IOCTL_SIS_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t) +#define DRM_IOCTL_SIS_AGP_INIT DRM_IOWR(0x53, drm_sis_agp_t) +#define DRM_IOCTL_SIS_AGP_ALLOC DRM_IOWR(0x54, drm_sis_mem_t) +#define DRM_IOCTL_SIS_AGP_FREE DRM_IOW( 0x55, drm_sis_mem_t) +#define DRM_IOCTL_SIS_FB_INIT DRM_IOW( 0x56, drm_sis_fb_t) +/* +#define DRM_IOCTL_SIS_FLIP DRM_IOW( 0x48, drm_sis_flip_t) +#define DRM_IOCTL_SIS_FLIP_INIT DRM_IO( 0x49) +#define DRM_IOCTL_SIS_FLIP_FINAL DRM_IO( 0x50) +*/ + +typedef struct { + int context; + unsigned int offset; + unsigned int size; + unsigned long free; +} drm_sis_mem_t; + +typedef struct { + unsigned int offset, size; +} drm_sis_agp_t; + +typedef struct { + unsigned int offset, size; +} drm_sis_fb_t; + +#endif /* __SIS_DRM_H__ */ diff --git a/shared/sis_drv.h b/shared/sis_drv.h new file mode 100644 index 00000000..40e7f463 --- /dev/null +++ b/shared/sis_drv.h @@ -0,0 +1,47 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _SIS_DRV_H_ +#define _SIS_DRV_H_ + +#include "sis_ds.h" + +typedef struct drm_sis_private { + drm_map_t *buffers; + + memHeap_t *AGPHeap; + memHeap_t *FBHeap; +} drm_sis_private_t; + +extern int sis_fb_alloc( DRM_IOCTL_ARGS ); +extern int sis_fb_free( DRM_IOCTL_ARGS ); +extern int sis_ioctl_agp_init( DRM_IOCTL_ARGS ); +extern int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS ); +extern int sis_ioctl_agp_free( DRM_IOCTL_ARGS ); +extern int sis_fb_init( DRM_IOCTL_ARGS ); + +#endif diff --git a/shared/sis_ds.c b/shared/sis_ds.c new file mode 100644 index 00000000..543ce71e --- /dev/null +++ b/shared/sis_ds.c @@ -0,0 +1,386 @@ +/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin <sclin@sis.com.tw> + * + */ + +#include "sis.h" +#include "drmP.h" +#include "drm.h" +#include "sis_ds.h" + +/* Set Data Structure, not check repeated value + * temporarily used + */ + +set_t *setInit(void) +{ + int i; + set_t *set; + + set = (set_t *)DRM(alloc)(sizeof(set_t), DRM_MEM_DRIVER); + if (set != NULL) { + for (i = 0; i < SET_SIZE; i++) { + set->list[i].free_next = i + 1; + set->list[i].alloc_next = -1; + } + set->list[SET_SIZE-1].free_next = -1; + set->free = 0; + set->alloc = -1; + set->trace = -1; + } + return set; +} + +int setAdd(set_t *set, ITEM_TYPE item) +{ + int free = set->free; + + if (free != -1) { + set->list[free].val = item; + set->free = set->list[free].free_next; + } else { + return 0; + } + + set->list[free].alloc_next = set->alloc; + set->alloc = free; + set->list[free].free_next = -1; + + return 1; +} + +int setDel(set_t *set, ITEM_TYPE item) +{ + int alloc = set->alloc; + int prev = -1; + + while (alloc != -1) { + if (set->list[alloc].val == item) { + if (prev != -1) + set->list[prev].alloc_next = + set->list[alloc].alloc_next; + else + set->alloc = set->list[alloc].alloc_next; + break; + } + prev = alloc; + alloc = set->list[alloc].alloc_next; + } + + if (alloc == -1) + return 0; + + set->list[alloc].free_next = set->free; + set->free = alloc; + set->list[alloc].alloc_next = -1; + + return 1; +} + +/* setFirst -> setAdd -> setNext is wrong */ + +int setFirst(set_t *set, ITEM_TYPE *item) +{ + if (set->alloc == -1) + return 0; + + *item = set->list[set->alloc].val; + set->trace = set->list[set->alloc].alloc_next; + + return 1; +} + +int setNext(set_t *set, ITEM_TYPE *item) +{ + if (set->trace == -1) + return 0; + + *item = set->list[set->trace].val; + set->trace = set->list[set->trace].alloc_next; + + return 1; +} + +int setDestroy(set_t *set) +{ + DRM(free)(set, sizeof(set_t), DRM_MEM_DRIVER); + + return 1; +} + +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Keith Whitwell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#define ISFREE(bptr) ((bptr)->free) + +memHeap_t *mmInit(int ofs, + int size) +{ + PMemBlock blocks; + + if (size <= 0) + return 0; + + blocks = (TMemBlock *)DRM(calloc)(1, sizeof(TMemBlock), DRM_MEM_DRIVER); + if (blocks != NULL) { + blocks->ofs = ofs; + blocks->size = size; + blocks->free = 1; + return (memHeap_t *)blocks; + } else + return 0; +} + +/* Checks if a pointer 'b' is part of the heap 'heap' */ +int mmBlockInHeap(memHeap_t *heap, PMemBlock b) +{ + TMemBlock *p; + + if (heap == NULL || b == NULL) + return 0; + + p = heap; + while (p != NULL && p != b) { + p = p->next; + } + if (p == b) + return 1; + else + return 0; +} + +/* Kludgey workaround for existing i810 server. Remove soon. + */ +memHeap_t *mmAddRange( memHeap_t *heap, + int ofs, + int size ) +{ + PMemBlock blocks; + blocks = (TMemBlock *)DRM(calloc)(2, sizeof(TMemBlock), DRM_MEM_DRIVER); + if (blocks != NULL) { + blocks[0].size = size; + blocks[0].free = 1; + blocks[0].ofs = ofs; + blocks[0].next = &blocks[1]; + + /* Discontinuity - stops JoinBlock from trying to join + * non-adjacent ranges. + */ + blocks[1].size = 0; + blocks[1].free = 0; + blocks[1].ofs = ofs+size; + blocks[1].next = (PMemBlock)heap; + return (memHeap_t *)blocks; + } else + return heap; +} + +static TMemBlock* SliceBlock(TMemBlock *p, + int startofs, int size, + int reserved, int alignment) +{ + TMemBlock *newblock; + + /* break left */ + if (startofs > p->ofs) { + newblock = (TMemBlock*) DRM(calloc)(1, sizeof(TMemBlock), + DRM_MEM_DRIVER); + newblock->ofs = startofs; + newblock->size = p->size - (startofs - p->ofs); + newblock->free = 1; + newblock->next = p->next; + p->size -= newblock->size; + p->next = newblock; + p = newblock; + } + + /* break right */ + if (size < p->size) { + newblock = (TMemBlock*) DRM(calloc)(1, sizeof(TMemBlock), + DRM_MEM_DRIVER); + newblock->ofs = startofs + size; + newblock->size = p->size - size; + newblock->free = 1; + newblock->next = p->next; + p->size = size; + p->next = newblock; + } + + /* p = middle block */ + p->align = alignment; + p->free = 0; + p->reserved = reserved; + return p; +} + +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch) +{ + int mask,startofs, endofs; + TMemBlock *p; + + if (heap == NULL || align2 < 0 || size <= 0) + return NULL; + + mask = (1 << align2)-1; + startofs = 0; + p = (TMemBlock *)heap; + while (p != NULL) { + if (ISFREE(p)) { + startofs = (p->ofs + mask) & ~mask; + if ( startofs < startSearch ) { + startofs = startSearch; + } + endofs = startofs+size; + if (endofs <= (p->ofs+p->size)) + break; + } + p = p->next; + } + if (p == NULL) + return NULL; + p = SliceBlock(p,startofs,size,0,mask+1); + p->heap = heap; + return p; +} + +static __inline__ int Join2Blocks(TMemBlock *p) +{ + if (p->free && p->next && p->next->free) { + TMemBlock *q = p->next; + p->size += q->size; + p->next = q->next; + DRM(free)(q, sizeof(TMemBlock), DRM_MEM_DRIVER); + return 1; + } + return 0; +} + +int mmFreeMem(PMemBlock b) +{ + TMemBlock *p, *prev; + + if (b == NULL) + return 0; + if (b->heap == NULL) + return -1; + + p = b->heap; + prev = NULL; + while (p != NULL && p != b) { + prev = p; + p = p->next; + } + if (p == NULL || p->free || p->reserved) + return -1; + + p->free = 1; + Join2Blocks(p); + if (prev) + Join2Blocks(prev); + return 0; +} + +int mmReserveMem(memHeap_t *heap, int offset,int size) +{ + int endofs; + TMemBlock *p; + + if (heap == NULL || size <= 0) + return -1; + + endofs = offset + size; + p = (TMemBlock *)heap; + while (p && p->ofs <= offset) { + if (ISFREE(p) && endofs <= (p->ofs+p->size)) { + SliceBlock(p,offset,size,1,1); + return 0; + } + p = p->next; + } + return -1; +} + +int mmFreeReserved(memHeap_t *heap, int offset) +{ + TMemBlock *p,*prev; + + if (heap == NULL) + return -1; + + p = (TMemBlock *)heap; + prev = NULL; + while (p != NULL && p->ofs != offset) { + prev = p; + p = p->next; + } + if (p == NULL || !p->reserved) + return -1; + + p->free = 1; + p->reserved = 0; + Join2Blocks(p); + if (prev != NULL) + Join2Blocks(prev); + return 0; +} + +void mmDestroy(memHeap_t *heap) +{ + TMemBlock *p,*q; + + if (heap == NULL) + return; + + p = (TMemBlock *)heap; + while (p != NULL) { + q = p->next; + DRM(free)(p, sizeof(TMemBlock), DRM_MEM_DRIVER); + p = q; + } +} diff --git a/shared/sis_ds.h b/shared/sis_ds.h new file mode 100644 index 00000000..482693fe --- /dev/null +++ b/shared/sis_ds.h @@ -0,0 +1,164 @@ +/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin <sclin@sis.com.tw> + * + */ + +#ifndef __SIS_DS_H__ +#define __SIS_DS_H__ + +/* Set Data Structure */ + +#define SET_SIZE 5000 + +typedef unsigned int ITEM_TYPE; + +typedef struct { + ITEM_TYPE val; + int alloc_next, free_next; +} list_item_t; + +typedef struct { + int alloc; + int free; + int trace; + list_item_t list[SET_SIZE]; +} set_t; + +set_t *setInit(void); +int setAdd(set_t *set, ITEM_TYPE item); +int setDel(set_t *set, ITEM_TYPE item); +int setFirst(set_t *set, ITEM_TYPE *item); +int setNext(set_t *set, ITEM_TYPE *item); +int setDestroy(set_t *set); + +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Keith Whitwell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +struct mem_block_t { + struct mem_block_t *next; + struct mem_block_t *heap; + int ofs,size; + int align; + int free:1; + int reserved:1; +}; +typedef struct mem_block_t TMemBlock; +typedef struct mem_block_t *PMemBlock; + +/* a heap is just the first block in a chain */ +typedef struct mem_block_t memHeap_t; + +static __inline__ int mmBlockSize(PMemBlock b) +{ + return b->size; +} + +static __inline__ int mmOffset(PMemBlock b) +{ + return b->ofs; +} + +static __inline__ void mmMarkReserved(PMemBlock b) +{ + b->reserved = 1; +} + +/* + * input: total size in bytes + * return: a heap pointer if OK, NULL if error + */ +memHeap_t *mmInit( int ofs, int size ); + +memHeap_t *mmAddRange( memHeap_t *heap, + int ofs, + int size ); + +/* + * Allocate 'size' bytes with 2^align2 bytes alignment, + * restrict the search to free memory after 'startSearch' + * depth and back buffers should be in different 4mb banks + * to get better page hits if possible + * input: size = size of block + * align2 = 2^align2 bytes alignment + * startSearch = linear offset from start of heap to begin search + * return: pointer to the allocated block, 0 if error + */ +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch ); + +/* + * Returns 1 if the block 'b' is part of the heap 'heap' + */ +int mmBlockInHeap( PMemBlock heap, PMemBlock b ); + +/* + * Free block starts at offset + * input: pointer to a block + * return: 0 if OK, -1 if error + */ +int mmFreeMem( PMemBlock b ); + +/* + * Reserve 'size' bytes block start at offset + * This is used to prevent allocation of memory already used + * by the X server for the front buffer, pixmaps, and cursor + * input: size, offset + * output: 0 if OK, -1 if error + */ +int mmReserveMem( memHeap_t *heap, int offset,int size ); +int mmFreeReserved( memHeap_t *heap, int offset ); + +/* + * destroy MM + */ +void mmDestroy( memHeap_t *mmInit ); + +/* For debuging purpose. */ +void mmDumpMemInfo( memHeap_t *mmInit ); + +#endif /* __SIS_DS_H__ */ diff --git a/shared/sis_mm.c b/shared/sis_mm.c new file mode 100644 index 00000000..46cc0efa --- /dev/null +++ b/shared/sis_mm.c @@ -0,0 +1,403 @@ +/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*- + * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw + * + * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Sung-Ching Lin <sclin@sis.com.tw> + * + */ + +#include "sis.h" +#include "drmP.h" +#include "sis_drm.h" +#include "sis_drv.h" +#include "sis_ds.h" +#if defined(__linux__) && defined(CONFIG_FB_SIS) +#include <linux/sisfb.h> +#endif + +#define MAX_CONTEXT 100 +#define VIDEO_TYPE 0 +#define AGP_TYPE 1 + +typedef struct { + int used; + int context; + set_t *sets[2]; /* 0 for video, 1 for AGP */ +} sis_context_t; + +static sis_context_t global_ppriv[MAX_CONTEXT]; + + +static int add_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + + for (i = 0; i < MAX_CONTEXT; i++) { + if (global_ppriv[i].used && global_ppriv[i].context == context) + { + retval = setAdd(global_ppriv[i].sets[type], val); + break; + } + } + return retval; +} + +static int del_alloc_set(int context, int type, unsigned int val) +{ + int i, retval = 0; + + for (i = 0; i < MAX_CONTEXT; i++) { + if (global_ppriv[i].used && global_ppriv[i].context == context) + { + retval = setDel(global_ppriv[i].sets[type], val); + break; + } + } + return retval; +} + +/* fb management via fb device */ +#if defined(__linux__) && defined(CONFIG_FB_SIS) + +int sis_fb_init( DRM_IOCTL_ARGS ) +{ + return 0; +} + +int sis_fb_alloc( DRM_IOCTL_ARGS ) +{ + drm_sis_mem_t fb; + struct sis_memreq req; + int retval = 0; + + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + + req.size = fb.size; + sis_malloc(&req); + if (req.offset) { + /* TODO */ + fb.offset = req.offset; + fb.free = req.offset; + if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) { + DRM_DEBUG("adding to allocation set fails\n"); + sis_free(req.offset); + retval = DRM_ERR(EINVAL); + } + } else { + fb.offset = 0; + fb.size = 0; + fb.free = 0; + } + + DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb)); + + DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset); + + return retval; +} + +int sis_fb_free( DRM_IOCTL_ARGS ) +{ + drm_sis_mem_t fb; + int retval = 0; + + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + + if (!fb.free) + return DRM_ERR(EINVAL); + + if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) + retval = DRM_ERR(EINVAL); + sis_free(fb.free); + + DRM_DEBUG("free fb, offset = %d\n", fb.free); + + return retval; +} + +#else + +/* Called by the X Server to initialize the FB heap. Allocations will fail + * unless this is called. Offset is the beginning of the heap from the + * framebuffer offset (MaxXFBMem in XFree86). + * + * Memory layout according to Thomas Winischofer: + * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC| + * + * X driver/sisfb HW- Command- + * framebuffer memory DRI heap Cursor queue + */ +int sis_fb_init( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_fb_t fb; + + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t *)data, sizeof(fb)); + + if (dev_priv == NULL) { + dev->dev_private = DRM(calloc)(1, sizeof(drm_sis_private_t), + DRM_MEM_DRIVER); + dev_priv = dev->dev_private; + if (dev_priv == NULL) + return ENOMEM; + } + + if (dev_priv->FBHeap != NULL) + return DRM_ERR(EINVAL); + + dev_priv->FBHeap = mmInit(fb.offset, fb.size); + + DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size); + + return 0; +} + +int sis_fb_alloc( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_mem_t fb; + PMemBlock block; + int retval = 0; + + if (dev_priv == NULL || dev_priv->FBHeap == NULL) + return DRM_ERR(EINVAL); + + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + + block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0); + if (block) { + /* TODO */ + fb.offset = block->ofs; + fb.free = (unsigned long)block; + if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) { + DRM_DEBUG("adding to allocation set fails\n"); + mmFreeMem((PMemBlock)fb.free); + retval = DRM_ERR(EINVAL); + } + } else { + fb.offset = 0; + fb.size = 0; + fb.free = 0; + } + + DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb)); + + DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset); + + return retval; +} + +int sis_fb_free( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_mem_t fb; + + if (dev_priv == NULL || dev_priv->FBHeap == NULL) + return DRM_ERR(EINVAL); + + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + + if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock)fb.free)) + return DRM_ERR(EINVAL); + + if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) + return DRM_ERR(EINVAL); + mmFreeMem((PMemBlock)fb.free); + + DRM_DEBUG("free fb, free = %d\n", fb.free); + + return 0; +} + +#endif + +/* agp memory management */ + +int sis_ioctl_agp_init( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_agp_t agp; + + if (dev_priv == NULL) { + dev->dev_private = DRM(calloc)(1, sizeof(drm_sis_private_t), + DRM_MEM_DRIVER); + dev_priv = dev->dev_private; + if (dev_priv == NULL) + return ENOMEM; + } + + if (dev_priv->AGPHeap != NULL) + return DRM_ERR(EINVAL); + + DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t *)data, sizeof(agp)); + + dev_priv->AGPHeap = mmInit(agp.offset, agp.size); + + DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); + + return 0; +} + +int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_mem_t agp; + PMemBlock block; + int retval = 0; + + if (dev_priv == NULL || dev_priv->AGPHeap == NULL) + return DRM_ERR(EINVAL); + + DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t *)data, sizeof(agp)); + + block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0); + if (block) { + /* TODO */ + agp.offset = block->ofs; + agp.free = (unsigned long)block; + if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) { + DRM_DEBUG("adding to allocation set fails\n"); + mmFreeMem((PMemBlock)agp.free); + retval = -1; + } + } else { + agp.offset = 0; + agp.size = 0; + agp.free = 0; + } + + DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, agp, sizeof(agp)); + + DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset); + + return retval; +} + +int sis_ioctl_agp_free( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_mem_t agp; + + if (dev_priv == NULL || dev_priv->AGPHeap == NULL) + return DRM_ERR(EINVAL); + + DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t *)data, sizeof(agp)); + + if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock)agp.free)) + return DRM_ERR(EINVAL); + + mmFreeMem((PMemBlock)agp.free); + if (!del_alloc_set(agp.context, AGP_TYPE, agp.free)) + return DRM_ERR(EINVAL); + + DRM_DEBUG("free agp, free = %d\n", agp.free); + + return 0; +} + +int sis_init_context(int context) +{ + int i; + + for (i = 0; i < MAX_CONTEXT ; i++) { + if (global_ppriv[i].used && + (global_ppriv[i].context == context)) + break; + } + + if (i >= MAX_CONTEXT) { + for (i = 0; i < MAX_CONTEXT ; i++) { + if (!global_ppriv[i].used) { + global_ppriv[i].context = context; + global_ppriv[i].used = 1; + global_ppriv[i].sets[0] = setInit(); + global_ppriv[i].sets[1] = setInit(); + DRM_DEBUG("init allocation set, socket=%d, " + "context = %d\n", i, context); + break; + } + } + if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || + (global_ppriv[i].sets[1] == NULL)) + { + return 0; + } + } + + return 1; +} + +int sis_final_context(int context) +{ + int i; + + for (i=0; i<MAX_CONTEXT; i++) { + if (global_ppriv[i].used && + (global_ppriv[i].context == context)) + break; + } + + if (i < MAX_CONTEXT) { + set_t *set; + unsigned int item; + int retval; + + DRM_DEBUG("find socket %d, context = %d\n", i, context); + + /* Video Memory */ + set = global_ppriv[i].sets[0]; + retval = setFirst(set, &item); + while (retval) { + DRM_DEBUG("free video memory 0x%x\n", item); +#if defined(__linux__) && defined(CONFIG_FB_SIS) + sis_free(item); +#else + mmFreeMem((PMemBlock)item); +#endif + retval = setNext(set, &item); + } + setDestroy(set); + + /* AGP Memory */ + set = global_ppriv[i].sets[1]; + retval = setFirst(set, &item); + while (retval) { + DRM_DEBUG("free agp memory 0x%x\n", item); + mmFreeMem((PMemBlock)item); + retval = setNext(set, &item); + } + setDestroy(set); + + global_ppriv[i].used = 0; + } + + return 1; +} |