Implemented an solution to the fork resource problem without using

zap_page_range, a little more code, but just as good (and no kernel
    export modifications are needed for this solution.)
This commit is contained in:
Jeff Hartmann 2001-02-20 22:16:48 +00:00
parent 0270da2882
commit ba3a1aa6b6
8 changed files with 252 additions and 130 deletions

View file

@ -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) */

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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) */

View file

@ -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;
}

View file

@ -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();
}

View file

@ -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 );
}

View file

@ -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