diff options
Diffstat (limited to 'linux')
| -rw-r--r-- | linux/drmP.h | 2 | ||||
| -rw-r--r-- | linux/drm_bufs.h | 103 | ||||
| -rw-r--r-- | linux/drm_drv.h | 66 | 
3 files changed, 137 insertions, 34 deletions
diff --git a/linux/drmP.h b/linux/drmP.h index 75fb999a..4271a7a2 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -831,6 +831,8 @@ 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 ); +extern int 	     DRM(initmap)( drm_device_t *dev, unsigned int offset, +				 unsigned int size, int type, int flags );  #if __HAVE_DMA  extern int	     DRM(addbufs)( struct inode *inode, struct file *filp,  				   unsigned int cmd, unsigned long arg ); diff --git a/linux/drm_bufs.h b/linux/drm_bufs.h index d3d0b83c..7ae95fcc 100644 --- a/linux/drm_bufs.h +++ b/linux/drm_bufs.h @@ -68,6 +68,69 @@ int DRM(order)( unsigned long size )  	return order;  } + /** + * Adjusts the memory offset to its absolute value according to the mapping + * type.  Adds the map to the map list drm_device::maplist. Adds MTRR's where + * applicable and if supported by the kernel. + */ +int DRM(initmap)( drm_device_t *dev, unsigned int offset, unsigned int size, int type, int flags ) +{ +	drm_map_t *map; +	drm_map_list_t *list; + +	DRM_DEBUG("\n"); + +	if ( (offset & (~PAGE_MASK)) || (size & (~PAGE_MASK)) ) +		return -EINVAL; +#if !defined(__sparc__) && !defined(__alpha__) +	if ( offset + size < offset || offset < virt_to_phys(high_memory) ) +		return -EINVAL; +#endif +	if ( !(list = DRM(alloc)( sizeof(*list), DRM_MEM_MAPS ))) +		return -ENOMEM; +	memset(list, 0, sizeof(*list)); +		 +	if ( !(map = DRM(alloc)( sizeof(*map), DRM_MEM_MAPS ))) { +		DRM(free)(list, sizeof(*list), DRM_MEM_MAPS); +		return -ENOMEM; +	} + +	*map = (drm_map_t){ +		.offset = offset, +		.size = size, +		.type = type, +		.flags = flags, +		.mtrr = -1, +		.handle = 0, +	}; +	list->map = map; + +	DRM_DEBUG( "initmap offset = 0x%08lx, size = 0x%08lx, type = %d\n", +		   map->offset, map->size, map->type ); +         +#ifdef __alpha__ +	map->offset += dev->hose->mem_space->start; +#endif +#if __REALLY_HAVE_MTRR +	if ( map->type == _DRM_FRAME_BUFFER || +		(map->flags & _DRM_WRITE_COMBINING) ) { +		map->mtrr = mtrr_add( map->offset, map->size, +					MTRR_TYPE_WRCOMB, 1 ); +	} +#endif +	if (map->type == _DRM_REGISTERS) +		map->handle = DRM(ioremap)( map->offset, map->size, dev ); + +	down(&dev->struct_sem); +	list_add(&list->head, &dev->maplist->head); +	up(&dev->struct_sem); +	 +	DRM_DEBUG("finished\n"); + +	return 0; +} + +  /**   * Ioctl to specify a range of memory that is available for mapping by a non-root process.   * @@ -120,7 +183,21 @@ int DRM(addmap)( struct inode *inode, struct file *filp,  	switch ( map->type ) {  	case _DRM_REGISTERS: -	case _DRM_FRAME_BUFFER: +	case _DRM_FRAME_BUFFER: { +		/* after all the drivers switch to permanent mapping this should just return an error */ +        	struct list_head *_list; + +		/* if map already exists, return the existing one instead of creating a new one */ +		list_for_each( _list, &dev->maplist->head ) { +			drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); +			if ( _entry->map && _entry->map->type == map->type ) { +				DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); +				map = _entry->map; +				DRM_DEBUG( "Found existing: offset = 0x%08lx, size = 0x%08lx, type = %d\n", +					map->offset, map->size, map->type ); +				goto found_it; +			} +		}  #if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__)  		if ( map->offset + map->size < map->offset ||  		     map->offset < virt_to_phys(high_memory) ) { @@ -142,7 +219,7 @@ int DRM(addmap)( struct inode *inode, struct file *filp,  			map->handle = DRM(ioremap)( map->offset, map->size,  						    dev );  		break; - +	}  	case _DRM_SHM:  		map->handle = vmalloc_32(map->size);  		DRM_DEBUG( "%lu %d %p\n", @@ -196,7 +273,7 @@ int DRM(addmap)( struct inode *inode, struct file *filp,  	down(&dev->struct_sem);  	list_add(&list->head, &dev->maplist->head);   	up(&dev->struct_sem); - +found_it:  	if ( copy_to_user( argp, map, sizeof(*map) ) )  		return -EFAULT;  	if ( map->type != _DRM_SHM ) { @@ -241,7 +318,7 @@ int DRM(rmmap)(struct inode *inode, struct file *filp,  			   sizeof(request))) {  		return -EFAULT;  	} - +	  	down(&dev->struct_sem);  	list = &dev->maplist->head;  	list_for_each(list, &dev->maplist->head) { @@ -260,6 +337,12 @@ int DRM(rmmap)(struct inode *inode, struct file *filp,  		return -EINVAL;  	}  	map = r_list->map; +	 +	/* Register and framebuffer maps are permanent */ +	if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { +		up(&dev->struct_sem); +		return 0; +	}  	list_del(list);  	DRM(free)(list, sizeof(*list), DRM_MEM_MAPS); @@ -271,17 +354,7 @@ int DRM(rmmap)(struct inode *inode, struct file *filp,  		switch (map->type) {  		case _DRM_REGISTERS:  		case _DRM_FRAME_BUFFER: -#if __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, dev); -			break; +			break;  /* Can't get here, make compiler happy */  		case _DRM_SHM:  			vfree(map->handle);  			break; diff --git a/linux/drm_drv.h b/linux/drm_drv.h index 7f652e43..4b97e40c 100644 --- a/linux/drm_drv.h +++ b/linux/drm_drv.h @@ -275,12 +275,6 @@ static int DRM(setup)( drm_device_t *dev )  		dev->magiclist[i].tail = 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->ctxlist = DRM(alloc)(sizeof(*dev->ctxlist),  				  DRM_MEM_CTXLIST);  	if(dev->ctxlist == NULL) return -ENOMEM; @@ -420,17 +414,8 @@ static int DRM(takedown)( drm_device_t *dev )  				switch ( map->type ) {  				case _DRM_REGISTERS:  				case _DRM_FRAME_BUFFER: -#if __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, dev ); -					break; +					continue; +					  				case _DRM_SHM:  					vfree(map->handle);  					break; @@ -457,8 +442,6 @@ static int DRM(takedown)( drm_device_t *dev )  			list_del( list );  			DRM(free)(r_list, sizeof(*r_list), DRM_MEM_MAPS);   		} -		DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); -		dev->maplist = NULL;   	}  #if __HAVE_DMA_QUEUE || __HAVE_MULTIPLE_DMA_QUEUES @@ -537,6 +520,11 @@ static int drm_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	dev->pci_func = PCI_FUNC(pdev->devfn);  	dev->irq = pdev->irq; +	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_priv_size can be changed by a driver in driver_register_fns */  	dev->dev_priv_size = sizeof(u32);  	DRM(driver_register_fns)(dev); @@ -677,6 +665,10 @@ static int __init drm_init( void )   */  static void __exit drm_cleanup( drm_device_t *dev )  { +	drm_map_t *map; +	drm_map_list_t *r_list; +	struct list_head *list, *list_next; +	  	DRM_DEBUG( "\n" );  	if (!dev) {  		DRM_ERROR("cleanup called no dev\n"); @@ -685,6 +677,42 @@ static void __exit drm_cleanup( drm_device_t *dev )  	DRM(takedown)(dev); +	if( dev->maplist ) { +		list_for_each_safe( list, list_next, &dev->maplist->head ) { +			r_list = (drm_map_list_t *)list; + +			if ( ( map = r_list->map ) ) { +				switch ( map->type ) { +				case _DRM_REGISTERS: +					DRM(ioremapfree)( map->handle, map->size, dev ); +					break; +					 +				case _DRM_FRAME_BUFFER: +#if __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 +					break; +					 +				case _DRM_SHM: +				case _DRM_AGP: +				case _DRM_SCATTER_GATHER: +					DRM_DEBUG("Extra maplist item\n"); +					break; +				} +				DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); +			} +			list_del( list ); +			DRM(free)(r_list, sizeof(*r_list), DRM_MEM_MAPS); + 		} +		DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); +		dev->maplist = NULL; + 	}  	if (DRM(fb_loaded)==0)  		pci_disable_device(dev->pdev);  | 
