diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 8054d254..6f21c0ed 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -723,10 +723,10 @@ extern struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, #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); -extern void DRM(rmmap_fixup_vmas)(drm_device_t *dev, drm_map_t *map); /* Proc support (proc.c) */ diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index f3c275f8..02694f46 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -166,7 +166,10 @@ int DRM(addmap)( struct inode *inode, struct file *filp, } -/* Remove a map private from list and deallocate resources */ +/* 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) { @@ -174,9 +177,10 @@ int DRM(rmmap)(struct inode *inode, struct file *filp, 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))) { @@ -201,34 +205,41 @@ int DRM(rmmap)(struct inode *inode, struct file *filp, return -EINVAL; } map = r_list->map; - list_del(list); - up(&dev->struct_sem); - + list_del(list); DRM(free)(list, sizeof(*list), DRM_MEM_MAPS); - /* Zap any pages that are still mapped and remove no_page vm_op. */ - DRM(rmmap_fixup_vmas)(dev, map); - 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); - } + 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 - 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); + + 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; } diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index f31f8958..123eea29 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -41,7 +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), + close: DRM(vm_shm_close), }; struct vm_operations_struct drm_vm_dma_ops = { @@ -112,6 +112,89 @@ struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, #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; + drm_vma_entry_t *pt, *prev; + drm_map_t *map; + drm_map_list_t *r_list; + struct list_head *list; + int found_maps = 0; + + 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); + +#if LINUX_VERSION_CODE >= 0x020300 + map = vma->vm_private_data; +#else + map = vma->vm_pte; +#endif + + 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 + 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 unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma, unsigned long address, @@ -331,39 +414,3 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) DRM(vm_open)(vma); return 0; } - -/* Support for rmmap so we can safely delete mappings without forcing - * them to be unmapped (which isn't possible if the process forked) - * before we call rmmap. - */ - -void DRM(rmmap_fixup_vmas)(drm_device_t *dev, drm_map_t *map) -{ - drm_vma_entry_t *pt, *prev; - - lock_kernel(); - 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 == (void *)map) -#else - if (pt->vma->vm_pte == (unsigned long)map) -#endif - { - /* Zap the mappings */ - flush_cache_range(pt->vma->vm_mm, - pt->vma->vm_start, - pt->vma->vm_end - pt->vma->vm_start); - zap_page_range(pt->vma->vm_mm, - pt->vma->vm_start, - pt->vma->vm_end - pt->vma->vm_start); - flush_tlb_range(pt->vma->vm_mm, - pt->vma->vm_start, - pt->vma->vm_end - pt->vma->vm_start); - /* Change the vm_ops so no page isn't defined */ - pt->vma->vm_ops = &drm_vm_ops; - } - } - up(&dev->struct_sem); - unlock_kernel(); -} diff --git a/linux/drmP.h b/linux/drmP.h index 8054d254..6f21c0ed 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -723,10 +723,10 @@ extern struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, #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); -extern void DRM(rmmap_fixup_vmas)(drm_device_t *dev, drm_map_t *map); /* Proc support (proc.c) */ diff --git a/linux/drm_bufs.h b/linux/drm_bufs.h index f3c275f8..02694f46 100644 --- a/linux/drm_bufs.h +++ b/linux/drm_bufs.h @@ -166,7 +166,10 @@ int DRM(addmap)( struct inode *inode, struct file *filp, } -/* Remove a map private from list and deallocate resources */ +/* 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) { @@ -174,9 +177,10 @@ int DRM(rmmap)(struct inode *inode, struct file *filp, 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))) { @@ -201,34 +205,41 @@ int DRM(rmmap)(struct inode *inode, struct file *filp, return -EINVAL; } map = r_list->map; - list_del(list); - up(&dev->struct_sem); - + list_del(list); DRM(free)(list, sizeof(*list), DRM_MEM_MAPS); - /* Zap any pages that are still mapped and remove no_page vm_op. */ - DRM(rmmap_fixup_vmas)(dev, map); - 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); - } + 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 - 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); + + 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; } diff --git a/linux/drm_vm.h b/linux/drm_vm.h index f31f8958..123eea29 100644 --- a/linux/drm_vm.h +++ b/linux/drm_vm.h @@ -41,7 +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), + close: DRM(vm_shm_close), }; struct vm_operations_struct drm_vm_dma_ops = { @@ -112,6 +112,89 @@ struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, #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; + drm_vma_entry_t *pt, *prev; + drm_map_t *map; + drm_map_list_t *r_list; + struct list_head *list; + int found_maps = 0; + + 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); + +#if LINUX_VERSION_CODE >= 0x020300 + map = vma->vm_private_data; +#else + map = vma->vm_pte; +#endif + + 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 + 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 unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma, unsigned long address, @@ -331,39 +414,3 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) DRM(vm_open)(vma); return 0; } - -/* Support for rmmap so we can safely delete mappings without forcing - * them to be unmapped (which isn't possible if the process forked) - * before we call rmmap. - */ - -void DRM(rmmap_fixup_vmas)(drm_device_t *dev, drm_map_t *map) -{ - drm_vma_entry_t *pt, *prev; - - lock_kernel(); - 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 == (void *)map) -#else - if (pt->vma->vm_pte == (unsigned long)map) -#endif - { - /* Zap the mappings */ - flush_cache_range(pt->vma->vm_mm, - pt->vma->vm_start, - pt->vma->vm_end - pt->vma->vm_start); - zap_page_range(pt->vma->vm_mm, - pt->vma->vm_start, - pt->vma->vm_end - pt->vma->vm_start); - flush_tlb_range(pt->vma->vm_mm, - pt->vma->vm_start, - pt->vma->vm_end - pt->vma->vm_start); - /* Change the vm_ops so no page isn't defined */ - pt->vma->vm_ops = &drm_vm_ops; - } - } - up(&dev->struct_sem); - unlock_kernel(); -} diff --git a/linux/mga_dma.c b/linux/mga_dma.c index 8b483193..275495dc 100644 --- a/linux/mga_dma.c +++ b/linux/mga_dma.c @@ -56,7 +56,11 @@ int mga_do_wait_for_idle( drm_mga_private_t *dev_priv ) for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK; - if ( status == MGA_ENDPRDMASTS ) return 0; + if ( status == MGA_ENDPRDMASTS ) { + /* printk("I'm not busy, flushing pixel cache\n"); */ + MGA_WRITE8( MGA_CRTC_INDEX, 0 ); + return 0; + } udelay( 1 ); } diff --git a/linux/mga_drv.h b/linux/mga_drv.h index 7a5a1dcc..ab6d9edb 100644 --- a/linux/mga_drv.h +++ b/linux/mga_drv.h @@ -165,7 +165,8 @@ extern int mga_warp_init( drm_device_t *dev ); #define MGA_DEREF( reg ) *(volatile u32 *)MGA_ADDR( reg ) #define MGA_READ( reg ) MGA_DEREF( reg ) #define MGA_WRITE( reg, val ) do { MGA_DEREF( reg ) = val; } while (0) - +#define MGA_DEREF8( reg ) *(volatile u8 *)MGA_ADDR( reg ) +#define MGA_WRITE8( reg, val ) do { MGA_DEREF8( reg ) = val; } while (0) #define DWGREG0 0x1c00 #define DWGREG0_END 0x1dff @@ -329,6 +330,7 @@ do { \ /* A reduced set of the mga registers. */ +#define MGA_CRTC_INDEX 0x1fd4 #define MGA_ALPHACTRL 0x2c7c #define MGA_AR0 0x1c60