mirror of
https://gitlab.freedesktop.org/mesa/drm.git
synced 2026-05-08 10:28:04 +02:00
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:
parent
0270da2882
commit
ba3a1aa6b6
8 changed files with 252 additions and 130 deletions
|
|
@ -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) */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
121
linux/drm_vm.h
121
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue