diff options
author | Kevin E Martin <kem@kem.org> | 2001-03-14 22:22:50 +0000 |
---|---|---|
committer | Kevin E Martin <kem@kem.org> | 2001-03-14 22:22:50 +0000 |
commit | 74e19a40187ac3b5907922e5dc01418135a5794b (patch) | |
tree | 6623cfe435730e28c25829ebc6931e46871b81ce /linux-core | |
parent | e2b2bffc6b25361b2f09afc5a28030645440cd03 (diff) |
Merged sarea-1-0-0sarea-1-0-0-20010314-mergefull-1-0-0-20010315-head
Diffstat (limited to 'linux-core')
-rw-r--r-- | linux-core/drmP.h | 52 | ||||
-rw-r--r-- | linux-core/drm_bufs.c | 118 | ||||
-rw-r--r-- | linux-core/drm_context.c | 112 | ||||
-rw-r--r-- | linux-core/drm_drv.c | 130 | ||||
-rw-r--r-- | linux-core/drm_ioctl.c | 30 | ||||
-rw-r--r-- | linux-core/drm_proc.c | 11 | ||||
-rw-r--r-- | linux-core/drm_vm.c | 154 | ||||
-rw-r--r-- | linux-core/i810_dma.c | 26 | ||||
-rw-r--r-- | linux-core/i810_drm.h | 4 | ||||
-rw-r--r-- | linux-core/i810_drv.h | 10 |
10 files changed, 471 insertions, 176 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4032689a2..a7e4d5732 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -73,6 +73,7 @@ #if LINUX_VERSION_CODE < 0x020400 #include "compat-pre24.h" #endif +#include <asm/pgalloc.h> #include "drm.h" /* DRM template customization defaults @@ -329,16 +330,19 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, DRM(ioremapfree)( (map)->handle, (map)->size ); \ } while (0) -#define DRM_FIND_MAP(map, o) \ - do { \ - int i; \ - for ( i = 0 ; i < dev->map_count ; i++ ) { \ - if ( dev->maplist[i]->offset == o ) { \ - map = dev->maplist[i]; \ - break; \ - } \ - } \ - } while (0) +#define DRM_FIND_MAP(_map, _o) \ +do { \ + struct list_head *_list; \ + list_for_each(_list, &dev->maplist->head) { \ + drm_map_list_t *_r_list; \ + _r_list = (drm_map_list_t *)_list; \ + if(_r_list->map && \ + _r_list->map->offset == (_o)) { \ + (_map) = _r_list->map; \ + break; \ + } \ + } \ +} while(0) /* Internal types and structures */ #define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) @@ -349,6 +353,10 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, #define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) #define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist) +#define DRM_GET_PRIV_SAREA(_dev, _ctx, _map) do { \ + (_map) = (_dev)->context_sareas[_ctx]; \ +} while(0) + typedef int drm_ioctl_t( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); @@ -577,6 +585,11 @@ typedef struct drm_sigdata { drm_hw_lock_t *lock; } drm_sigdata_t; +typedef struct drm_map_list { + struct list_head head; + drm_map_t *map; +} drm_map_list_t; + typedef struct drm_device { const char *name; /* Simple driver name */ char *unique; /* Unique identifier: e.g., busid */ @@ -609,9 +622,12 @@ typedef struct drm_device { drm_magic_head_t magiclist[DRM_HASH_SIZE]; /* Memory management */ - drm_map_t **maplist; /* Vector of pointers to regions */ + drm_map_list_t *maplist; /* Linked list of regions */ int map_count; /* Number of mappable regions */ + drm_map_t **context_sareas; + int max_context; + drm_vma_entry_t *vmalist; /* List of vmas (for debugging) */ drm_lock_data_t lock; /* Information on hardware lock */ @@ -700,9 +716,6 @@ extern unsigned long DRM(vm_nopage)(struct vm_area_struct *vma, extern unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma, unsigned long address, int write_access); -extern unsigned long DRM(vm_shm_nopage_lock)(struct vm_area_struct *vma, - unsigned long address, - int write_access); extern unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma, unsigned long address, int write_access); @@ -714,15 +727,13 @@ extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma, extern struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, unsigned long address, int write_access); -extern struct page *DRM(vm_shm_nopage_lock)(struct vm_area_struct *vma, - unsigned long address, - int write_access); extern struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, unsigned long address, int write_access); #endif extern void DRM(vm_open)(struct vm_area_struct *vma); extern void DRM(vm_close)(struct vm_area_struct *vma); +extern void DRM(vm_shm_close)(struct vm_area_struct *vma); extern int DRM(mmap_dma)(struct file *filp, struct vm_area_struct *vma); extern int DRM(mmap)(struct file *filp, struct vm_area_struct *vma); @@ -788,6 +799,11 @@ extern int DRM(ctxbitmap_init)( drm_device_t *dev ); extern void DRM(ctxbitmap_cleanup)( drm_device_t *dev ); #endif +extern int DRM(setsareactx)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int DRM(getsareactx)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); + /* Drawable IOCTL support (drm_drawable.h) */ extern int DRM(adddraw)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); @@ -830,6 +846,8 @@ extern int DRM(notifier)(void *priv); extern int DRM(order)( unsigned long size ); extern int DRM(addmap)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); +extern int DRM(rmmap)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); #if __HAVE_DMA extern int DRM(addbufs)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index b7e27d172..1d5403225 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -69,6 +69,7 @@ int DRM(addmap)( struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_map_t *map; + drm_map_list_t *list; if ( !(filp->f_mode & 3) ) return -EACCES; /* Require read/write */ @@ -81,6 +82,14 @@ int DRM(addmap)( struct inode *inode, struct file *filp, return -EFAULT; } + /* Only allow shared memory to be removable since we only keep enough + * book keeping information about shared memory to allow for removal + * when processes fork. + */ + if ( (map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM ) { + DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); + return -EINVAL; + } DRM_DEBUG( "offset = 0x%08lx, size = 0x%08lx, type = %d\n", map->offset, map->size, map->type ); if ( (map->offset & (~PAGE_MASK)) || (map->size & (~PAGE_MASK)) ) { @@ -100,7 +109,7 @@ int DRM(addmap)( struct inode *inode, struct file *filp, return -EINVAL; } #endif -#ifdef CONFIG_MTRR +#ifdef __REALLY_HAVE_MTRR if ( map->type == _DRM_FRAME_BUFFER || (map->flags & _DRM_WRITE_COMBINING) ) { map->mtrr = mtrr_add( map->offset, map->size, @@ -111,9 +120,7 @@ int DRM(addmap)( struct inode *inode, struct file *filp, break; case _DRM_SHM: - map->handle = (void *)DRM(alloc_pages)( DRM(order)( map->size ) - - PAGE_SHIFT, - DRM_MEM_SAREA ); + map->handle = vmalloc_32(map->size); DRM_DEBUG( "%ld %d %p\n", map->size, DRM(order)( map->size ), map->handle ); if ( !map->handle ) { @@ -136,22 +143,17 @@ int DRM(addmap)( struct inode *inode, struct file *filp, return -EINVAL; } - down( &dev->struct_sem ); - if ( dev->maplist ) { - ++dev->map_count; - dev->maplist = DRM(realloc)( dev->maplist, - (dev->map_count-1) - * sizeof(*dev->maplist), - dev->map_count - * sizeof(*dev->maplist), - DRM_MEM_MAPS ); - } else { - dev->map_count = 1; - dev->maplist = DRM(alloc)( dev->map_count*sizeof(*dev->maplist), - DRM_MEM_MAPS ); + list = DRM(alloc)(sizeof(*list), DRM_MEM_MAPS); + if(!list) { + DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; } - dev->maplist[dev->map_count-1] = map; - up( &dev->struct_sem ); + memset(list, 0, sizeof(*list)); + list->map = map; + + down(&dev->struct_sem); + list_add(&list->head, &dev->maplist->head); + up(&dev->struct_sem); if ( copy_to_user( (drm_map_t *)arg, map, sizeof(*map) ) ) return -EFAULT; @@ -164,6 +166,84 @@ int DRM(addmap)( struct inode *inode, struct file *filp, return 0; } + +/* Remove a map private from list and deallocate resources if the mapping + * isn't in use. + */ + +int DRM(rmmap)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + struct list_head *list; + drm_map_list_t *r_list; + drm_vma_entry_t *pt, *prev; + drm_map_t *map; + drm_map_t request; + int found_maps = 0; + + if (copy_from_user(&request, (drm_map_t *)arg, + sizeof(request))) { + return -EFAULT; + } + + down(&dev->struct_sem); + list = &dev->maplist->head; + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *) list; + + if(r_list->map && + r_list->map->handle == request.handle && + r_list->map->flags & _DRM_REMOVABLE) break; + } + + /* List has wrapped around to the head pointer, or its empty we didn't + * find anything. + */ + if(list == (&dev->maplist->head)) { + up(&dev->struct_sem); + return -EINVAL; + } + map = r_list->map; + list_del(list); + DRM(free)(list, sizeof(*list), DRM_MEM_MAPS); + + for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) { +#if LINUX_VERSION_CODE >= 0x020300 + if (pt->vma->vm_private_data == map) found_maps++; +#else + if (pt->vma->vm_pte == map) found_maps++; +#endif + } + + if(!found_maps) { + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: +#ifdef __REALLY_HAVE_MTRR + if (map->mtrr >= 0) { + int retcode; + retcode = mtrr_del(map->mtrr, + map->offset, + map->size); + DRM_DEBUG("mtrr_del = %d\n", retcode); + } +#endif + DRM(ioremapfree)(map->handle, map->size); + break; + case _DRM_SHM: + vfree(map->handle); + break; + case _DRM_AGP: + break; + } + DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + } + up(&dev->struct_sem); + return 0; +} + #if __HAVE_DMA #if __REALLY_HAVE_AGP diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c index e2b6170a8..4ac896ef5 100644 --- a/linux-core/drm_context.c +++ b/linux-core/drm_context.c @@ -41,9 +41,13 @@ void DRM(ctxbitmap_free)( drm_device_t *dev, int ctx_handle ) { if ( ctx_handle < 0 ) goto failed; + if ( !dev->ctx_bitmap ) goto failed; if ( ctx_handle < DRM_MAX_CTXBITMAP ) { + down(&dev->struct_sem); clear_bit( ctx_handle, dev->ctx_bitmap ); + dev->context_sareas[ctx_handle] = NULL; + up(&dev->struct_sem); return; } failed: @@ -56,12 +60,37 @@ int DRM(ctxbitmap_next)( drm_device_t *dev ) { int bit; + if(!dev->ctx_bitmap) return -1; + + down(&dev->struct_sem); bit = find_first_zero_bit( dev->ctx_bitmap, DRM_MAX_CTXBITMAP ); if ( bit < DRM_MAX_CTXBITMAP ) { set_bit( bit, dev->ctx_bitmap ); DRM_DEBUG( "drm_ctxbitmap_next bit : %d\n", bit ); + if((bit+1) > dev->max_context) { + dev->max_context = (bit+1); + if(dev->context_sareas) { + dev->context_sareas = DRM(realloc)( + dev->context_sareas, + (dev->max_context - 1) * + sizeof(*dev->context_sareas), + dev->max_context * + sizeof(*dev->context_sareas), + DRM_MEM_MAPS); + dev->context_sareas[bit] = NULL; + } else { + /* max_context == 1 at this point */ + dev->context_sareas = DRM(alloc)( + dev->max_context * + sizeof(*dev->context_sareas), + DRM_MEM_MAPS); + dev->context_sareas[bit] = NULL; + } + } + up(&dev->struct_sem); return bit; } + up(&dev->struct_sem); return -1; } @@ -70,12 +99,18 @@ int DRM(ctxbitmap_init)( drm_device_t *dev ) int i; int temp; + down(&dev->struct_sem); dev->ctx_bitmap = (unsigned long *) DRM(alloc)( PAGE_SIZE, DRM_MEM_CTXBITMAP ); if ( dev->ctx_bitmap == NULL ) { + up(&dev->struct_sem); return -ENOMEM; } memset( (void *)dev->ctx_bitmap, 0, PAGE_SIZE ); + dev->context_sareas = NULL; + dev->max_context = -1; + up(&dev->struct_sem); + for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) { temp = DRM(ctxbitmap_next)( dev ); DRM_DEBUG( "drm_ctxbitmap_init : %d\n", temp ); @@ -86,9 +121,86 @@ int DRM(ctxbitmap_init)( drm_device_t *dev ) void DRM(ctxbitmap_cleanup)( drm_device_t *dev ) { + down(&dev->struct_sem); + if( dev->context_sareas ) DRM(free)( dev->context_sareas, + sizeof(*dev->context_sareas) * + dev->max_context, + DRM_MEM_MAPS ); DRM(free)( (void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP ); + up(&dev->struct_sem); +} + +/* ================================================================ + * Per Context SAREA Support + */ + +int DRM(getsareactx)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_priv_map_t request; + drm_map_t *map; + + if (copy_from_user(&request, + (drm_ctx_priv_map_t *)arg, + sizeof(request))) + return -EFAULT; + + down(&dev->struct_sem); + if ((int)request.ctx_id >= dev->max_context) { + up(&dev->struct_sem); + return -EINVAL; + } + + map = dev->context_sareas[request.ctx_id]; + up(&dev->struct_sem); + + request.handle = map->handle; + if (copy_to_user((drm_ctx_priv_map_t *)arg, &request, sizeof(request))) + return -EFAULT; + return 0; } +int DRM(setsareactx)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_priv_map_t request; + drm_map_t *map = NULL; + drm_map_list_t *r_list; + struct list_head *list; + + if (copy_from_user(&request, + (drm_ctx_priv_map_t *)arg, + sizeof(request))) + return -EFAULT; + + down(&dev->struct_sem); + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *)list; + if(r_list->map && + r_list->map->handle == request.handle) break; + } + if (list == &(dev->maplist->head)) { + up(&dev->struct_sem); + return -EINVAL; + } + map = r_list->map; + up(&dev->struct_sem); + + if (!map) return -EINVAL; + + down(&dev->struct_sem); + if ((int)request.ctx_id >= dev->max_context) { + up(&dev->struct_sem); + return -EINVAL; + } + dev->context_sareas[request.ctx_id] = map; + up(&dev->struct_sem); + return 0; +} /* ================================================================ * The actual DRM context handling routines diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index c19b63983..7447ca6d4 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -118,60 +118,64 @@ static struct file_operations DRM(fops) = { }; -static drm_ioctl_desc_t DRM(ioctls)[] = { - [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 }, - - [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { DRM(setunique), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { DRM(block), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { DRM(unblock), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { DRM(authmagic), 1, 1 }, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { DRM(addmap), 1, 1 }, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { DRM(addctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { DRM(rmctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { DRM(modctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { DRM(getctx), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { DRM(switchctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { DRM(newctx), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { DRM(resctx), 1, 0 }, - - [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { DRM(adddraw), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { DRM(rmdraw), 1, 1 }, - - [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { DRM(lock), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { DRM(unlock), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(finish), 1, 0 }, +static drm_ioctl_desc_t DRM(ioctls)[] = { + [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { DRM(getmagic), 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { DRM(irq_busid), 0, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP)] = { DRM(getmap), 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT)] = { DRM(getclient), 0, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { DRM(setunique), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { DRM(block), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { DRM(unblock), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { DRM(authmagic), 1, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { DRM(addmap), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP)] = { DRM(rmmap), 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = { DRM(setsareactx), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = { DRM(getsareactx), 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { DRM(addctx), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { DRM(rmctx), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { DRM(modctx), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { DRM(getctx), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { DRM(switchctx), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { DRM(newctx), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { DRM(resctx), 1, 0 }, + + [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { DRM(adddraw), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { DRM(rmdraw), 1, 1 }, + + [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { DRM(lock), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { DRM(unlock), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(finish), 1, 0 }, #if __HAVE_DMA - [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(addbufs), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { DRM(markbufs), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { DRM(infobufs), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { DRM(mapbufs), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(addbufs), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)] = { DRM(markbufs), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { DRM(infobufs), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { DRM(mapbufs), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { DRM(freebufs), 1, 0 }, /* The DRM_IOCTL_DMA ioctl should be defined by the driver. */ #if __HAVE_DMA_IRQ - [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { DRM(control), 1, 1 }, #endif #endif #if __REALLY_HAVE_AGP - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { DRM(agp_info), 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { DRM(agp_alloc), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { DRM(agp_free), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { DRM(agp_bind), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ACQUIRE)] = { DRM(agp_acquire), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_RELEASE)] = { DRM(agp_release), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE)] = { DRM(agp_enable), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO)] = { DRM(agp_info), 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC)] = { DRM(agp_alloc), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE)] = { DRM(agp_free), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND)] = { DRM(agp_bind), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 }, #endif DRIVER_IOCTLS @@ -262,8 +266,14 @@ static int DRM(setup)( drm_device_t *dev ) dev->magiclist[i].head = NULL; dev->magiclist[i].tail = NULL; } - dev->maplist = NULL; + + dev->maplist = DRM(alloc)(sizeof(*dev->maplist), + DRM_MEM_MAPS); + if(dev->maplist == NULL) return -ENOMEM; + memset(dev->maplist, 0, sizeof(*dev->maplist)); + INIT_LIST_HEAD(&dev->maplist->head); dev->map_count = 0; + dev->vmalist = NULL; dev->lock.hw_lock = NULL; init_waitqueue_head( &dev->lock.lock_queue ); @@ -307,6 +317,8 @@ static int DRM(takedown)( drm_device_t *dev ) { drm_magic_entry_t *pt, *next; drm_map_t *map; + drm_map_list_t *r_list; + struct list_head *list; drm_vma_entry_t *vma, *vma_next; int i; @@ -373,10 +385,13 @@ static int DRM(takedown)( drm_device_t *dev ) dev->vmalist = NULL; } - /* Clear map area and mtrr information */ - if ( dev->maplist ) { - for ( i = 0 ; i < dev->map_count ; i++ ) { - map = dev->maplist[i]; + if( dev->maplist ) { + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *)list; + map = r_list->map; + DRM(free)(r_list, sizeof(*r_list), DRM_MEM_MAPS); + if(!map) continue; + switch ( map->type ) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: @@ -392,25 +407,20 @@ static int DRM(takedown)( drm_device_t *dev ) DRM(ioremapfree)( map->handle, map->size ); break; case _DRM_SHM: - DRM(free_pages)( (unsigned long)map->handle, - DRM(order)( map->size ) - - PAGE_SHIFT, - DRM_MEM_SAREA ); + vfree(map->handle); break; + case _DRM_AGP: /* Do nothing here, because this is all * handled in the AGP/GART driver. */ break; } - DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); - } - DRM(free)( dev->maplist, - dev->map_count * sizeof(*dev->maplist), - DRM_MEM_MAPS ); + DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + } + DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); dev->maplist = NULL; - dev->map_count = 0; - } + } #if __HAVE_DMA_QUEUE || __HAVE_MULTIPLE_DMA_QUEUES if ( dev->queuelist ) { diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c index ce6ac2e68..2fba6b0c2 100644 --- a/linux-core/drm_ioctl.c +++ b/linux-core/drm_ioctl.c @@ -105,22 +105,40 @@ int DRM(getmap)( struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_map_t map; + drm_map_list_t *r_list = NULL; + struct list_head *list; int idx; + int i; if (copy_from_user(&map, (drm_map_t *)arg, sizeof(map))) return -EFAULT; idx = map.offset; + down(&dev->struct_sem); if (idx < 0 || idx >= dev->map_count) { up(&dev->struct_sem); return -EINVAL; } - map.offset = dev->maplist[idx]->offset; - map.size = dev->maplist[idx]->size; - map.type = dev->maplist[idx]->type; - map.flags = dev->maplist[idx]->flags; - map.handle = dev->maplist[idx]->handle; - map.mtrr = dev->maplist[idx]->mtrr; + + i = 0; + list_for_each(list, &dev->maplist->head) { + if(i == idx) { + r_list = (drm_map_list_t *)list; + break; + } + i++; + } + if(!r_list || !r_list->map) { + up(&dev->struct_sem); + return -EINVAL; + } + + map.offset = r_list->map->offset; + map.size = r_list->map->size; + map.type = r_list->map->type; + map.flags = r_list->map->flags; + map.handle = r_list->map->handle; + map.mtrr = r_list->map->mtrr; up(&dev->struct_sem); if (copy_to_user((drm_map_t *)arg, &map, sizeof(map))) return -EFAULT; diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index ee9c0cbc8..f65f42b71 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -165,6 +165,9 @@ static int DRM(_vm_info)(char *buf, char **start, off_t offset, int request, drm_device_t *dev = (drm_device_t *)data; int len = 0; drm_map_t *map; + drm_map_list_t *r_list; + struct list_head *list; + /* Hardcoded from _DRM_FRAME_BUFFER, _DRM_REGISTERS, _DRM_SHM, and _DRM_AGP. */ @@ -182,8 +185,11 @@ static int DRM(_vm_info)(char *buf, char **start, off_t offset, int request, DRM_PROC_PRINT("slot offset size type flags " "address mtrr\n\n"); - for (i = 0; i < dev->map_count; i++) { - map = dev->maplist[i]; + i = 0; + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *)list; + map = r_list->map; + if(!map) continue; if (map->type < 0 || map->type > 3) type = "??"; else type = types[map->type]; DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", @@ -198,6 +204,7 @@ static int DRM(_vm_info)(char *buf, char **start, off_t offset, int request, } else { DRM_PROC_PRINT("%4d\n", map->mtrr); } + i++; } if (len > request + offset) return request; diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 347816ac3..123eea299 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -41,13 +41,7 @@ struct vm_operations_struct drm_vm_ops = { struct vm_operations_struct drm_vm_shm_ops = { nopage: DRM(vm_shm_nopage), open: DRM(vm_open), - close: DRM(vm_close), -}; - -struct vm_operations_struct drm_vm_shm_lock_ops = { - nopage: DRM(vm_shm_nopage_lock), - open: DRM(vm_open), - close: DRM(vm_close), + close: DRM(vm_shm_close), }; struct vm_operations_struct drm_vm_dma_ops = { @@ -88,12 +82,26 @@ struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, #endif unsigned long physical; unsigned long offset; + unsigned long i; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ if (!map) return NOPAGE_OOM; /* Nothing allocated */ offset = address - vma->vm_start; - physical = (unsigned long)map->handle + offset; + i = (unsigned long)map->handle + offset; + /* We have to walk page tables here because we need large SAREA's, and + * they need to be virtually contigious in kernel space. + */ + pgd = pgd_offset_k( i ); + if( !pgd_present( *pgd ) ) return NOPAGE_OOM; + pmd = pmd_offset( pgd, i ); + if( !pmd_present( *pmd ) ) return NOPAGE_OOM; + pte = pte_offset( pmd, i ); + if( !pte_present( *pte ) ) return NOPAGE_OOM; + physical = (unsigned long)pte_page( *pte )->virtual; atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */ DRM_DEBUG("0x%08lx => 0x%08lx\n", address, physical); @@ -104,37 +112,87 @@ struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, #endif } -#if LINUX_VERSION_CODE < 0x020317 -unsigned long DRM(vm_shm_nopage_lock)(struct vm_area_struct *vma, - unsigned long address, - int write_access) -#else - /* Return type changed in 2.3.23 */ -struct page *DRM(vm_shm_nopage_lock)(struct vm_area_struct *vma, - unsigned long address, - int write_access) -#endif +/* Special close routine which deletes map information if we are the last + * person to close a mapping and its not in the global maplist. + */ + +void DRM(vm_shm_close)(struct vm_area_struct *vma) { - drm_file_t *priv = vma->vm_file->private_data; - drm_device_t *dev = priv->dev; - unsigned long physical; - unsigned long offset; - unsigned long page; + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; + drm_vma_entry_t *pt, *prev; + drm_map_t *map; + drm_map_list_t *r_list; + struct list_head *list; + int found_maps = 0; - if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ - if (!dev->lock.hw_lock) return NOPAGE_OOM; /* Nothing allocated */ + DRM_DEBUG("0x%08lx,0x%08lx\n", + vma->vm_start, vma->vm_end - vma->vm_start); +#if LINUX_VERSION_CODE < 0x020333 + MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif + atomic_dec(&dev->vma_count); - offset = address - vma->vm_start; - page = offset >> PAGE_SHIFT; - physical = (unsigned long)dev->lock.hw_lock + offset; - atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */ +#if LINUX_VERSION_CODE >= 0x020300 + map = vma->vm_private_data; +#else + map = vma->vm_pte; +#endif - DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical); -#if LINUX_VERSION_CODE < 0x020317 - return physical; + down(&dev->struct_sem); + for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) { +#if LINUX_VERSION_CODE >= 0x020300 + if (pt->vma->vm_private_data == map) found_maps++; #else - return virt_to_page(physical); + if (pt->vma->vm_pte == map) found_maps++; #endif + if (pt->vma == vma) { + if (prev) { + prev->next = pt->next; + } else { + dev->vmalist = pt->next; + } + DRM(free)(pt, sizeof(*pt), DRM_MEM_VMAS); + } + } + /* We were the only map that was found */ + if(found_maps == 1 && + map->flags & _DRM_REMOVABLE) { + /* Check to see if we are in the maplist, if we are not, then + * we delete this mappings information. + */ + found_maps = 0; + list = &dev->maplist->head; + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *) list; + if (r_list->map == map) found_maps++; + } + + if(!found_maps) { + switch (map->type) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: +#ifdef __REALLY_HAVE_MTRR + if (map->mtrr >= 0) { + int retcode; + retcode = mtrr_del(map->mtrr, + map->offset, + map->size); + DRM_DEBUG("mtrr_del = %d\n", retcode); + } +#endif + DRM(ioremapfree)(map->handle, map->size); + break; + case _DRM_SHM: + vfree(map->handle); + break; + case _DRM_AGP: + break; + } + DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + } + } + up(&dev->struct_sem); } #if LINUX_VERSION_CODE < 0x020317 @@ -176,9 +234,7 @@ void DRM(vm_open)(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->dev; -#if DRM_DEBUG_CODE drm_vma_entry_t *vma_entry; -#endif DRM_DEBUG("0x%08lx,0x%08lx\n", vma->vm_start, vma->vm_end - vma->vm_start); @@ -188,8 +244,6 @@ void DRM(vm_open)(struct vm_area_struct *vma) MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ #endif - -#if DRM_DEBUG_CODE vma_entry = DRM(alloc)(sizeof(*vma_entry), DRM_MEM_VMAS); if (vma_entry) { down(&dev->struct_sem); @@ -199,16 +253,13 @@ void DRM(vm_open)(struct vm_area_struct *vma) dev->vmalist = vma_entry; up(&dev->struct_sem); } -#endif } void DRM(vm_close)(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; drm_device_t *dev = priv->dev; -#if DRM_DEBUG_CODE drm_vma_entry_t *pt, *prev; -#endif DRM_DEBUG("0x%08lx,0x%08lx\n", vma->vm_start, vma->vm_end - vma->vm_start); @@ -217,7 +268,6 @@ void DRM(vm_close)(struct vm_area_struct *vma) #endif atomic_dec(&dev->vma_count); -#if DRM_DEBUG_CODE down(&dev->struct_sem); for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) { if (pt->vma == vma) { @@ -231,7 +281,6 @@ void DRM(vm_close)(struct vm_area_struct *vma) } } up(&dev->struct_sem); -#endif } int DRM(mmap_dma)(struct file *filp, struct vm_area_struct *vma) @@ -272,7 +321,8 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_map_t *map = NULL; - int i; + drm_map_list_t *r_list; + struct list_head *list; DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", vma->vm_start, vma->vm_end, VM_OFFSET(vma)); @@ -286,12 +336,13 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) once, so it doesn't have to be optimized for performance, even if the list was a bit longer. */ - for (i = 0; i < dev->map_count; i++) { - map = dev->maplist[i]; + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *)list; + map = r_list->map; + if (!map) continue; if (map->offset == VM_OFFSET(vma)) break; } - if (i >= dev->map_count) return -EINVAL; if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) return -EPERM; @@ -339,17 +390,12 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &drm_vm_ops; break; case _DRM_SHM: - if (map->flags & _DRM_CONTAINS_LOCK) - vma->vm_ops = &drm_vm_shm_lock_ops; - else { - vma->vm_ops = &drm_vm_shm_ops; + vma->vm_ops = &drm_vm_shm_ops; #if LINUX_VERSION_CODE >= 0x020300 - vma->vm_private_data = (void *)map; + vma->vm_private_data = (void *)map; #else - vma->vm_pte = (unsigned long)map; + vma->vm_pte = (unsigned long)map; #endif - } - /* Don't let this area swap. Change when DRM_KERNEL advisory is supported. */ vma->vm_flags |= VM_LOCKED; diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index e27406a62..4c90496a7 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -396,23 +396,26 @@ static int i810_dma_initialize(drm_device_t *dev, drm_i810_private_t *dev_priv, drm_i810_init_t *init) { - drm_map_t *sarea_map; + struct list_head *list; dev->dev_private = (void *) dev_priv; memset(dev_priv, 0, sizeof(drm_i810_private_t)); - if (init->ring_map_idx >= dev->map_count || - init->buffer_map_idx >= dev->map_count) { - i810_dma_cleanup(dev); - DRM_ERROR("ring_map or buffer_map are invalid\n"); - return -EINVAL; - } + list_for_each(list, &dev->maplist->head) { + drm_map_list_t *r_list = (drm_map_list_t *)list; + if( r_list->map && + r_list->map->type == _DRM_SHM && + r_list->map->flags & _DRM_CONTAINS_LOCK ) { + dev_priv->sarea_map = r_list->map; + break; + } + } + + DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset ); + DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset ); - dev_priv->ring_map_idx = init->ring_map_idx; - dev_priv->buffer_map_idx = init->buffer_map_idx; - sarea_map = dev->maplist[0]; dev_priv->sarea_priv = (drm_i810_sarea_t *) - ((u8 *)sarea_map->handle + + ((u8 *)dev_priv->sarea_map->handle + init->sarea_priv_offset); atomic_set(&dev_priv->flush_done, 0); @@ -865,6 +868,7 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev, void i810_dma_service(int irq, void *device, struct pt_regs *regs) { drm_device_t *dev = (drm_device_t *)device; + drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; u16 temp; atomic_inc(&dev->counts[_DRM_STAT_IRQ]); diff --git a/linux-core/i810_drm.h b/linux-core/i810_drm.h index c5f51c9ad..cee189b7b 100644 --- a/linux-core/i810_drm.h +++ b/linux-core/i810_drm.h @@ -98,8 +98,8 @@ typedef struct _drm_i810_init { I810_INIT_DMA = 0x01, I810_CLEANUP_DMA = 0x02 } func; - int ring_map_idx; - int buffer_map_idx; + unsigned int mmio_offset; + unsigned int buffers_offset; int sarea_priv_offset; unsigned int ring_start; unsigned int ring_end; diff --git a/linux-core/i810_drv.h b/linux-core/i810_drv.h index 43d44e028..e1b17148e 100644 --- a/linux-core/i810_drv.h +++ b/linux-core/i810_drv.h @@ -54,11 +54,12 @@ typedef struct _drm_i810_ring_buffer{ } drm_i810_ring_buffer_t; typedef struct drm_i810_private { - int ring_map_idx; - int buffer_map_idx; + drm_map_t *sarea_map; + drm_map_t *buffer_map; + drm_map_t *mmio_map; - drm_i810_ring_buffer_t ring; drm_i810_sarea_t *sarea_priv; + drm_i810_ring_buffer_t ring; unsigned long hw_status_page; unsigned long counter; @@ -108,9 +109,8 @@ int i810_clear_bufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -#define I810_REG(reg) 2 #define I810_BASE(reg) ((unsigned long) \ - dev->maplist[I810_REG(reg)]->handle) + dev_priv->mmio_map->handle) #define I810_ADDR(reg) (I810_BASE(reg) + reg) #define I810_DEREF(reg) *(__volatile__ int *)I810_ADDR(reg) #define I810_READ(reg) I810_DEREF(reg) |