diff options
| author | Gareth Hughes <gareth@users.sourceforge.net> | 2001-02-15 08:12:14 +0000 | 
|---|---|---|
| committer | Gareth Hughes <gareth@users.sourceforge.net> | 2001-02-15 08:12:14 +0000 | 
| commit | 360475376c5a597caf4a981c934a6b0d783fa94d (patch) | |
| tree | 433f6970813deb74a2c8e1636b772a1f8567b267 /linux-core | |
| parent | 38c22bc4883ac201bde7f5f130a72acd1be68ec5 (diff) | |
Merge mga-1-0-0-branch into trunk.
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/Makefile.kernel | 4 | ||||
| -rw-r--r-- | linux-core/drmP.h | 485 | ||||
| -rw-r--r-- | linux-core/drm_agpsupport.c | 335 | ||||
| -rw-r--r-- | linux-core/drm_auth.c | 162 | ||||
| -rw-r--r-- | linux-core/drm_bufs.c | 757 | ||||
| -rw-r--r-- | linux-core/drm_context.c | 270 | ||||
| -rw-r--r-- | linux-core/drm_dma.c | 576 | ||||
| -rw-r--r-- | linux-core/drm_drawable.c | 51 | ||||
| -rw-r--r-- | linux-core/drm_drv.c | 927 | ||||
| -rw-r--r-- | linux-core/drm_fops.c | 252 | ||||
| -rw-r--r-- | linux-core/drm_init.c | 112 | ||||
| -rw-r--r-- | linux-core/drm_ioctl.c | 192 | ||||
| -rw-r--r-- | linux-core/drm_lock.c | 251 | ||||
| -rw-r--r-- | linux-core/drm_memory.h | 460 | ||||
| -rw-r--r-- | linux-core/drm_proc.c | 623 | ||||
| -rw-r--r-- | linux-core/drm_stub.c | 142 | ||||
| -rw-r--r-- | linux-core/drm_vm.c | 370 | ||||
| -rw-r--r-- | linux-core/i810_dma.c | 396 | ||||
| -rw-r--r-- | linux-core/i810_drv.c | 692 | ||||
| -rw-r--r-- | linux-core/i810_drv.h | 60 | ||||
| -rw-r--r-- | linux-core/mga_drv.c | 708 | ||||
| -rw-r--r-- | linux-core/r128_drv.c | 755 | ||||
| -rw-r--r-- | linux-core/radeon_drv.c | 759 | ||||
| -rw-r--r-- | linux-core/tdfx_drv.c | 691 | 
24 files changed, 6263 insertions, 3767 deletions
| diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 9fe0038f..a39b3cc5 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -62,7 +62,7 @@ obj-$(CONFIG_DRM_MGA)    += mga.o  obj-$(CONFIG_DRM_I810)   += i810.o -# When linking into the kernel, link the library just once.  +# When linking into the kernel, link the library just once.  # If making modules, we include the library into each module  lib-objs-mod := $(patsubst %.o,%-mod.o,$(lib-objs)) @@ -75,7 +75,7 @@ endif  include $(TOPDIR)/Rules.make -$(patsubst %.o,%.c,$(lib-objs-mod)):  +$(patsubst %.o,%.c,$(lib-objs-mod)):  	@ln -sf $(subst -mod,,$@) $@  drmlib-mod.a: $(lib-objs-mod) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 9a8fe61f..58d98f50 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -19,14 +19,14 @@   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE.   *   * Authors:   *    Rickard E. (Rik) Faith <faith@valinux.com> - * + *    Gareth Hughes <gareth@valinux.com>   */  #ifndef _DRM_P_H_ @@ -75,6 +75,32 @@  #endif  #include "drm.h" +/* DRM template customization defaults + */ +#ifndef __HAVE_AGP +#define __HAVE_AGP		0 +#endif +#ifndef __HAVE_MTRR +#define __HAVE_MTRR		0 +#endif +#ifndef __HAVE_DMA +#define __HAVE_DMA		0 +#endif +#ifndef __HAVE_DMA_WAITLIST +#define __HAVE_DMA_WAITLIST	0 +#endif +#ifndef __HAVE_DMA_FREELIST +#define __HAVE_DMA_FREELIST	0 +#endif + +#define __REALLY_HAVE_AGP	(__HAVE_AGP && (defined(CONFIG_AGP) || \ +						defined(CONFIG_AGP_MODULE))) +#define __REALLY_HAVE_MTRR	(__HAVE_MTRR && defined(CONFIG_MTRR)) + + +/* Begin the DRM... + */ +  #define DRM_DEBUG_CODE 2	  /* Include debugging code (if > 1, then  				     also include looping detection. */  #define DRM_DMA_HISTOGRAM 1	  /* Make histogram of DMA latency. */ @@ -109,6 +135,7 @@  #define DRM_MEM_TOTALAGP  16  #define DRM_MEM_BOUNDAGP  17  #define DRM_MEM_CTXBITMAP 18 +#define DRM_MEM_STUB      19  #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) @@ -259,16 +286,16 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,  	printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ "] *ERROR* " fmt , ##arg)  #define DRM_MEM_ERROR(area, fmt, arg...) \  	printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ ":%s] *ERROR* " fmt , \ -	       drm_mem_stats[area].name , ##arg) +	       DRM(mem_stats)[area].name , ##arg)  #define DRM_INFO(fmt, arg...)  printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)  #if DRM_DEBUG_CODE -#define DRM_DEBUG(fmt, arg...)						  \ -	do {								  \ -		if (drm_flags&DRM_FLAG_DEBUG)				  \ -			printk(KERN_DEBUG				  \ -			       "[" DRM_NAME ":" __FUNCTION__ "] " fmt ,	  \ -			       ##arg);					  \ +#define DRM_DEBUG(fmt, arg...)						\ +	do {								\ +		if ( DRM(flags) & DRM_FLAG_DEBUG )			\ +			printk(KERN_DEBUG				\ +			       "[" DRM_NAME ":" __FUNCTION__ "] " fmt ,	\ +			       ##arg);					\  	} while (0)  #else  #define DRM_DEBUG(fmt, arg...)		 do { } while (0) @@ -276,22 +303,22 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,  #define DRM_PROC_LIMIT (PAGE_SIZE-80) -#define DRM_PROC_PRINT(fmt, arg...)	   \ -   len += sprintf(&buf[len], fmt , ##arg); \ -   if (len > DRM_PROC_LIMIT) return len; +#define DRM_PROC_PRINT(fmt, arg...)					\ +   len += sprintf(&buf[len], fmt , ##arg);				\ +   if (len > DRM_PROC_LIMIT) { *eof = 1; return len - offset; } -#define DRM_PROC_PRINT_RET(ret, fmt, arg...)	    \ -   len += sprintf(&buf[len], fmt , ##arg);	    \ -   if (len > DRM_PROC_LIMIT) { ret; return len; } +#define DRM_PROC_PRINT_RET(ret, fmt, arg...)				\ +   len += sprintf(&buf[len], fmt , ##arg);				\ +   if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; }  				/* Mapping helper macros */  #define DRM_IOREMAP(map)						\ -	(map)->handle = drm_ioremap( (map)->offset, (map)->size ) +	(map)->handle = DRM(ioremap)( (map)->offset, (map)->size )  #define DRM_IOREMAPFREE(map)						\  	do {								\  		if ( (map)->handle && (map)->size )			\ -			drm_ioremapfree( (map)->handle, (map)->size );	\ +			DRM(ioremapfree)( (map)->handle, (map)->size );	\  	} while (0)  #define DRM_FIND_MAP(map, o)						\ @@ -314,8 +341,8 @@ 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) -typedef int drm_ioctl_t(struct inode *inode, struct file *filp, -			unsigned int cmd, unsigned long arg); +typedef int drm_ioctl_t( struct inode *inode, struct file *filp, +			 unsigned int cmd, unsigned long arg );  typedef struct drm_ioctl_desc {  	drm_ioctl_t	     *func; @@ -463,9 +490,11 @@ typedef struct drm_queue {  	wait_queue_head_t read_queue;	/* Processes waiting on block_read  */  	atomic_t	  block_write;	/* Queue blocked for writes	    */  	wait_queue_head_t write_queue;	/* Processes waiting on block_write */ +#if 1  	atomic_t	  total_queued;	/* Total queued statistic	    */  	atomic_t	  total_flushed;/* Total flushes statistic	    */  	atomic_t	  total_locks;	/* Total locks statistics	    */ +#endif  	drm_ctx_flags_t	  flags;	/* Context preserving and 2D-only   */  	drm_waitlist_t	  waitlist;	/* Pending buffers		    */  	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */ @@ -479,6 +508,7 @@ typedef struct drm_lock_data {  } drm_lock_data_t;  typedef struct drm_device_dma { +#if 0  				/* Performance Counters */  	atomic_t	  total_prio;	/* Total DRM_DMA_PRIORITY	   */  	atomic_t	  total_bytes;	/* Total bytes DMA'd		   */ @@ -492,6 +522,7 @@ typedef struct drm_device_dma {  	atomic_t	  total_tried;	/* Tried next_buffer		    */  	atomic_t	  total_hit;	/* Sent next_buffer		    */  	atomic_t	  total_lost;	/* Lost interrupt		    */ +#endif  	drm_buf_entry_t	  bufs[DRM_MAX_ORDER+1];  	int		  buf_count; @@ -501,7 +532,7 @@ typedef struct drm_device_dma {  	unsigned long	  *pagelist;  	unsigned long	  byte_count;  	enum { -	   _DRM_DMA_USE_AGP = 0x01 +		_DRM_DMA_USE_AGP = 0x01  	} flags;  				/* DMA support */ @@ -511,7 +542,7 @@ typedef struct drm_device_dma {  	wait_queue_head_t waiting;	/* Processes waiting on free bufs  */  } drm_device_dma_t; -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +#if __REALLY_HAVE_AGP  typedef struct drm_agp_mem {  	unsigned long      handle;  	agp_memory         *memory; @@ -559,17 +590,10 @@ typedef struct drm_device {  	int		  buf_use;	/* Buffers in use -- cannot alloc  */  	atomic_t	  buf_alloc;	/* Buffer allocation in progress   */ -				/* Performance Counters */ -	atomic_t	  total_open; -	atomic_t	  total_close; -	atomic_t	  total_ioctl; -	atomic_t	  total_irq;	/* Total interruptions		   */ -	atomic_t	  total_ctx;	/* Total context switches	   */ - -	atomic_t	  total_locks; -	atomic_t	  total_unlocks; -	atomic_t	  total_contends; -	atomic_t	  total_sleeps; +				/* Performance counters */ +	unsigned long     counters; +	drm_stat_type_t   types[15]; +	atomic_t          counts[15];  				/* Authentication */  	drm_file_t	  *file_first; @@ -617,7 +641,7 @@ typedef struct drm_device {  	wait_queue_head_t buf_readers;	/* Processes waiting to read	   */  	wait_queue_head_t buf_writers;	/* Processes waiting to ctx switch */ -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +#if __REALLY_HAVE_AGP  	drm_agp_head_t    *agp;  #endif  	unsigned long     *ctx_bitmap; @@ -630,227 +654,262 @@ typedef struct drm_device {  				/* Internal function definitions */  				/* Misc. support (init.c) */ -extern int	     drm_flags; -extern void	     drm_parse_options(char *s); -extern int           drm_cpu_valid(void); +extern int	     DRM(flags); +extern void	     DRM(parse_options)( char *s ); +extern int           DRM(cpu_valid)( void ); +				/* Driver support (drm_drv.h) */ +extern int           DRM(version)(struct inode *inode, struct file *filp, +				  unsigned int cmd, unsigned long arg); +extern int           DRM(open)(struct inode *inode, struct file *filp); +extern int           DRM(release)(struct inode *inode, struct file *filp); +extern int           DRM(ioctl)(struct inode *inode, struct file *filp, +				unsigned int cmd, unsigned long arg); +extern int           DRM(lock)(struct inode *inode, struct file *filp, +			       unsigned int cmd, unsigned long arg); +extern int           DRM(unlock)(struct inode *inode, struct file *filp, +				 unsigned int cmd, unsigned long arg);  				/* Device support (fops.c) */ -extern int	     drm_open_helper(struct inode *inode, struct file *filp, -				     drm_device_t *dev); -extern int	     drm_flush(struct file *filp); -extern int	     drm_release(struct inode *inode, struct file *filp); -extern int	     drm_fasync(int fd, struct file *filp, int on); -extern ssize_t	     drm_read(struct file *filp, char *buf, size_t count, -			      loff_t *off); -extern int	     drm_write_string(drm_device_t *dev, const char *s); -extern unsigned int  drm_poll(struct file *filp, struct poll_table_struct *wait); +extern int	     DRM(open_helper)(struct inode *inode, struct file *filp, +				      drm_device_t *dev); +extern int	     DRM(flush)(struct file *filp); +extern int	     DRM(release_fuck)(struct inode *inode, struct file *filp); +extern int	     DRM(fasync)(int fd, struct file *filp, int on); +extern ssize_t	     DRM(read)(struct file *filp, char *buf, size_t count, +			       loff_t *off); +extern int	     DRM(write_string)(drm_device_t *dev, const char *s); +extern unsigned int  DRM(poll)(struct file *filp, +			       struct poll_table_struct *wait);  				/* Mapping support (vm.c) */  #if LINUX_VERSION_CODE < 0x020317 -extern unsigned long drm_vm_nopage(struct vm_area_struct *vma, +extern unsigned long DRM(vm_nopage)(struct vm_area_struct *vma, +				    unsigned long address, +				    int write_access); +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); +#else +				/* Return type changed in 2.3.23 */ +extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma,  				   unsigned long address,  				   int write_access); -extern unsigned long drm_vm_shm_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 unsigned long drm_vm_shm_nopage_lock(struct vm_area_struct *vma, +extern struct page *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, +extern struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,  				       unsigned long address,  				       int write_access); -#else -				/* Return type changed in 2.3.23 */ -extern struct page *drm_vm_nopage(struct vm_area_struct *vma, -				  unsigned long address, -				  int write_access); -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 int	     drm_mmap_dma(struct file *filp, -				  struct vm_area_struct *vma); -extern int	     drm_mmap(struct file *filp, 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 int	     DRM(mmap_dma)(struct file *filp, +				   struct vm_area_struct *vma); +extern int	     DRM(mmap)(struct file *filp, struct vm_area_struct *vma);  				/* Proc support (proc.c) */ -extern int	     drm_proc_init(drm_device_t *dev); -extern int	     drm_proc_cleanup(void); +extern struct proc_dir_entry *drm_proc_init(drm_device_t *dev, +					    int minor, +					    struct proc_dir_entry *root, +					    struct proc_dir_entry **dev_root); +extern int          drm_proc_cleanup(int minor, +                                     struct proc_dir_entry *root, +                                     struct proc_dir_entry *dev_root);  				/* Memory management support (memory.c) */ -extern void	     drm_mem_init(void); -extern int	     drm_mem_info(char *buf, char **start, off_t offset, -				  int len, int *eof, void *data); -extern void	     *drm_alloc(size_t size, int area); -extern void	     *drm_realloc(void *oldpt, size_t oldsize, size_t size, -				  int area); -extern char	     *drm_strdup(const char *s, int area); -extern void	     drm_strfree(const char *s, int area); -extern void	     drm_free(void *pt, size_t size, int area); -extern unsigned long drm_alloc_pages(int order, int area); -extern void	     drm_free_pages(unsigned long address, int order, -				    int area); -extern void	     *drm_ioremap(unsigned long offset, unsigned long size); -extern void	     drm_ioremapfree(void *pt, unsigned long size); - -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -extern agp_memory    *drm_alloc_agp(int pages, u32 type); -extern int           drm_free_agp(agp_memory *handle, int pages); -extern int           drm_bind_agp(agp_memory *handle, unsigned int start); -extern int           drm_unbind_agp(agp_memory *handle); +extern void	     DRM(mem_init)(void); +extern int	     DRM(mem_info)(char *buf, char **start, off_t offset, +				   int request, int *eof, void *data); +extern void	     *DRM(alloc)(size_t size, int area); +extern void	     *DRM(realloc)(void *oldpt, size_t oldsize, size_t size, +				   int area); +extern char	     *DRM(strdup)(const char *s, int area); +extern void	     DRM(strfree)(const char *s, int area); +extern void	     DRM(free)(void *pt, size_t size, int area); +extern unsigned long DRM(alloc_pages)(int order, int area); +extern void	     DRM(free_pages)(unsigned long address, int order, +				     int area); +extern void	     *DRM(ioremap)(unsigned long offset, unsigned long size); +extern void	     DRM(ioremapfree)(void *pt, unsigned long size); + +#if __REALLY_HAVE_AGP +extern agp_memory    *DRM(alloc_agp)(int pages, u32 type); +extern int           DRM(free_agp)(agp_memory *handle, int pages); +extern int           DRM(bind_agp)(agp_memory *handle, unsigned int start); +extern int           DRM(unbind_agp)(agp_memory *handle);  #endif - -				/* Buffer management support (bufs.c) */ -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_addbufs(struct inode *inode, struct file *filp, -				 unsigned int cmd, unsigned long arg); -extern int	     drm_infobufs(struct inode *inode, struct file *filp, -				  unsigned int cmd, unsigned long arg); -extern int	     drm_markbufs(struct inode *inode, struct file *filp, -				  unsigned int cmd, unsigned long arg); -extern int	     drm_freebufs(struct inode *inode, struct file *filp, -				  unsigned int cmd, unsigned long arg); -extern int	     drm_mapbufs(struct inode *inode, struct file *filp, -				 unsigned int cmd, unsigned long arg); - - -				/* Buffer list management support (lists.c) */ -extern int	     drm_waitlist_create(drm_waitlist_t *bl, int count); -extern int	     drm_waitlist_destroy(drm_waitlist_t *bl); -extern int	     drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf); -extern drm_buf_t     *drm_waitlist_get(drm_waitlist_t *bl); - -extern int	     drm_freelist_create(drm_freelist_t *bl, int count); -extern int	     drm_freelist_destroy(drm_freelist_t *bl); -extern int	     drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, -				      drm_buf_t *buf); -extern drm_buf_t     *drm_freelist_get(drm_freelist_t *bl, int block); - -				/* DMA support (gen_dma.c) */ -extern void	     drm_dma_setup(drm_device_t *dev); -extern void	     drm_dma_takedown(drm_device_t *dev); -extern void	     drm_free_buffer(drm_device_t *dev, drm_buf_t *buf); -extern void	     drm_reclaim_buffers(drm_device_t *dev, pid_t pid); -extern int	     drm_context_switch(drm_device_t *dev, int old, int new); -extern int	     drm_context_switch_complete(drm_device_t *dev, int new); -extern void	     drm_clear_next_buffer(drm_device_t *dev); -extern int	     drm_select_queue(drm_device_t *dev, -				      void (*wrapper)(unsigned long)); -extern int	     drm_dma_enqueue(drm_device_t *dev, drm_dma_t *dma); -extern int	     drm_dma_get_buffers(drm_device_t *dev, drm_dma_t *dma); -#if DRM_DMA_HISTOGRAM -extern int	     drm_histogram_slot(unsigned long count); -extern void	     drm_histogram_compute(drm_device_t *dev, drm_buf_t *buf); -#endif - -  				/* Misc. IOCTL support (ioctl.c) */ -extern int	     drm_irq_busid(struct inode *inode, struct file *filp, -				   unsigned int cmd, unsigned long arg); -extern int	     drm_getunique(struct inode *inode, struct file *filp, -				   unsigned int cmd, unsigned long arg); -extern int	     drm_setunique(struct inode *inode, struct file *filp, +extern int	     DRM(irq_busid)(struct inode *inode, struct file *filp, +				    unsigned int cmd, unsigned long arg); +extern int	     DRM(getunique)(struct inode *inode, struct file *filp, +				    unsigned int cmd, unsigned long arg); +extern int	     DRM(setunique)(struct inode *inode, struct file *filp, +				    unsigned int cmd, unsigned long arg); +extern int	     DRM(getmap)(struct inode *inode, struct file *filp, +				 unsigned int cmd, unsigned long arg); +extern int	     DRM(getclient)(struct inode *inode, struct file *filp, +				    unsigned int cmd, unsigned long arg); +extern int	     DRM(getstats)(struct inode *inode, struct file *filp,  				   unsigned int cmd, unsigned long arg); -  				/* Context IOCTL support (context.c) */ -extern int	     drm_resctx(struct inode *inode, struct file *filp, -				unsigned int cmd, unsigned long arg); -extern int	     drm_addctx(struct inode *inode, struct file *filp, -				unsigned int cmd, unsigned long arg); -extern int	     drm_modctx(struct inode *inode, struct file *filp, -				unsigned int cmd, unsigned long arg); -extern int	     drm_getctx(struct inode *inode, struct file *filp, -				unsigned int cmd, unsigned long arg); -extern int	     drm_switchctx(struct inode *inode, struct file *filp, -				   unsigned int cmd, unsigned long arg); -extern int	     drm_newctx(struct inode *inode, struct file *filp, -				unsigned int cmd, unsigned long arg); -extern int	     drm_rmctx(struct inode *inode, struct file *filp, -			       unsigned int cmd, unsigned long arg); - +extern int	     DRM(resctx)( struct inode *inode, struct file *filp, +				  unsigned int cmd, unsigned long arg ); +extern int	     DRM(addctx)( struct inode *inode, struct file *filp, +				  unsigned int cmd, unsigned long arg ); +extern int	     DRM(modctx)( struct inode *inode, struct file *filp, +				  unsigned int cmd, unsigned long arg ); +extern int	     DRM(getctx)( struct inode *inode, struct file *filp, +				  unsigned int cmd, unsigned long arg ); +extern int	     DRM(switchctx)( struct inode *inode, struct file *filp, +				     unsigned int cmd, unsigned long arg ); +extern int	     DRM(newctx)( struct inode *inode, struct file *filp, +				  unsigned int cmd, unsigned long arg ); +extern int	     DRM(rmctx)( struct inode *inode, struct file *filp, +				 unsigned int cmd, unsigned long arg ); + +extern int	     DRM(context_switch)(drm_device_t *dev, int old, int new); +extern int	     DRM(context_switch_complete)(drm_device_t *dev, int new);  				/* Drawable IOCTL support (drawable.c) */ -extern int	     drm_adddraw(struct inode *inode, struct file *filp, +extern int	     DRM(adddraw)(struct inode *inode, struct file *filp, +				  unsigned int cmd, unsigned long arg); +extern int	     DRM(rmdraw)(struct inode *inode, struct file *filp,  				 unsigned int cmd, unsigned long arg); -extern int	     drm_rmdraw(struct inode *inode, struct file *filp, -				unsigned int cmd, unsigned long arg);  				/* Authentication IOCTL support (auth.c) */ -extern int	     drm_add_magic(drm_device_t *dev, drm_file_t *priv, -				   drm_magic_t magic); -extern int	     drm_remove_magic(drm_device_t *dev, drm_magic_t magic); -extern int	     drm_getmagic(struct inode *inode, struct file *filp, -				  unsigned int cmd, unsigned long arg); -extern int	     drm_authmagic(struct inode *inode, struct file *filp, +extern int	     DRM(add_magic)(drm_device_t *dev, drm_file_t *priv, +				    drm_magic_t magic); +extern int	     DRM(remove_magic)(drm_device_t *dev, drm_magic_t magic); +extern int	     DRM(getmagic)(struct inode *inode, struct file *filp,  				   unsigned int cmd, unsigned long arg); +extern int	     DRM(authmagic)(struct inode *inode, struct file *filp, +				    unsigned int cmd, unsigned long arg);  				/* Locking IOCTL support (lock.c) */ -extern int	     drm_block(struct inode *inode, struct file *filp, -			       unsigned int cmd, unsigned long arg); -extern int	     drm_unblock(struct inode *inode, struct file *filp, -				 unsigned int cmd, unsigned long arg); -extern int	     drm_lock_take(__volatile__ unsigned int *lock, -				   unsigned int context); -extern int	     drm_lock_transfer(drm_device_t *dev, -				       __volatile__ unsigned int *lock, -				       unsigned int context); -extern int	     drm_lock_free(drm_device_t *dev, -				   __volatile__ unsigned int *lock, -				   unsigned int context); -extern int	     drm_finish(struct inode *inode, struct file *filp, +extern int	     DRM(block)(struct inode *inode, struct file *filp,  				unsigned int cmd, unsigned long arg); -extern int	     drm_flush_unblock(drm_device_t *dev, int context, -				       drm_lock_flags_t flags); -extern int	     drm_flush_block_and_flush(drm_device_t *dev, int context, -					       drm_lock_flags_t flags); -extern int           drm_notifier(void *priv); +extern int	     DRM(unblock)(struct inode *inode, struct file *filp, +				  unsigned int cmd, unsigned long arg); +extern int	     DRM(lock_take)(__volatile__ unsigned int *lock, +				    unsigned int context); +extern int	     DRM(lock_transfer)(drm_device_t *dev, +					__volatile__ unsigned int *lock, +					unsigned int context); +extern int	     DRM(lock_free)(drm_device_t *dev, +				    __volatile__ unsigned int *lock, +				    unsigned int context); +extern int	     DRM(finish)(struct inode *inode, struct file *filp, +				 unsigned int cmd, unsigned long arg); +extern int	     DRM(flush_unblock)(drm_device_t *dev, int context, +					drm_lock_flags_t flags); +extern int	     DRM(flush_block_and_flush)(drm_device_t *dev, int context, +						drm_lock_flags_t flags); +extern int           DRM(notifier)(void *priv);  				/* Context Bitmap support (ctxbitmap.c) */ -extern int	     drm_ctxbitmap_init(drm_device_t *dev); -extern void	     drm_ctxbitmap_cleanup(drm_device_t *dev); -extern int	     drm_ctxbitmap_next(drm_device_t *dev); -extern void	     drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle); +extern int	     DRM(ctxbitmap_init)( drm_device_t *dev ); +extern void	     DRM(ctxbitmap_cleanup)( drm_device_t *dev ); -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) + + + +				/* Buffer management support (bufs.c) */ +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(addbufs)( struct inode *inode, struct file *filp, +				   unsigned int cmd, unsigned long arg ); +extern int	     DRM(infobufs)( struct inode *inode, struct file *filp, +				    unsigned int cmd, unsigned long arg ); +extern int	     DRM(markbufs)( struct inode *inode, struct file *filp, +				    unsigned int cmd, unsigned long arg ); +extern int	     DRM(freebufs)( struct inode *inode, struct file *filp, +				    unsigned int cmd, unsigned long arg ); +extern int	     DRM(mapbufs)( struct inode *inode, struct file *filp, +				   unsigned int cmd, unsigned long arg ); + + +#if __HAVE_DMA +				/* DMA support (dma.c) */ +extern int	     DRM(dma_setup)(drm_device_t *dev); +extern void	     DRM(dma_takedown)(drm_device_t *dev); +extern void	     DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); +extern void	     DRM(reclaim_buffers)(drm_device_t *dev, pid_t pid); +extern void	     DRM(clear_next_buffer)(drm_device_t *dev); +extern int	     DRM(select_queue)(drm_device_t *dev, +				       void (*wrapper)(unsigned long)); +extern int	     DRM(dma_enqueue)(drm_device_t *dev, drm_dma_t *dma); +#if 0 +extern int	     DRM(dma_get_buffers)(drm_device_t *dev, drm_dma_t *dma); +#endif +#if DRM_DMA_HISTOGRAM +extern int	     DRM(histogram_slot)(unsigned long count); +extern void	     DRM(histogram_compute)(drm_device_t *dev, drm_buf_t *buf); +#endif +#endif + +				/* Buffer list management support (lists.c) */ +#if __HAVE_DMA_WAITLIST +extern int	     DRM(waitlist_create)(drm_waitlist_t *bl, int count); +extern int	     DRM(waitlist_destroy)(drm_waitlist_t *bl); +extern int	     DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf); +extern drm_buf_t     *DRM(waitlist_get)(drm_waitlist_t *bl); +#endif +#if __HAVE_DMA_FREELIST +extern int	     DRM(freelist_create)(drm_freelist_t *bl, int count); +extern int	     DRM(freelist_destroy)(drm_freelist_t *bl); +extern int	     DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl, +				       drm_buf_t *buf); +extern drm_buf_t     *DRM(freelist_get)(drm_freelist_t *bl, int block); +#endif + +#if __REALLY_HAVE_AGP  				/* AGP/GART support (agpsupport.c) */ -extern drm_agp_head_t *drm_agp_init(void); -extern void           drm_agp_uninit(void); -extern int            drm_agp_acquire(struct inode *inode, struct file *filp, -				      unsigned int cmd, unsigned long arg); -extern void           _drm_agp_release(void); -extern int            drm_agp_release(struct inode *inode, struct file *filp, +extern drm_agp_head_t *DRM(agp_init)(void); +extern void           DRM(agp_uninit)(void); +extern int            DRM(agp_acquire)(struct inode *inode, struct file *filp, +				       unsigned int cmd, unsigned long arg); +extern void           DRM(agp_do_release)(void); +extern int            DRM(agp_release)(struct inode *inode, struct file *filp, +				       unsigned int cmd, unsigned long arg); +extern int            DRM(agp_enable)(struct inode *inode, struct file *filp,  				      unsigned int cmd, unsigned long arg); -extern int            drm_agp_enable(struct inode *inode, struct file *filp, -				     unsigned int cmd, unsigned long arg); -extern int            drm_agp_info(struct inode *inode, struct file *filp, -				   unsigned int cmd, unsigned long arg); -extern int            drm_agp_alloc(struct inode *inode, struct file *filp, +extern int            DRM(agp_info)(struct inode *inode, struct file *filp,  				    unsigned int cmd, unsigned long arg); -extern int            drm_agp_free(struct inode *inode, struct file *filp, -				   unsigned int cmd, unsigned long arg); -extern int            drm_agp_unbind(struct inode *inode, struct file *filp, +extern int            DRM(agp_alloc)(struct inode *inode, struct file *filp,  				     unsigned int cmd, unsigned long arg); -extern int            drm_agp_bind(struct inode *inode, struct file *filp, -				   unsigned int cmd, unsigned long arg); -extern agp_memory     *drm_agp_allocate_memory(size_t pages, u32 type); -extern int            drm_agp_free_memory(agp_memory *handle); -extern int            drm_agp_bind_memory(agp_memory *handle, off_t start); -extern int            drm_agp_unbind_memory(agp_memory *handle); +extern int            DRM(agp_free)(struct inode *inode, struct file *filp, +				    unsigned int cmd, unsigned long arg); +extern int            DRM(agp_unbind)(struct inode *inode, struct file *filp, +				      unsigned int cmd, unsigned long arg); +extern int            DRM(agp_bind)(struct inode *inode, struct file *filp, +				    unsigned int cmd, unsigned long arg); +extern agp_memory     *DRM(agp_allocate_memory)(size_t pages, u32 type); +extern int            DRM(agp_free_memory)(agp_memory *handle); +extern int            DRM(agp_bind_memory)(agp_memory *handle, off_t start); +extern int            DRM(agp_unbind_memory)(agp_memory *handle); + +				/* Stub support (drm_stub.h) */ +int                   DRM(stub_register)(const char *name, +					 struct file_operations *fops, +					 drm_device_t *dev); +int                   DRM(stub_unregister)(int minor); +  #endif  #endif  #endif diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c new file mode 100644 index 00000000..b070a59e --- /dev/null +++ b/linux-core/drm_agpsupport.c @@ -0,0 +1,335 @@ +/* drm_agpsupport.h -- DRM support for AGP/GART backend -*- linux-c -*- + * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Author: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include <linux/module.h> + +#if __REALLY_HAVE_AGP + +#if LINUX_VERSION_CODE < 0x020400 +#include "agpsupport-pre24.h" +#else +#define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp") +#define DRM_AGP_PUT inter_module_put("drm_agp") +#endif + +static const drm_agp_t *drm_agp = NULL; + +int DRM(agp_info)(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; +	agp_kern_info    *kern; +	drm_agp_info_t   info; + +	if (!dev->agp->acquired || !drm_agp->copy_info) return -EINVAL; + +	kern                   = &dev->agp->agp_info; +	info.agp_version_major = kern->version.major; +	info.agp_version_minor = kern->version.minor; +	info.mode              = kern->mode; +	info.aperture_base     = kern->aper_base; +	info.aperture_size     = kern->aper_size * 1024 * 1024; +	info.memory_allowed    = kern->max_memory << PAGE_SHIFT; +	info.memory_used       = kern->current_memory << PAGE_SHIFT; +	info.id_vendor         = kern->device->vendor; +	info.id_device         = kern->device->device; + +	if (copy_to_user((drm_agp_info_t *)arg, &info, sizeof(info))) +		return -EFAULT; +	return 0; +} + +int DRM(agp_acquire)(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; +	int              retcode; + +	if (dev->agp->acquired || !drm_agp->acquire) return -EINVAL; +	if ((retcode = drm_agp->acquire())) return retcode; +	dev->agp->acquired = 1; +	return 0; +} + +int DRM(agp_release)(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; + +	if (!dev->agp->acquired || !drm_agp->release) return -EINVAL; +	drm_agp->release(); +	dev->agp->acquired = 0; +	return 0; + +} + +void DRM(agp_do_release)(void) +{ +	if (drm_agp->release) drm_agp->release(); +} + +int DRM(agp_enable)(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_agp_mode_t   mode; + +	if (!dev->agp->acquired || !drm_agp->enable) return -EINVAL; + +	if (copy_from_user(&mode, (drm_agp_mode_t *)arg, sizeof(mode))) +		return -EFAULT; + +	dev->agp->mode    = mode.mode; +	drm_agp->enable(mode.mode); +	dev->agp->base    = dev->agp->agp_info.aper_base; +	dev->agp->enabled = 1; +	return 0; +} + +int DRM(agp_alloc)(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_agp_buffer_t request; +	drm_agp_mem_t    *entry; +	agp_memory       *memory; +	unsigned long    pages; +	u32 		 type; + +	if (!dev->agp->acquired) return -EINVAL; +	if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request))) +		return -EFAULT; +	if (!(entry = DRM(alloc)(sizeof(*entry), DRM_MEM_AGPLISTS))) +		return -ENOMEM; + +   	memset(entry, 0, sizeof(*entry)); + +	pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; +	type = (u32) request.type; + +	if (!(memory = DRM(alloc_agp)(pages, type))) { +		DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS); +		return -ENOMEM; +	} + +	entry->handle    = (unsigned long)memory->memory; +	entry->memory    = memory; +	entry->bound     = 0; +	entry->pages     = pages; +	entry->prev      = NULL; +	entry->next      = dev->agp->memory; +	if (dev->agp->memory) dev->agp->memory->prev = entry; +	dev->agp->memory = entry; + +	request.handle   = entry->handle; +        request.physical = memory->physical; + +	if (copy_to_user((drm_agp_buffer_t *)arg, &request, sizeof(request))) { +		dev->agp->memory       = entry->next; +		dev->agp->memory->prev = NULL; +		DRM(free_agp)(memory, pages); +		DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS); +		return -EFAULT; +	} +	return 0; +} + +static drm_agp_mem_t *DRM(agp_lookup_entry)(drm_device_t *dev, +					    unsigned long handle) +{ +	drm_agp_mem_t *entry; + +	for (entry = dev->agp->memory; entry; entry = entry->next) { +		if (entry->handle == handle) return entry; +	} +	return NULL; +} + +int DRM(agp_unbind)(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_agp_binding_t request; +	drm_agp_mem_t     *entry; + +	if (!dev->agp->acquired) return -EINVAL; +	if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request))) +		return -EFAULT; +	if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) +		return -EINVAL; +	if (!entry->bound) return -EINVAL; +	return DRM(unbind_agp)(entry->memory); +} + +int DRM(agp_bind)(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_agp_binding_t request; +	drm_agp_mem_t     *entry; +	int               retcode; +	int               page; + +	if (!dev->agp->acquired || !drm_agp->bind_memory) return -EINVAL; +	if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request))) +		return -EFAULT; +	if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) +		return -EINVAL; +	if (entry->bound) return -EINVAL; +	page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE; +	if ((retcode = DRM(bind_agp)(entry->memory, page))) return retcode; +	entry->bound = dev->agp->base + (page << PAGE_SHIFT); +	DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", +		  dev->agp->base, entry->bound); +	return 0; +} + +int DRM(agp_free)(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_agp_buffer_t request; +	drm_agp_mem_t    *entry; + +	if (!dev->agp->acquired) return -EINVAL; +	if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request))) +		return -EFAULT; +	if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) +		return -EINVAL; +	if (entry->bound) DRM(unbind_agp)(entry->memory); + +	if (entry->prev) entry->prev->next = entry->next; +	else             dev->agp->memory  = entry->next; +	if (entry->next) entry->next->prev = entry->prev; +	DRM(free_agp)(entry->memory, entry->pages); +	DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS); +	return 0; +} + +drm_agp_head_t *DRM(agp_init)(void) +{ +	drm_agp_head_t *head         = NULL; + +	drm_agp = DRM_AGP_GET; +	if (drm_agp) { +		if (!(head = DRM(alloc)(sizeof(*head), DRM_MEM_AGPLISTS))) +			return NULL; +		memset((void *)head, 0, sizeof(*head)); +		drm_agp->copy_info(&head->agp_info); +		if (head->agp_info.chipset == NOT_SUPPORTED) { +			DRM(free)(head, sizeof(*head), DRM_MEM_AGPLISTS); +			return NULL; +		} +		head->memory = NULL; +		switch (head->agp_info.chipset) { +		case INTEL_GENERIC:	head->chipset = "Intel";         break; +		case INTEL_LX:		head->chipset = "Intel 440LX";   break; +		case INTEL_BX:		head->chipset = "Intel 440BX";   break; +		case INTEL_GX:		head->chipset = "Intel 440GX";   break; +		case INTEL_I810:	head->chipset = "Intel i810";    break; + +#if LINUX_VERSION_CODE >= 0x020400 +		case INTEL_I840:	head->chipset = "Intel i840";    break; +#endif + +		case VIA_GENERIC:	head->chipset = "VIA";           break; +		case VIA_VP3:		head->chipset = "VIA VP3";       break; +		case VIA_MVP3:		head->chipset = "VIA MVP3";      break; + +#if LINUX_VERSION_CODE >= 0x020400 +		case VIA_MVP4:		head->chipset = "VIA MVP4";      break; +		case VIA_APOLLO_KX133:	head->chipset = "VIA Apollo KX133"; +			break; +		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133"; +			break; +#endif + +		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro"; +			break; +		case SIS_GENERIC:	head->chipset = "SiS";           break; +		case AMD_GENERIC:	head->chipset = "AMD";           break; +		case AMD_IRONGATE:	head->chipset = "AMD Irongate";  break; +		case ALI_GENERIC:	head->chipset = "ALi";           break; +		case ALI_M1541: 	head->chipset = "ALi M1541";     break; +		default:		head->chipset = "Unknown";       break; +		} +		DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n", +			 head->agp_info.version.major, +			 head->agp_info.version.minor, +			 head->chipset, +			 head->agp_info.aper_base, +			 head->agp_info.aper_size); +	} +	return head; +} + +void DRM(agp_uninit)(void) +{ +	DRM_AGP_PUT; +	drm_agp = NULL; +} + +agp_memory *DRM(agp_allocate_memory)(size_t pages, u32 type) +{ +	if (!drm_agp->allocate_memory) return NULL; +	return drm_agp->allocate_memory(pages, type); +} + +int DRM(agp_free_memory)(agp_memory *handle) +{ +	if (!handle || !drm_agp->free_memory) return 0; +	drm_agp->free_memory(handle); +	return 1; +} + +int DRM(agp_bind_memory)(agp_memory *handle, off_t start) +{ +	if (!handle || !drm_agp->bind_memory) return -EINVAL; +	return drm_agp->bind_memory(handle, start); +} + +int DRM(agp_unbind_memory)(agp_memory *handle) +{ +	if (!handle || !drm_agp->unbind_memory) return -EINVAL; +	return drm_agp->unbind_memory(handle); +} + +#endif /* __REALLY_HAVE_AGP */ diff --git a/linux-core/drm_auth.c b/linux-core/drm_auth.c new file mode 100644 index 00000000..2636e617 --- /dev/null +++ b/linux-core/drm_auth.c @@ -0,0 +1,162 @@ +/* drm_auth.h -- IOCTLs for authentication -*- linux-c -*- + * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include "drmP.h" + +static int DRM(hash_magic)(drm_magic_t magic) +{ +	return magic & (DRM_HASH_SIZE-1); +} + +static drm_file_t *DRM(find_file)(drm_device_t *dev, drm_magic_t magic) +{ +	drm_file_t	  *retval = NULL; +	drm_magic_entry_t *pt; +	int		  hash	  = DRM(hash_magic)(magic); + +	down(&dev->struct_sem); +	for (pt = dev->magiclist[hash].head; pt; pt = pt->next) { +		if (pt->magic == magic) { +			retval = pt->priv; +			break; +		} +	} +	up(&dev->struct_sem); +	return retval; +} + +int DRM(add_magic)(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic) +{ +	int		  hash; +	drm_magic_entry_t *entry; + +	DRM_DEBUG("%d\n", magic); + +	hash	     = DRM(hash_magic)(magic); +	entry	     = DRM(alloc)(sizeof(*entry), DRM_MEM_MAGIC); +	if (!entry) return -ENOMEM; +	entry->magic = magic; +	entry->priv  = priv; +	entry->next  = NULL; + +	down(&dev->struct_sem); +	if (dev->magiclist[hash].tail) { +		dev->magiclist[hash].tail->next = entry; +		dev->magiclist[hash].tail	= entry; +	} else { +		dev->magiclist[hash].head	= entry; +		dev->magiclist[hash].tail	= entry; +	} +	up(&dev->struct_sem); + +	return 0; +} + +int DRM(remove_magic)(drm_device_t *dev, drm_magic_t magic) +{ +	drm_magic_entry_t *prev = NULL; +	drm_magic_entry_t *pt; +	int		  hash; + +	DRM_DEBUG("%d\n", magic); +	hash = DRM(hash_magic)(magic); + +	down(&dev->struct_sem); +	for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) { +		if (pt->magic == magic) { +			if (dev->magiclist[hash].head == pt) { +				dev->magiclist[hash].head = pt->next; +			} +			if (dev->magiclist[hash].tail == pt) { +				dev->magiclist[hash].tail = prev; +			} +			if (prev) { +				prev->next = pt->next; +			} +			up(&dev->struct_sem); +			return 0; +		} +	} +	up(&dev->struct_sem); + +	DRM(free)(pt, sizeof(*pt), DRM_MEM_MAGIC); + +	return -EINVAL; +} + +int DRM(getmagic)(struct inode *inode, struct file *filp, +		  unsigned int cmd, unsigned long arg) +{ +	static drm_magic_t sequence = 0; +	static spinlock_t  lock	    = SPIN_LOCK_UNLOCKED; +	drm_file_t	   *priv    = filp->private_data; +	drm_device_t	   *dev	    = priv->dev; +	drm_auth_t	   auth; + +				/* Find unique magic */ +	if (priv->magic) { +		auth.magic = priv->magic; +	} else { +		do { +			spin_lock(&lock); +			if (!sequence) ++sequence; /* reserve 0 */ +			auth.magic = sequence++; +			spin_unlock(&lock); +		} while (DRM(find_file)(dev, auth.magic)); +		priv->magic = auth.magic; +		DRM(add_magic)(dev, priv, auth.magic); +	} + +	DRM_DEBUG("%u\n", auth.magic); +	if (copy_to_user((drm_auth_t *)arg, &auth, sizeof(auth))) +		return -EFAULT; +	return 0; +} + +int DRM(authmagic)(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_auth_t	   auth; +	drm_file_t	   *file; + +	if (copy_from_user(&auth, (drm_auth_t *)arg, sizeof(auth))) +		return -EFAULT; +	DRM_DEBUG("%u\n", auth.magic); +	if ((file = DRM(find_file)(dev, auth.magic))) { +		file->authenticated = 1; +		DRM(remove_magic)(dev, auth.magic); +		return 0; +	} +	return -EINVAL; +} diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c new file mode 100644 index 00000000..f2613a98 --- /dev/null +++ b/linux-core/drm_bufs.c @@ -0,0 +1,757 @@ +/* drm_bufs.h -- Generic buffer template -*- linux-c -*- + * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include "drmP.h" + +#ifndef __HAVE_PCI_DMA +#define __HAVE_PCI_DMA		0 +#endif + +#ifndef DRIVER_BUF_PRIV_T +#define DRIVER_BUF_PRIV_T		u32 +#endif +#ifndef DRIVER_AGP_BUFFERS_MAP +#if __HAVE_AGP && __HAVE_DMA +#error "You must define DRIVER_AGP_BUFFERS_MAP()" +#else +#define DRIVER_AGP_BUFFERS_MAP( dev )	NULL +#endif +#endif + +/* + * Compute order.  Can be made faster. + */ +int DRM(order)( unsigned long size ) +{ +	int order; +	unsigned long tmp; + +	for ( order = 0, tmp = size ; tmp >>= 1 ; ++order ); + +	if ( size & ~(1 << order) ) +		++order; + +	return order; +} + +int DRM(addmap)( 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_map_t *map; + +	if ( !(filp->f_mode & 3) ) return -EACCES; /* Require read/write */ + +	map = DRM(alloc)( sizeof(*map), DRM_MEM_MAPS ); +	if ( !map ) +		return -ENOMEM; + +	if ( copy_from_user( map, (drm_map_t *)arg, sizeof(*map) ) ) { +		DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); +		return -EFAULT; +	} + +	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)) ) { +		DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); +		return -EINVAL; +	} +	map->mtrr   = -1; +	map->handle = 0; + +	switch ( map->type ) { +	case _DRM_REGISTERS: +	case _DRM_FRAME_BUFFER: +#ifndef __sparc__ +		if ( map->offset + map->size < map->offset || +		     map->offset < virt_to_phys(high_memory) ) { +			DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); +			return -EINVAL; +		} +#endif +#ifdef CONFIG_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 +		map->handle = DRM(ioremap)( map->offset, map->size ); +		break; + +	case _DRM_SHM: +		map->handle = (void *)DRM(alloc_pages)( DRM(order)( map->size ) +						       - PAGE_SHIFT, +						       DRM_MEM_SAREA ); +		DRM_DEBUG( "%ld %d %p\n", +			   map->size, DRM(order)( map->size ), map->handle ); +		if ( !map->handle ) { +			DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); +			return -ENOMEM; +		} +		map->offset = (unsigned long)map->handle; +		if ( map->flags & _DRM_CONTAINS_LOCK ) { +			dev->lock.hw_lock = map->handle; /* Pointer to lock */ +		} +		break; +#if __REALLY_HAVE_AGP +	case _DRM_AGP: +		map->offset = map->offset + dev->agp->base; +		break; +#endif +	default: +		DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); +		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 ); +	} +	dev->maplist[dev->map_count-1] = map; +	up( &dev->struct_sem ); + +	if ( copy_to_user( (drm_map_t *)arg, map, sizeof(*map) ) ) +		return -EFAULT; +	if ( map->type != _DRM_SHM ) { +		if ( copy_to_user( &((drm_map_t *)arg)->handle, +				   &map->offset, +				   sizeof(map->offset) ) ) +			return -EFAULT; +	} +	return 0; +} + +#if __HAVE_DMA + +#if __REALLY_HAVE_AGP +int DRM(addbufs_agp)( 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_device_dma_t *dma = dev->dma; +	drm_buf_desc_t request; +	drm_buf_entry_t *entry; +	drm_buf_t *buf; +	unsigned long offset; +	unsigned long agp_offset; +	int count; +	int order; +	int size; +	int alignment; +	int page_order; +	int total; +	int byte_count; +	int i; + +	if ( !dma ) return -EINVAL; + +	if ( copy_from_user( &request, (drm_buf_desc_t *)arg, +			     sizeof(request) ) ) +		return -EFAULT; + +	count = request.count; +	order = DRM(order)( request.size ); +	size = 1 << order; + +	alignment  = (request.flags & _DRM_PAGE_ALIGN) +		? PAGE_ALIGN(size) : size; +	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; +	total = PAGE_SIZE << page_order; + +	byte_count = 0; +	agp_offset = dev->agp->base + request.agp_start; + +	DRM_DEBUG( "count:      %d\n",  count ); +	DRM_DEBUG( "order:      %d\n",  order ); +	DRM_DEBUG( "size:       %d\n",  size ); +	DRM_DEBUG( "agp_offset: %ld\n", agp_offset ); +	DRM_DEBUG( "alignment:  %d\n",  alignment ); +	DRM_DEBUG( "page_order: %d\n",  page_order ); +	DRM_DEBUG( "total:      %d\n",  total ); + +	if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL; +	if ( dev->queue_count ) return -EBUSY; /* Not while in use */ + +	spin_lock( &dev->count_lock ); +	if ( dev->buf_use ) { +		spin_unlock( &dev->count_lock ); +		return -EBUSY; +	} +	atomic_inc( &dev->buf_alloc ); +	spin_unlock( &dev->count_lock ); + +	down( &dev->struct_sem ); +	entry = &dma->bufs[order]; +	if ( entry->buf_count ) { +		up( &dev->struct_sem ); +		atomic_dec( &dev->buf_alloc ); +		return -ENOMEM; /* May only call once for each order */ +	} + +	entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist), +				    DRM_MEM_BUFS ); +	if ( !entry->buflist ) { +		up( &dev->struct_sem ); +		atomic_dec( &dev->buf_alloc ); +		return -ENOMEM; +	} +	memset( entry->buflist, 0, count * sizeof(*entry->buflist) ); + +	entry->buf_size = size; +	entry->page_order = page_order; + +	offset = 0; + +	while ( entry->buf_count < count ) { +		buf          = &entry->buflist[entry->buf_count]; +		buf->idx     = dma->buf_count + entry->buf_count; +		buf->total   = alignment; +		buf->order   = order; +		buf->used    = 0; + +		buf->offset  = (dma->byte_count + offset); /* ******** */ +		buf->bus_address = agp_offset + offset; +		buf->address = (void *)(agp_offset + offset); +		buf->next    = NULL; +		buf->waiting = 0; +		buf->pending = 0; +		init_waitqueue_head( &buf->dma_wait ); +		buf->pid     = 0; + +		buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); +		buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), +					       DRM_MEM_BUFS ); +		memset( buf->dev_private, 0, buf->dev_priv_size ); + +#if DRM_DMA_HISTOGRAM +		buf->time_queued = 0; +		buf->time_dispatched = 0; +		buf->time_completed = 0; +		buf->time_freed = 0; +#endif +		DRM_DEBUG( "buffer %d @ %p\n", +			   entry->buf_count, buf->address ); + +		offset += alignment; +		entry->buf_count++; +		byte_count += PAGE_SIZE << page_order; +	} + +	DRM_DEBUG( "byte_count: %d\n", byte_count ); + +	dma->buflist = DRM(realloc)( dma->buflist, +				     dma->buf_count * sizeof(*dma->buflist), +				     (dma->buf_count + entry->buf_count) +				     * sizeof(*dma->buflist), +				     DRM_MEM_BUFS ); +	for ( i = 0 ; i < entry->buf_count ; i++ ) { +		dma->buflist[i + dma->buf_count] = &entry->buflist[i]; +	} + +	dma->buf_count += entry->buf_count; +	dma->byte_count += byte_count; + +	DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); +	DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); + +/* GH: Please leave this disabled for now.  I need to fix this properly... + */ +#if 0 +	/* FIXME: work this mess out... +	 */ +	DRM(freelist_create)( &entry->freelist, entry->buf_count ); +	for ( i = 0 ; i < entry->buf_count ; i++ ) { +		DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] ); +	} +#endif + +	up( &dev->struct_sem ); + +	request.count = entry->buf_count; +	request.size = size; + +	if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) ) +		return -EFAULT; + +	dma->flags = _DRM_DMA_USE_AGP; + +	atomic_dec( &dev->buf_alloc ); +	return 0; +} +#endif /* __REALLY_HAVE_AGP */ + +#if __HAVE_PCI_DMA +int DRM(addbufs_pci)( 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_device_dma_t *dma = dev->dma; +	drm_buf_desc_t request; +	int count; +	int order; +	int size; +	int total; +	int page_order; +	drm_buf_entry_t *entry; +	unsigned long page; +	drm_buf_t *buf; +	int alignment; +	unsigned long offset; +	int i; +	int byte_count; +	int page_count; + +	if ( !dma ) return -EINVAL; + +	if ( copy_from_user( &request, (drm_buf_desc_t *)arg, +			     sizeof(request) ) ) +		return -EFAULT; + +	count = request.count; +	order = DRM(order)( request.size ); +	size = 1 << order; + +	DRM_DEBUG( "count=%d, size=%d (%d), order=%d, queue_count=%d\n", +		   request.count, request.size, size, +		   order, dev->queue_count ); + +	if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL; +	if ( dev->queue_count ) return -EBUSY; /* Not while in use */ + +	alignment = (request.flags & _DRM_PAGE_ALIGN) +		? PAGE_ALIGN(size) : size; +	page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; +	total = PAGE_SIZE << page_order; + +	spin_lock( &dev->count_lock ); +	if ( dev->buf_use ) { +		spin_unlock( &dev->count_lock ); +		return -EBUSY; +	} +	atomic_inc( &dev->buf_alloc ); +	spin_unlock( &dev->count_lock ); + +	down( &dev->struct_sem ); +	entry = &dma->bufs[order]; +	if ( entry->buf_count ) { +		up( &dev->struct_sem ); +		atomic_dec( &dev->buf_alloc ); +		return -ENOMEM;	/* May only call once for each order */ +	} + +	entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist), +				    DRM_MEM_BUFS ); +	if ( !entry->buflist ) { +		up( &dev->struct_sem ); +		atomic_dec( &dev->buf_alloc ); +		return -ENOMEM; +	} +	memset( entry->buflist, 0, count * sizeof(*entry->buflist) ); + +	entry->seglist = DRM(alloc)( count * sizeof(*entry->seglist), +				    DRM_MEM_SEGS ); +	if ( !entry->seglist ) { +		DRM(free)( entry->buflist, +			  count * sizeof(*entry->buflist), +			  DRM_MEM_BUFS ); +		up( &dev->struct_sem ); +		atomic_dec( &dev->buf_alloc ); +		return -ENOMEM; +	} +	memset( entry->seglist, 0, count * sizeof(*entry->seglist) ); + +	dma->pagelist = DRM(realloc)( dma->pagelist, +				      dma->page_count * sizeof(*dma->pagelist), +				      (dma->page_count + (count << page_order)) +				      * sizeof(*dma->pagelist), +				      DRM_MEM_PAGES ); +	DRM_DEBUG( "pagelist: %d entries\n", +		   dma->page_count + (count << page_order) ); + +	entry->buf_size	= size; +	entry->page_order = page_order; +	byte_count = 0; +	page_count = 0; + +	while ( entry->buf_count < count ) { +		page = DRM(alloc_pages)( page_order, DRM_MEM_DMA ); +		if ( !page ) break; +		entry->seglist[entry->seg_count++] = page; +		for ( i = 0 ; i < (1 << page_order) ; i++ ) { +			DRM_DEBUG( "page %d @ 0x%08lx\n", +				   dma->page_count + page_count, +				   page + PAGE_SIZE * i ); +			dma->pagelist[dma->page_count + page_count++] +				= page + PAGE_SIZE * i; +		} +		for ( offset = 0 ; +		      offset + size <= total && entry->buf_count < count ; +		      offset += alignment, ++entry->buf_count ) { +			buf	     = &entry->buflist[entry->buf_count]; +			buf->idx     = dma->buf_count + entry->buf_count; +			buf->total   = alignment; +			buf->order   = order; +			buf->used    = 0; +			buf->offset  = (dma->byte_count + byte_count + offset); +			buf->address = (void *)(page + offset); +			buf->next    = NULL; +			buf->waiting = 0; +			buf->pending = 0; +			init_waitqueue_head( &buf->dma_wait ); +			buf->pid     = 0; +#if DRM_DMA_HISTOGRAM +			buf->time_queued     = 0; +			buf->time_dispatched = 0; +			buf->time_completed  = 0; +			buf->time_freed	     = 0; +#endif +			DRM_DEBUG( "buffer %d @ %p\n", +				   entry->buf_count, buf->address ); +		} +		byte_count += PAGE_SIZE << page_order; +	} + +	dma->buflist = DRM(realloc)( dma->buflist, +				     dma->buf_count * sizeof(*dma->buflist), +				     (dma->buf_count + entry->buf_count) +				     * sizeof(*dma->buflist), +				     DRM_MEM_BUFS ); +	for ( i = 0 ; i < entry->buf_count ; i++ ) { +		dma->buflist[i + dma->buf_count] = &entry->buflist[i]; +	} + +	dma->buf_count += entry->buf_count; +	dma->seg_count += entry->seg_count; +	dma->page_count += entry->seg_count << page_order; +	dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); + +/* GH: Please leave this disabled for now.  I need to fix this properly... + */ +#if 0 +	/* FIXME: work this mess out... +	 */ +	DRM(freelist_create)( &entry->freelist, entry->buf_count ); +	for ( i = 0 ; i < entry->buf_count ; i++ ) { +		DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] ); +	} +#endif + +	up( &dev->struct_sem ); + +	request.count = entry->buf_count; +	request.size = size; + +	if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) ) +		return -EFAULT; + +	atomic_dec( &dev->buf_alloc ); +	return 0; +} +#endif /* __HAVE_PCI_DMA */ + +int DRM(addbufs)( struct inode *inode, struct file *filp, +		  unsigned int cmd, unsigned long arg ) +{ +	drm_buf_desc_t request; + +	if ( copy_from_user( &request, (drm_buf_desc_t *)arg, +			     sizeof(request) ) ) +		return -EFAULT; + +#if __REALLY_HAVE_AGP +	if ( request.flags & _DRM_AGP_BUFFER ) +		return DRM(addbufs_agp)( inode, filp, cmd, arg ); +	else +#endif +#if __HAVE_PCI_DMA +		return DRM(addbufs_pci)( inode, filp, cmd, arg ); +#else +		return -EINVAL; +#endif +} + +int DRM(infobufs)( 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_device_dma_t *dma = dev->dma; +	drm_buf_info_t request; +	int i; +	int count; + +	if ( !dma ) return -EINVAL; + +	spin_lock( &dev->count_lock ); +	if ( atomic_read( &dev->buf_alloc ) ) { +		spin_unlock( &dev->count_lock ); +		return -EBUSY; +	} +	++dev->buf_use;		/* Can't allocate more after this call */ +	spin_unlock( &dev->count_lock ); + +	if ( copy_from_user( &request, +			     (drm_buf_info_t *)arg, +			     sizeof(request) ) ) +		return -EFAULT; + +	for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) { +		if ( dma->bufs[i].buf_count ) ++count; +	} + +	DRM_DEBUG( "count = %d\n", count ); + +	if ( request.count >= count ) { +		for ( i = 0, count = 0 ; i < DRM_MAX_ORDER + 1 ; i++ ) { +			if ( dma->bufs[i].buf_count ) { +				drm_buf_desc_t *to = &request.list[count]; +				drm_buf_entry_t *from = &dma->bufs[i]; +				drm_freelist_t *list = &dma->bufs[i].freelist; +				if ( copy_to_user( &to->count, +						   &from->buf_count, +						   sizeof(from->buf_count) ) || +				     copy_to_user( &to->size, +						   &from->buf_size, +						   sizeof(from->buf_size) ) || +				     copy_to_user( &to->low_mark, +						   &list->low_mark, +						   sizeof(list->low_mark) ) || +				     copy_to_user( &to->high_mark, +						   &list->high_mark, +						   sizeof(list->high_mark) ) ) +					return -EFAULT; + +				DRM_DEBUG( "%d %d %d %d %d\n", +					   i, +					   dma->bufs[i].buf_count, +					   dma->bufs[i].buf_size, +					   dma->bufs[i].freelist.low_mark, +					   dma->bufs[i].freelist.high_mark ); +				++count; +			} +		} +	} +	request.count = count; + +	if ( copy_to_user( (drm_buf_info_t *)arg, +			   &request, +			   sizeof(request) ) ) +		return -EFAULT; + +	return 0; +} + +int DRM(markbufs)( 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_device_dma_t *dma = dev->dma; +	drm_buf_desc_t request; +	int order; +	drm_buf_entry_t *entry; + +	if ( !dma ) return -EINVAL; + +	if ( copy_from_user( &request, +			     (drm_buf_desc_t *)arg, +			     sizeof(request) ) ) +		return -EFAULT; + +	DRM_DEBUG( "%d, %d, %d\n", +		   request.size, request.low_mark, request.high_mark ); +	order = DRM(order)( request.size ); +	if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL; +	entry = &dma->bufs[order]; + +	if ( request.low_mark < 0 || request.low_mark > entry->buf_count ) +		return -EINVAL; +	if ( request.high_mark < 0 || request.high_mark > entry->buf_count ) +		return -EINVAL; + +	entry->freelist.low_mark  = request.low_mark; +	entry->freelist.high_mark = request.high_mark; + +	return 0; +} + +int DRM(freebufs)( 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_device_dma_t *dma = dev->dma; +	drm_buf_free_t request; +	int i; +	int idx; +	drm_buf_t *buf; + +	if ( !dma ) return -EINVAL; + +	if ( copy_from_user( &request, +			     (drm_buf_free_t *)arg, +			     sizeof(request) ) ) +		return -EFAULT; + +	DRM_DEBUG( "%d\n", request.count ); +	for ( i = 0 ; i < request.count ; i++ ) { +		if ( copy_from_user( &idx, +				     &request.list[i], +				     sizeof(idx) ) ) +			return -EFAULT; +		if ( idx < 0 || idx >= dma->buf_count ) { +			DRM_ERROR( "Index %d (of %d max)\n", +				   idx, dma->buf_count - 1 ); +			return -EINVAL; +		} +		buf = dma->buflist[idx]; +		if ( buf->pid != current->pid ) { +			DRM_ERROR( "Process %d freeing buffer owned by %d\n", +				   current->pid, buf->pid ); +			return -EINVAL; +		} +		DRM(free_buffer)( dev, buf ); +	} + +	return 0; +} + +int DRM(mapbufs)( 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_device_dma_t *dma = dev->dma; +	int retcode = 0; +	const int zero = 0; +	unsigned long virtual; +	unsigned long address; +	drm_buf_map_t request; +	int i; + +	if ( !dma ) return -EINVAL; + +	spin_lock( &dev->count_lock ); +	if ( atomic_read( &dev->buf_alloc ) ) { +		spin_unlock( &dev->count_lock ); +		return -EBUSY; +	} +	dev->buf_use++;		/* Can't allocate more after this call */ +	spin_unlock( &dev->count_lock ); + +	if ( copy_from_user( &request, (drm_buf_map_t *)arg, +			     sizeof(request) ) ) +		return -EFAULT; + +	if ( request.count >= dma->buf_count ) { +		if ( __HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP) ) { +			drm_map_t *map = DRIVER_AGP_BUFFERS_MAP( dev ); + +			if ( !map ) { +				retcode = -EINVAL; +				goto done; +			} + +			down( ¤t->mm->mmap_sem ); +			virtual = do_mmap( filp, 0, map->size, +					   PROT_READ | PROT_WRITE, +					   MAP_SHARED, +					   (unsigned long)map->offset ); +			up( ¤t->mm->mmap_sem ); +		} else { +			down( ¤t->mm->mmap_sem ); +			virtual = do_mmap( filp, 0, dma->byte_count, +					   PROT_READ | PROT_WRITE, +					   MAP_SHARED, 0 ); +			up( ¤t->mm->mmap_sem ); +		} +		if ( virtual > -1024UL ) { +			/* Real error */ +			retcode = (signed long)virtual; +			goto done; +		} +		request.virtual = (void *)virtual; + +		for ( i = 0 ; i < dma->buf_count ; i++ ) { +			if ( copy_to_user( &request.list[i].idx, +					   &dma->buflist[i]->idx, +					   sizeof(request.list[0].idx) ) ) { +				retcode = -EFAULT; +				goto done; +			} +			if ( copy_to_user( &request.list[i].total, +					   &dma->buflist[i]->total, +					   sizeof(request.list[0].total) ) ) { +				retcode = -EFAULT; +				goto done; +			} +			if ( copy_to_user( &request.list[i].used, +					   &zero, +					   sizeof(zero) ) ) { +				retcode = -EFAULT; +				goto done; +			} +			address = virtual + dma->buflist[i]->offset; /* *** */ +			if ( copy_to_user( &request.list[i].address, +					   &address, +					   sizeof(address) ) ) { +				retcode = -EFAULT; +				goto done; +			} +		} +	} + done: +	request.count = dma->buf_count; +	DRM_DEBUG( "%d buffers, retcode = %d\n", request.count, retcode ); + +	if ( copy_to_user( (drm_buf_map_t *)arg, &request, sizeof(request) ) ) +		return -EFAULT; + +	return retcode; +} + +#endif /* __HAVE_DMA */ diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c new file mode 100644 index 00000000..6bbcfca8 --- /dev/null +++ b/linux-core/drm_context.c @@ -0,0 +1,270 @@ +/* drm_context.h -- IOCTLs for generic contexts -*- linux-c -*- + * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +/* ================================================================ + * Context bitmap support + */ + +void DRM(ctxbitmap_free)( drm_device_t *dev, int ctx_handle ) +{ +	if ( ctx_handle < 0 ) goto failed; + +	if ( ctx_handle < DRM_MAX_CTXBITMAP ) { +		clear_bit( ctx_handle, dev->ctx_bitmap ); +		return; +	} +failed: +       	DRM_ERROR( "Attempt to free invalid context handle: %d\n", +		   ctx_handle ); +       	return; +} + +int DRM(ctxbitmap_next)( drm_device_t *dev ) +{ +	int bit; + +	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 ); +		return bit; +	} +	return -1; +} + +int DRM(ctxbitmap_init)( drm_device_t *dev ) +{ +	int i; +   	int temp; + +	dev->ctx_bitmap = (unsigned long *) DRM(alloc)( PAGE_SIZE, +							DRM_MEM_CTXBITMAP ); +	if ( dev->ctx_bitmap == NULL ) { +		return -ENOMEM; +	} +	memset( (void *)dev->ctx_bitmap, 0, PAGE_SIZE ); +	for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) { +		temp = DRM(ctxbitmap_next)( dev ); +	   	DRM_DEBUG( "drm_ctxbitmap_init : %d\n", temp ); +	} + +	return 0; +} + +void DRM(ctxbitmap_cleanup)( drm_device_t *dev ) +{ +	DRM(free)( (void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP ); +} + + +/* ================================================================ + * The actual DRM context handling routines + */ + +int DRM(context_switch)( drm_device_t *dev, int old, int new ) +{ +        char buf[64]; + +        if ( test_and_set_bit( 0, &dev->context_flag ) ) { +                DRM_ERROR( "Reentering -- FIXME\n" ); +                return -EBUSY; +        } + +#if DRM_DMA_HISTOGRAM +        dev->ctx_start = get_cycles(); +#endif + +        DRM_DEBUG( "Context switch from %d to %d\n", old, new ); + +        if ( new == dev->last_context ) { +                clear_bit( 0, &dev->context_flag ); +                return 0; +        } + +        if ( DRM(flags) & DRM_FLAG_NOCTX ) { +                DRM(context_switch_complete)( dev, new ); +        } else { +                sprintf( buf, "C %d %d\n", old, new ); +                DRM(write_string)( dev, buf ); +        } + +        return 0; +} + +int DRM(context_switch_complete)( drm_device_t *dev, int new ) +{ +        dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */ +        dev->last_switch  = jiffies; + +        if ( !_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ) { +                DRM_ERROR( "Lock isn't held after context switch\n" ); +        } + +				/* If a context switch is ever initiated +                                   when the kernel holds the lock, release +                                   that lock here. */ +#if DRM_DMA_HISTOGRAM +        atomic_inc( &dev->histo.ctx[DRM(histogram_slot)(get_cycles() +							- dev->ctx_start)] ); + +#endif +        clear_bit( 0, &dev->context_flag ); +        wake_up( &dev->context_wait ); + +        return 0; +} + +int DRM(resctx)( struct inode *inode, struct file *filp, +		 unsigned int cmd, unsigned long arg ) +{ +	drm_ctx_res_t res; +	drm_ctx_t ctx; +	int i; + +	if ( copy_from_user( &res, (drm_ctx_res_t *)arg, sizeof(res) ) ) +		return -EFAULT; + +	if ( res.count >= DRM_RESERVED_CONTEXTS ) { +		memset( &ctx, 0, sizeof(ctx) ); +		for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) { +			ctx.handle = i; +			if ( copy_to_user( &res.contexts[i], +					   &i, sizeof(i) ) ) +				return -EFAULT; +		} +	} +	res.count = DRM_RESERVED_CONTEXTS; + +	if ( copy_to_user( (drm_ctx_res_t *)arg, &res, sizeof(res) ) ) +		return -EFAULT; +	return 0; +} + +int DRM(addctx)( 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_t ctx; + +	if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) ) +		return -EFAULT; + +	ctx.handle = DRM(ctxbitmap_next)( dev ); +	if ( ctx.handle == DRM_KERNEL_CONTEXT ) { +				/* Skip kernel's context and get a new one. */ +		ctx.handle = DRM(ctxbitmap_next)( dev ); +	} +	DRM_DEBUG( "%d\n", ctx.handle ); +	if ( ctx.handle == -1 ) { +		DRM_DEBUG( "Not enough free contexts.\n" ); +				/* Should this return -EBUSY instead? */ +		return -ENOMEM; +	} + +	if ( copy_to_user( (drm_ctx_t *)arg, &ctx, sizeof(ctx) ) ) +		return -EFAULT; +	return 0; +} + +int DRM(modctx)( struct inode *inode, struct file *filp, +		 unsigned int cmd, unsigned long arg ) +{ +	/* This does nothing */ +	return 0; +} + +int DRM(getctx)( struct inode *inode, struct file *filp, +		 unsigned int cmd, unsigned long arg ) +{ +	drm_ctx_t ctx; + +	if ( copy_from_user( &ctx, (drm_ctx_t*)arg, sizeof(ctx) ) ) +		return -EFAULT; + +	/* This is 0, because we don't handle any context flags */ +	ctx.flags = 0; + +	if ( copy_to_user( (drm_ctx_t*)arg, &ctx, sizeof(ctx) ) ) +		return -EFAULT; +	return 0; +} + +int DRM(switchctx)( 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_t ctx; + +	if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) ) +		return -EFAULT; + +	DRM_DEBUG( "%d\n", ctx.handle ); +	return DRM(context_switch)( dev, dev->last_context, ctx.handle ); +} + +int DRM(newctx)( 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_t ctx; + +	if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) ) +		return -EFAULT; + +	DRM_DEBUG( "%d\n", ctx.handle ); +	DRM(context_switch_complete)( dev, ctx.handle ); + +	return 0; +} + +int DRM(rmctx)( 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_t ctx; + +	if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) ) +		return -EFAULT; + +	DRM_DEBUG( "%d\n", ctx.handle ); +	if ( ctx.handle == DRM_KERNEL_CONTEXT + 1 ) { +		priv->remove_auth_on_close = 1; +	} +	if ( ctx.handle != DRM_KERNEL_CONTEXT ) { +		DRM(ctxbitmap_free)( dev, ctx.handle ); +	} + +	return 0; +} diff --git a/linux-core/drm_dma.c b/linux-core/drm_dma.c new file mode 100644 index 00000000..35eb896e --- /dev/null +++ b/linux-core/drm_dma.c @@ -0,0 +1,576 @@ +/* drm_dma.c -- DMA IOCTL and function support -*- linux-c -*- + * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include "drmP.h" + +#include <linux/interrupt.h>	/* For task queue support */ + +#ifndef __HAVE_DMA_WAITQUEUE +#define __HAVE_DMA_WAITQUEUE	0 +#endif +#ifndef __HAVE_DMA_RECLAIM +#define __HAVE_DMA_RECLAIM	0 +#endif + +#if __HAVE_DMA + +int DRM(dma_setup)( drm_device_t *dev ) +{ +	int i; + +	dev->dma = DRM(alloc)( sizeof(*dev->dma), DRM_MEM_DRIVER ); +	if ( !dev->dma ) +		return -ENOMEM; + +	memset( dev->dma, 0, sizeof(*dev->dma) ); + +	for ( i = 0 ; i <= DRM_MAX_ORDER ; i++ ) +		memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); + +	return 0; +} + +void DRM(dma_takedown)(drm_device_t *dev) +{ +	drm_device_dma_t  *dma = dev->dma; +	int		  i, j; + +	if (!dma) return; + +				/* Clear dma buffers */ +	for (i = 0; i <= DRM_MAX_ORDER; i++) { +		if (dma->bufs[i].seg_count) { +			DRM_DEBUG("order %d: buf_count = %d," +				  " seg_count = %d\n", +				  i, +				  dma->bufs[i].buf_count, +				  dma->bufs[i].seg_count); +			for (j = 0; j < dma->bufs[i].seg_count; j++) { +				DRM(free_pages)(dma->bufs[i].seglist[j], +						dma->bufs[i].page_order, +						DRM_MEM_DMA); +			} +			DRM(free)(dma->bufs[i].seglist, +				  dma->bufs[i].seg_count +				  * sizeof(*dma->bufs[0].seglist), +				  DRM_MEM_SEGS); +		} +	   	if(dma->bufs[i].buf_count) { +		   	for(j = 0; j < dma->bufs[i].buf_count; j++) { +			   if(dma->bufs[i].buflist[j].dev_private) { +			      DRM(free)(dma->bufs[i].buflist[j].dev_private, +					dma->bufs[i].buflist[j].dev_priv_size, +					DRM_MEM_BUFS); +			   } +			} +		   	DRM(free)(dma->bufs[i].buflist, +				  dma->bufs[i].buf_count * +				  sizeof(*dma->bufs[0].buflist), +				  DRM_MEM_BUFS); +#if __HAVE_DMA_FREELIST +		   	DRM(freelist_destroy)(&dma->bufs[i].freelist); +#endif +		} +	} + +	if (dma->buflist) { +		DRM(free)(dma->buflist, +			  dma->buf_count * sizeof(*dma->buflist), +			  DRM_MEM_BUFS); +	} + +	if (dma->pagelist) { +		DRM(free)(dma->pagelist, +			  dma->page_count * sizeof(*dma->pagelist), +			  DRM_MEM_PAGES); +	} +	DRM(free)(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER); +	dev->dma = NULL; +} + + +#if DRM_DMA_HISTOGRAM +/* This is slow, but is useful for debugging. */ +int DRM(histogram_slot)(unsigned long count) +{ +	int value = DRM_DMA_HISTOGRAM_INITIAL; +	int slot; + +	for (slot = 0; +	     slot < DRM_DMA_HISTOGRAM_SLOTS; +	     ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) { +		if (count < value) return slot; +	} +	return DRM_DMA_HISTOGRAM_SLOTS - 1; +} + +void DRM(histogram_compute)(drm_device_t *dev, drm_buf_t *buf) +{ +	cycles_t queued_to_dispatched; +	cycles_t dispatched_to_completed; +	cycles_t completed_to_freed; +	int	 q2d, d2c, c2f, q2c, q2f; + +	if (buf->time_queued) { +		queued_to_dispatched	= (buf->time_dispatched +					   - buf->time_queued); +		dispatched_to_completed = (buf->time_completed +					   - buf->time_dispatched); +		completed_to_freed	= (buf->time_freed +					   - buf->time_completed); + +		q2d = DRM(histogram_slot)(queued_to_dispatched); +		d2c = DRM(histogram_slot)(dispatched_to_completed); +		c2f = DRM(histogram_slot)(completed_to_freed); + +		q2c = DRM(histogram_slot)(queued_to_dispatched +					  + dispatched_to_completed); +		q2f = DRM(histogram_slot)(queued_to_dispatched +					  + dispatched_to_completed +					  + completed_to_freed); + +		atomic_inc(&dev->histo.total); +		atomic_inc(&dev->histo.queued_to_dispatched[q2d]); +		atomic_inc(&dev->histo.dispatched_to_completed[d2c]); +		atomic_inc(&dev->histo.completed_to_freed[c2f]); + +		atomic_inc(&dev->histo.queued_to_completed[q2c]); +		atomic_inc(&dev->histo.queued_to_freed[q2f]); + +	} +	buf->time_queued     = 0; +	buf->time_dispatched = 0; +	buf->time_completed  = 0; +	buf->time_freed	     = 0; +} +#endif + +void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf) +{ +	if (!buf) return; + +	buf->waiting  = 0; +	buf->pending  = 0; +	buf->pid      = 0; +	buf->used     = 0; +#if DRM_DMA_HISTOGRAM +	buf->time_completed = get_cycles(); +#endif + +	if ( __HAVE_DMA_WAITQUEUE && waitqueue_active(&buf->dma_wait)) { +		wake_up_interruptible(&buf->dma_wait); +	} +#if __HAVE_DMA_FREELIST +	else { +		drm_device_dma_t *dma = dev->dma; +				/* If processes are waiting, the last one +				   to wake will put the buffer on the free +				   list.  If no processes are waiting, we +				   put the buffer on the freelist here. */ +		DRM(freelist_put)(dev, &dma->bufs[buf->order].freelist, buf); +	} +#endif +} + +#if !__HAVE_DMA_RECLAIM +void DRM(reclaim_buffers)(drm_device_t *dev, pid_t pid) +{ +	drm_device_dma_t *dma = dev->dma; +	int		 i; + +	if (!dma) return; +	for (i = 0; i < dma->buf_count; i++) { +		if (dma->buflist[i]->pid == pid) { +			switch (dma->buflist[i]->list) { +			case DRM_LIST_NONE: +				DRM(free_buffer)(dev, dma->buflist[i]); +				break; +			case DRM_LIST_WAIT: +				dma->buflist[i]->list = DRM_LIST_RECLAIM; +				break; +			default: +				/* Buffer already on hardware. */ +				break; +			} +		} +	} +} +#endif + + +/* GH: This is a big hack for now... + */ +#if __HAVE_OLD_DMA + +int drm_context_switch(drm_device_t *dev, int old, int new) +{ +	char	    buf[64]; +	drm_queue_t *q; + +#if 0 +	atomic_inc(&dev->total_ctx); +#endif + +	if (test_and_set_bit(0, &dev->context_flag)) { +		DRM_ERROR("Reentering -- FIXME\n"); +		return -EBUSY; +	} + +#if DRM_DMA_HISTOGRAM +	dev->ctx_start = get_cycles(); +#endif + +	DRM_DEBUG("Context switch from %d to %d\n", old, new); + +	if (new >= dev->queue_count) { +		clear_bit(0, &dev->context_flag); +		return -EINVAL; +	} + +	if (new == dev->last_context) { +		clear_bit(0, &dev->context_flag); +		return 0; +	} + +	q = dev->queuelist[new]; +	atomic_inc(&q->use_count); +	if (atomic_read(&q->use_count) == 1) { +		atomic_dec(&q->use_count); +		clear_bit(0, &dev->context_flag); +		return -EINVAL; +	} + +	if (DRM(flags) & DRM_FLAG_NOCTX) { +		drm_context_switch_complete(dev, new); +	} else { +		sprintf(buf, "C %d %d\n", old, new); +		DRM(write_string)(dev, buf); +	} + +	atomic_dec(&q->use_count); + +	return 0; +} + +int drm_context_switch_complete(drm_device_t *dev, int new) +{ +	drm_device_dma_t *dma = dev->dma; + +	dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */ +	dev->last_switch  = jiffies; + +	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { +		DRM_ERROR("Lock isn't held after context switch\n"); +	} + +	if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) { +		if (DRM(lock_free)(dev, &dev->lock.hw_lock->lock, +				  DRM_KERNEL_CONTEXT)) { +			DRM_ERROR("Cannot free lock\n"); +		} +	} + +#if DRM_DMA_HISTOGRAM +	atomic_inc(&dev->histo.ctx[DRM(histogram_slot)(get_cycles() +						      - dev->ctx_start)]); + +#endif +	clear_bit(0, &dev->context_flag); +	wake_up_interruptible(&dev->context_wait); + +	return 0; +} + +void DRM(clear_next_buffer)(drm_device_t *dev) +{ +	drm_device_dma_t *dma = dev->dma; + +	dma->next_buffer = NULL; +	if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) { +		wake_up_interruptible(&dma->next_queue->flush_queue); +	} +	dma->next_queue	 = NULL; +} + +int DRM(select_queue)(drm_device_t *dev, void (*wrapper)(unsigned long)) +{ +	int	   i; +	int	   candidate = -1; +	int	   j	     = jiffies; + +	if (!dev) { +		DRM_ERROR("No device\n"); +		return -1; +	} +	if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) { +				/* This only happens between the time the +				   interrupt is initialized and the time +				   the queues are initialized. */ +		return -1; +	} + +				/* Doing "while locked" DMA? */ +	if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) { +		return DRM_KERNEL_CONTEXT; +	} + +				/* If there are buffers on the last_context +				   queue, and we have not been executing +				   this context very long, continue to +				   execute this context. */ +	if (dev->last_switch <= j +	    && dev->last_switch + DRM_TIME_SLICE > j +	    && DRM_WAITCOUNT(dev, dev->last_context)) { +		return dev->last_context; +	} + +				/* Otherwise, find a candidate */ +	for (i = dev->last_checked + 1; i < dev->queue_count; i++) { +		if (DRM_WAITCOUNT(dev, i)) { +			candidate = dev->last_checked = i; +			break; +		} +	} + +	if (candidate < 0) { +		for (i = 0; i < dev->queue_count; i++) { +			if (DRM_WAITCOUNT(dev, i)) { +				candidate = dev->last_checked = i; +				break; +			} +		} +	} + +	if (wrapper +	    && candidate >= 0 +	    && candidate != dev->last_context +	    && dev->last_switch <= j +	    && dev->last_switch + DRM_TIME_SLICE > j) { +		if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) { +			del_timer(&dev->timer); +			dev->timer.function = wrapper; +			dev->timer.data	    = (unsigned long)dev; +			dev->timer.expires  = dev->last_switch+DRM_TIME_SLICE; +			add_timer(&dev->timer); +		} +		return -1; +	} + +	return candidate; +} + + +int DRM(dma_enqueue)(drm_device_t *dev, drm_dma_t *d) +{ +	int		  i; +	drm_queue_t	  *q; +	drm_buf_t	  *buf; +	int		  idx; +	int		  while_locked = 0; +	drm_device_dma_t  *dma = dev->dma; +	DECLARE_WAITQUEUE(entry, current); + +	DRM_DEBUG("%d\n", d->send_count); + +	if (d->flags & _DRM_DMA_WHILE_LOCKED) { +		int context = dev->lock.hw_lock->lock; + +		if (!_DRM_LOCK_IS_HELD(context)) { +			DRM_ERROR("No lock held during \"while locked\"" +				  " request\n"); +			return -EINVAL; +		} +		if (d->context != _DRM_LOCKING_CONTEXT(context) +		    && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) { +			DRM_ERROR("Lock held by %d while %d makes" +				  " \"while locked\" request\n", +				  _DRM_LOCKING_CONTEXT(context), +				  d->context); +			return -EINVAL; +		} +		q = dev->queuelist[DRM_KERNEL_CONTEXT]; +		while_locked = 1; +	} else { +		q = dev->queuelist[d->context]; +	} + + +	atomic_inc(&q->use_count); +	if (atomic_read(&q->block_write)) { +		add_wait_queue(&q->write_queue, &entry); +		atomic_inc(&q->block_count); +		for (;;) { +			current->state = TASK_INTERRUPTIBLE; +			if (!atomic_read(&q->block_write)) break; +			schedule(); +			if (signal_pending(current)) { +				atomic_dec(&q->use_count); +				remove_wait_queue(&q->write_queue, &entry); +				return -EINTR; +			} +		} +		atomic_dec(&q->block_count); +		current->state = TASK_RUNNING; +		remove_wait_queue(&q->write_queue, &entry); +	} + +	for (i = 0; i < d->send_count; i++) { +		idx = d->send_indices[i]; +		if (idx < 0 || idx >= dma->buf_count) { +			atomic_dec(&q->use_count); +			DRM_ERROR("Index %d (of %d max)\n", +				  d->send_indices[i], dma->buf_count - 1); +			return -EINVAL; +		} +		buf = dma->buflist[ idx ]; +		if (buf->pid != current->pid) { +			atomic_dec(&q->use_count); +			DRM_ERROR("Process %d using buffer owned by %d\n", +				  current->pid, buf->pid); +			return -EINVAL; +		} +		if (buf->list != DRM_LIST_NONE) { +			atomic_dec(&q->use_count); +			DRM_ERROR("Process %d using buffer %d on list %d\n", +				  current->pid, buf->idx, buf->list); +		} +		buf->used	  = d->send_sizes[i]; +		buf->while_locked = while_locked; +		buf->context	  = d->context; +		if (!buf->used) { +			DRM_ERROR("Queueing 0 length buffer\n"); +		} +		if (buf->pending) { +			atomic_dec(&q->use_count); +			DRM_ERROR("Queueing pending buffer:" +				  " buffer %d, offset %d\n", +				  d->send_indices[i], i); +			return -EINVAL; +		} +		if (buf->waiting) { +			atomic_dec(&q->use_count); +			DRM_ERROR("Queueing waiting buffer:" +				  " buffer %d, offset %d\n", +				  d->send_indices[i], i); +			return -EINVAL; +		} +		buf->waiting = 1; +		if (atomic_read(&q->use_count) == 1 +		    || atomic_read(&q->finalization)) { +			DRM(free_buffer)(dev, buf); +		} else { +			DRM(waitlist_put)(&q->waitlist, buf); +			atomic_inc(&q->total_queued); +		} +	} +	atomic_dec(&q->use_count); + +	return 0; +} + +static int DRM(dma_get_buffers_of_order)(drm_device_t *dev, drm_dma_t *d, +					 int order) +{ +	int		  i; +	drm_buf_t	  *buf; +	drm_device_dma_t  *dma = dev->dma; + +	for (i = d->granted_count; i < d->request_count; i++) { +		buf = DRM(freelist_get)(&dma->bufs[order].freelist, +					d->flags & _DRM_DMA_WAIT); +		if (!buf) break; +		if (buf->pending || buf->waiting) { +			DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n", +				  buf->idx, +				  buf->pid, +				  buf->waiting, +				  buf->pending); +		} +		buf->pid     = current->pid; +		if (copy_to_user(&d->request_indices[i], +				 &buf->idx, +				 sizeof(buf->idx))) +			return -EFAULT; + +		if (copy_to_user(&d->request_sizes[i], +				 &buf->total, +				 sizeof(buf->total))) +			return -EFAULT; + +		++d->granted_count; +	} +	return 0; +} + + +int DRM(dma_get_buffers)(drm_device_t *dev, drm_dma_t *dma) +{ +	int		  order; +	int		  retcode = 0; +	int		  tmp_order; + +	order = DRM(order)(dma->request_size); + +	dma->granted_count = 0; +	retcode		   = DRM(dma_get_buffers_of_order)(dev, dma, order); + +	if (dma->granted_count < dma->request_count +	    && (dma->flags & _DRM_DMA_SMALLER_OK)) { +		for (tmp_order = order - 1; +		     !retcode +			     && dma->granted_count < dma->request_count +			     && tmp_order >= DRM_MIN_ORDER; +		     --tmp_order) { + +			retcode = DRM(dma_get_buffers_of_order)(dev, dma, +								tmp_order); +		} +	} + +	if (dma->granted_count < dma->request_count +	    && (dma->flags & _DRM_DMA_LARGER_OK)) { +		for (tmp_order = order + 1; +		     !retcode +			     && dma->granted_count < dma->request_count +			     && tmp_order <= DRM_MAX_ORDER; +		     ++tmp_order) { + +			retcode = DRM(dma_get_buffers_of_order)(dev, dma, +								tmp_order); +		} +	} +	return 0; +} + +#endif + +#endif diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c new file mode 100644 index 00000000..13e46b9f --- /dev/null +++ b/linux-core/drm_drawable.c @@ -0,0 +1,51 @@ +/* drm_drawable.h -- IOCTLs for drawables -*- linux-c -*- + * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int DRM(adddraw)(struct inode *inode, struct file *filp, +		 unsigned int cmd, unsigned long arg) +{ +	drm_draw_t draw; + +	draw.handle = 0;	/* NOOP */ +	DRM_DEBUG("%d\n", draw.handle); +	if (copy_to_user((drm_draw_t *)arg, &draw, sizeof(draw))) +		return -EFAULT; +	return 0; +} + +int DRM(rmdraw)(struct inode *inode, struct file *filp, +		unsigned int cmd, unsigned long arg) +{ +	return 0;		/* NOOP */ +} diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c new file mode 100644 index 00000000..b24d213e --- /dev/null +++ b/linux-core/drm_drv.c @@ -0,0 +1,927 @@ +/* drm_drv.h -- Generic driver template -*- linux-c -*- + * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +/* + * To use this template, you must at least define the following (samples + * given for the MGA driver): + * + * #define DRIVER_AUTHOR	"VA Linux Systems, Inc." + * + * #define DRIVER_NAME		"mga" + * #define DRIVER_DESC		"Matrox G200/G400" + * #define DRIVER_DATE		"20001127" + * + * #define DRIVER_MAJOR		2 + * #define DRIVER_MINOR		0 + * #define DRIVER_PATCHLEVEL	2 + * + * #define DRIVER_IOCTL_COUNT	DRM_ARRAY_SIZE( mga_ioctls ) + * + * #define DRM(x)		mga_##x + */ + +#ifndef __MUST_HAVE_AGP +#define __MUST_HAVE_AGP			0 +#endif +#ifndef __HAVE_CTX_BITMAP +#define __HAVE_CTX_BITMAP		0 +#endif +#ifndef __HAVE_DMA_IRQ +#define __HAVE_DMA_IRQ			0 +#endif +#ifndef __HAVE_DMA_QUEUE +#define __HAVE_DMA_QUEUE		0 +#endif +#ifndef __HAVE_MULTIPLE_DMA_QUEUES +#define __HAVE_MULTIPLE_DMA_QUEUES	0 +#endif +#ifndef __HAVE_DMA_SCHEDULE +#define __HAVE_DMA_SCHEDULE		0 +#endif +#ifndef __HAVE_DMA_FLUSH +#define __HAVE_DMA_FLUSH		0 +#endif +#ifndef __HAVE_DMA_READY +#define __HAVE_DMA_READY		0 +#endif +#ifndef __HAVE_DMA_QUIESCENT +#define __HAVE_DMA_QUIESCENT		0 +#endif +#ifndef __HAVE_RELEASE +#define __HAVE_RELEASE			0 +#endif +#ifndef __HAVE_COUNTERS +#define __HAVE_COUNTERS			0 +#endif + +#ifndef DRIVER_PREINIT +#define DRIVER_PREINIT() +#endif +#ifndef DRIVER_POSTINIT +#define DRIVER_POSTINIT() +#endif +#ifndef DRIVER_PRERELEASE +#define DRIVER_PRERELEASE() +#endif +#ifndef DRIVER_PRETAKEDOWN +#define DRIVER_PRETAKEDOWN() +#endif +#ifndef DRIVER_IOCTLS +#define DRIVER_IOCTLS +#endif + + +static drm_device_t	DRM(device); +static int              DRM(minor); + +static struct file_operations	DRM(fops) = { +#if LINUX_VERSION_CODE >= 0x020400 +				/* This started being used during 2.4.0-test */ +	owner:   THIS_MODULE, +#endif +	open:	 DRM(open), +	flush:	 DRM(flush), +	release: DRM(release), +	ioctl:	 DRM(ioctl), +	mmap:	 DRM(mmap), +	read:	 DRM(read), +	fasync:	 DRM(fasync), +	poll:	 DRM(poll), +}; + + +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 }, + +#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 }, + +	/* 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 }, +#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 }, +#endif + +	DRIVER_IOCTLS +}; + +#define DRIVER_IOCTL_COUNT	DRM_ARRAY_SIZE( DRM(ioctls) ) + +#ifdef MODULE +static char *drm_opts = NULL; +#endif + +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_PARM( drm_opts, "s" ); + +#ifndef MODULE +/* DRM(options) is called by the kernel to parse command-line options + * passed via the boot-loader (e.g., LILO).  It calls the insmod option + * routine, drm_parse_drm. + */ + +static int __init DRM(options)( char *str ) +{ +	DRM(parse_options)( str ); +	return 1; +} + +__setup( DRIVER_NAME "=", DRM(options) ); +#endif + +static int DRM(setup)( drm_device_t *dev ) +{ +	int i; + +	atomic_set( &dev->ioctl_count, 0 ); +	atomic_set( &dev->vma_count, 0 ); +	dev->buf_use = 0; +	atomic_set( &dev->buf_alloc, 0 ); + +#if __HAVE_DMA +	i = DRM(dma_setup)( dev ); +	if ( i < 0 ) +		return i; +#endif + +	dev->counters  = 6 + __HAVE_COUNTERS; +	dev->types[0]  = _DRM_STAT_LOCK; +	dev->types[1]  = _DRM_STAT_OPENS; +	dev->types[2]  = _DRM_STAT_CLOSES; +	dev->types[3]  = _DRM_STAT_IOCTLS; +	dev->types[4]  = _DRM_STAT_LOCKS; +	dev->types[5]  = _DRM_STAT_UNLOCKS; +#ifdef __HAVE_COUNTER6 +	dev->types[6]  = __HAVE_COUNTER6; +#endif +#ifdef __HAVE_COUNTER7 +	dev->types[7]  = __HAVE_COUNTER7; +#endif +#ifdef __HAVE_COUNTER8 +	dev->types[8]  = __HAVE_COUNTER8; +#endif +#ifdef __HAVE_COUNTER9 +	dev->types[9]  = __HAVE_COUNTER9; +#endif +#ifdef __HAVE_COUNTER10 +	dev->types[10] = __HAVE_COUNTER10; +#endif +#ifdef __HAVE_COUNTER11 +	dev->types[11] = __HAVE_COUNTER11; +#endif +#ifdef __HAVE_COUNTER12 +	dev->types[12] = __HAVE_COUNTER12; +#endif +#ifdef __HAVE_COUNTER13 +	dev->types[13] = __HAVE_COUNTER13; +#endif +#ifdef __HAVE_COUNTER14 +	dev->types[14] = __HAVE_COUNTER14; +#endif +#ifdef __HAVE_COUNTER15 +	dev->types[14] = __HAVE_COUNTER14; +#endif + +	for ( i = 0 ; i < DRM_ARRAY_SIZE(dev->counts) ; i++ ) +		atomic_set( &dev->counts[i], 0 ); + +	for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) { +		dev->magiclist[i].head = NULL; +		dev->magiclist[i].tail = NULL; +	} +	dev->maplist = NULL; +	dev->map_count = 0; +	dev->vmalist = NULL; +	dev->lock.hw_lock = NULL; +	init_waitqueue_head( &dev->lock.lock_queue ); +	dev->queue_count = 0; +	dev->queue_reserved = 0; +	dev->queue_slots = 0; +	dev->queuelist = NULL; +	dev->irq = 0; +	dev->context_flag = 0; +	dev->interrupt_flag = 0; +	dev->dma_flag = 0; +	dev->last_context = 0; +	dev->last_switch = 0; +	dev->last_checked = 0; +	init_timer( &dev->timer ); +	init_waitqueue_head( &dev->context_wait ); + +	dev->ctx_start = 0; +	dev->lck_start = 0; + +	dev->buf_rp = dev->buf; +	dev->buf_wp = dev->buf; +	dev->buf_end = dev->buf + DRM_BSZ; +	dev->buf_async = NULL; +	init_waitqueue_head( &dev->buf_readers ); +	init_waitqueue_head( &dev->buf_writers ); + +	DRM_DEBUG( "\n" ); + +	/* The kernel's context could be created here, but is now created +	 * in drm_dma_enqueue.	This is more resource-efficient for +	 * hardware that does not do DMA, but may mean that +	 * drm_select_queue fails between the time the interrupt is +	 * initialized and the time the queues are initialized. +	 */ +	return 0; +} + + +static int DRM(takedown)( drm_device_t *dev ) +{ +	drm_magic_entry_t *pt, *next; +	drm_map_t *map; +	drm_vma_entry_t *vma, *vma_next; +	int i; + +	DRM_DEBUG( "\n" ); + +	DRIVER_PRETAKEDOWN(); +#if __HAVE_DMA_IRQ +	if ( dev->irq ) DRM(irq_uninstall)( dev ); +#endif + +	down( &dev->struct_sem ); +	del_timer( &dev->timer ); + +	if ( dev->devname ) { +		DRM(free)( dev->devname, strlen( dev->devname ) + 1, +			   DRM_MEM_DRIVER ); +		dev->devname = NULL; +	} + +	if ( dev->unique ) { +		DRM(free)( dev->unique, strlen( dev->unique ) + 1, +			   DRM_MEM_DRIVER ); +		dev->unique = NULL; +		dev->unique_len = 0; +	} +				/* Clear pid list */ +	for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) { +		for ( pt = dev->magiclist[i].head ; pt ; pt = next ) { +			next = pt->next; +			DRM(free)( pt, sizeof(*pt), DRM_MEM_MAGIC ); +		} +		dev->magiclist[i].head = dev->magiclist[i].tail = NULL; +	} + +#if __REALLY_HAVE_AGP +				/* Clear AGP information */ +	if ( dev->agp ) { +		drm_agp_mem_t *entry; +		drm_agp_mem_t *nexte; + +				/* Remove AGP resources, but leave dev->agp +                                   intact until drv_cleanup is called. */ +		for ( entry = dev->agp->memory ; entry ; entry = nexte ) { +			nexte = entry->next; +			if ( entry->bound ) DRM(unbind_agp)( entry->memory ); +			DRM(free_agp)( entry->memory, entry->pages ); +			DRM(free)( entry, sizeof(*entry), DRM_MEM_AGPLISTS ); +		} +		dev->agp->memory = NULL; + +		if ( dev->agp->acquired ) DRM(agp_do_release)(); + +		dev->agp->acquired = 0; +		dev->agp->enabled  = 0; +	} +#endif + +				/* Clear vma list (only built for debugging) */ +	if ( dev->vmalist ) { +		for ( vma = dev->vmalist ; vma ; vma = vma_next ) { +			vma_next = vma->next; +			DRM(free)( vma, sizeof(*vma), DRM_MEM_VMAS ); +		} +		dev->vmalist = NULL; +	} + +				/* Clear map area and mtrr information */ +	if ( dev->maplist ) { +		for ( i = 0 ; i < dev->map_count ; i++ ) { +			map = dev->maplist[i]; +			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 ); +				break; +			case _DRM_SHM: +				DRM(free_pages)( (unsigned long)map->handle, +						 DRM(order)( map->size ) +						 - PAGE_SHIFT, +						 DRM_MEM_SAREA ); +				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 ); +		dev->maplist = NULL; +		dev->map_count = 0; +	} + +#if __HAVE_DMA_QUEUE || __HAVE_MULTIPLE_DMA_QUEUES +	if ( dev->queuelist ) { +		for ( i = 0 ; i < dev->queue_count ; i++ ) { +			DRM(waitlist_destroy)( &dev->queuelist[i]->waitlist ); +			if ( dev->queuelist[i] ) { +				DRM(free)( dev->queuelist[i], +					  sizeof(*dev->queuelist[0]), +					  DRM_MEM_QUEUES ); +				dev->queuelist[i] = NULL; +			} +		} +		DRM(free)( dev->queuelist, +			  dev->queue_slots * sizeof(*dev->queuelist), +			  DRM_MEM_QUEUES ); +		dev->queuelist = NULL; +	} +	dev->queue_count = 0; +#endif + +#if __HAVE_DMA +	DRM(dma_takedown)( dev ); +#endif +	if ( dev->lock.hw_lock ) { +		dev->lock.hw_lock = NULL; /* SHM removed */ +		dev->lock.pid = 0; +		wake_up_interruptible( &dev->lock.lock_queue ); +	} +	up( &dev->struct_sem ); + +	return 0; +} + +/* drm_init is called via init_module at module load time, or via + * linux/init/main.c (this is not currently supported). + */ +static int __init drm_init( void ) +{ +	drm_device_t *dev = &DRM(device); +#if __HAVE_CTX_BITMAP +	int retcode; +#endif +	DRM_DEBUG( "\n" ); + +	memset( (void *)dev, 0, sizeof(*dev) ); +	dev->count_lock = SPIN_LOCK_UNLOCKED; +	sema_init( &dev->struct_sem, 1 ); + +#ifdef MODULE +	DRM(parse_options)( drm_opts ); +#endif +	DRIVER_PREINIT(); + +	DRM(mem_init)(); + +	if ((DRM(minor) = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) +		return -EPERM; +	dev->device = MKDEV(DRM_MAJOR, DRM(minor) ); +	dev->name   = DRIVER_NAME; + +#if __REALLY_HAVE_AGP +	dev->agp = DRM(agp_init)(); +#if __MUST_HAVE_AGP +	if ( dev->agp == NULL ) { +		DRM_ERROR( "Cannot initialize the agpgart module.\n" ); +		DRM(stub_unregister)(DRM(minor)); +		DRM(takedown)( dev ); +		return -ENOMEM; +	} +#endif +#if __REALLY_HAVE_MTRR +	dev->agp->agp_mtrr = mtrr_add( dev->agp->agp_info.aper_base, +				       dev->agp->agp_info.aper_size*1024*1024, +				       MTRR_TYPE_WRCOMB, +				       1 ); +#endif +#endif + +#if __HAVE_CTX_BITMAP +	retcode = DRM(ctxbitmap_init)( dev ); +	if( retcode ) { +		DRM_ERROR( "Cannot allocate memory for context bitmap.\n" ); +		DRM(stub_unregister)(DRM(minor)); +		DRM(takedown)( dev ); +		return retcode; +	} +#endif + +	DRIVER_POSTINIT(); + +	DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n", +		  DRIVER_NAME, +		  DRIVER_MAJOR, +		  DRIVER_MINOR, +		  DRIVER_PATCHLEVEL, +		  DRIVER_DATE, +		  DRM(minor) ); + +	return 0; +} + +/* drm_cleanup is called via cleanup_module at module unload time. + */ +static void __exit drm_cleanup( void ) +{ +	drm_device_t *dev = &DRM(device); + +	DRM_DEBUG( "\n" ); + +	if ( DRM(stub_unregister)(DRM(minor)) ) { +		DRM_ERROR( "Cannot unload module\n" ); +	} else { +		DRM_INFO( "Module unloaded\n" ); +	} +#if __HAVE_CTX_BITMAP +	DRM(ctxbitmap_cleanup)( dev ); +#endif + +#if __REALLY_HAVE_AGP && __REALLY_HAVE_MTRR +	if ( dev->agp && dev->agp->agp_mtrr ) { +		int retval; +		retval = mtrr_del( dev->agp->agp_mtrr, +				   dev->agp->agp_info.aper_base, +				   dev->agp->agp_info.aper_size*1024*1024 ); +		DRM_DEBUG( "mtrr_del=%d\n", retval ); +	} +#endif + +	DRM(takedown)( dev ); + +#if __REALLY_HAVE_AGP +	if ( dev->agp ) { +		DRM(agp_uninit)(); +		DRM(free)( dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS ); +		dev->agp = NULL; +	} +#endif +} + +module_init( drm_init ); +module_exit( drm_cleanup ); + + +int DRM(version)( struct inode *inode, struct file *filp, +		  unsigned int cmd, unsigned long arg ) +{ +	drm_version_t version; +	int len; + +	if ( copy_from_user( &version, +			     (drm_version_t *)arg, +			     sizeof(version) ) ) +		return -EFAULT; + +#define DRM_COPY( name, value )						\ +	len = strlen( value );						\ +	if ( len > name##_len ) len = name##_len;			\ +	name##_len = strlen( value );					\ +	if ( len && name ) {						\ +		if ( copy_to_user( name, value, len ) )			\ +			return -EFAULT;					\ +	} + +	version.version_major = DRIVER_MAJOR; +	version.version_minor = DRIVER_MINOR; +	version.version_patchlevel = DRIVER_PATCHLEVEL; + +	DRM_COPY( version.name, DRIVER_NAME ); +	DRM_COPY( version.date, DRIVER_DATE ); +	DRM_COPY( version.desc, DRIVER_DESC ); + +	if ( copy_to_user( (drm_version_t *)arg, +			   &version, +			   sizeof(version) ) ) +		return -EFAULT; +	return 0; +} + +int DRM(open)( struct inode *inode, struct file *filp ) +{ +	drm_device_t *dev = &DRM(device); +	int retcode = 0; + +	DRM_DEBUG( "open_count = %d\n", dev->open_count ); + +	retcode = DRM(open_helper)( inode, filp, dev ); +	if ( !retcode ) { +#if LINUX_VERSION_CODE < 0x020333 +		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif +		atomic_inc( &dev->counts[_DRM_STAT_OPENS] ); +		spin_lock( &dev->count_lock ); +		if ( !dev->open_count++ ) { +			spin_unlock( &dev->count_lock ); +			return DRM(setup)( dev ); +		} +		spin_unlock( &dev->count_lock ); +	} + +	return retcode; +} + +int DRM(release)( struct inode *inode, struct file *filp ) +{ +	drm_file_t *priv = filp->private_data; +	drm_device_t *dev; +	int retcode = 0; + +	lock_kernel(); +	dev = priv->dev; + +	DRM_DEBUG( "open_count = %d\n", dev->open_count ); + +	DRIVER_PRERELEASE(); + +	/* ======================================================== +	 * Begin inline drm_release +	 */ + +	DRM_DEBUG( "pid = %d, device = 0x%x, open_count = %d\n", +		   current->pid, dev->device, dev->open_count ); + +	if ( dev->lock.hw_lock && +	     _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && +	     dev->lock.pid == current->pid ) { +		DRM_ERROR( "Process %d dead, freeing lock for context %d\n", +			   current->pid, +			   _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) ); +#if __HAVE_RELEASE +		DRIVER_RELEASE(); +#endif +		DRM(lock_free)( dev, &dev->lock.hw_lock->lock, +				_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) ); + +				/* FIXME: may require heavy-handed reset of +                                   hardware at this point, possibly +                                   processed via a callback to the X +                                   server. */ +	} +#if __HAVE_RELEASE +	else if ( dev->lock.hw_lock ) { +		/* The lock is required to reclaim buffers */ +		DECLARE_WAITQUEUE( entry, current ); +		add_wait_queue( &dev->lock.lock_queue, &entry ); +		for (;;) { +			current->state = TASK_INTERRUPTIBLE; +			if ( !dev->lock.hw_lock ) { +				/* Device has been unregistered */ +				retcode = -EINTR; +				break; +			} +			if ( DRM(lock_take)( &dev->lock.hw_lock->lock, +					     DRM_KERNEL_CONTEXT ) ) { +				dev->lock.pid	    = priv->pid; +				dev->lock.lock_time = jiffies; +                                atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); +				break;	/* Got lock */ +			} +				/* Contention */ +#if 0 +			atomic_inc( &dev->total_sleeps ); +#endif +			schedule(); +			if ( signal_pending( current ) ) { +				retcode = -ERESTARTSYS; +				break; +			} +		} +		current->state = TASK_RUNNING; +		remove_wait_queue( &dev->lock.lock_queue, &entry ); +		if( !retcode ) { +			DRIVER_RELEASE(); +			DRM(lock_free)( dev, &dev->lock.hw_lock->lock, +					DRM_KERNEL_CONTEXT ); +		} +	} +#else +	DRM(reclaim_buffers)( dev, priv->pid ); +#endif + +	DRM(fasync)( -1, filp, 0 ); + +	down( &dev->struct_sem ); +	if ( priv->remove_auth_on_close == 1 ) { +		drm_file_t *temp = dev->file_first; +		while ( temp ) { +			temp->authenticated = 0; +			temp = temp->next; +		} +	} +	if ( priv->prev ) { +		priv->prev->next = priv->next; +	} else { +		dev->file_first	 = priv->next; +	} +	if ( priv->next ) { +		priv->next->prev = priv->prev; +	} else { +		dev->file_last	 = priv->prev; +	} +	up( &dev->struct_sem ); + +	DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES ); + +	/* ======================================================== +	 * End inline drm_release +	 */ + +#if LINUX_VERSION_CODE < 0x020333 +	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#endif +	atomic_inc( &dev->counts[_DRM_STAT_CLOSES] ); +	spin_lock( &dev->count_lock ); +	if ( !--dev->open_count ) { +		if ( atomic_read( &dev->ioctl_count ) || dev->blocked ) { +			DRM_ERROR( "Device busy: %d %d\n", +				   atomic_read( &dev->ioctl_count ), +				   dev->blocked ); +			spin_unlock( &dev->count_lock ); +			unlock_kernel(); +			return -EBUSY; +		} +		spin_unlock( &dev->count_lock ); +		unlock_kernel(); +		return DRM(takedown)( dev ); +	} +	spin_unlock( &dev->count_lock ); + +	unlock_kernel(); +	return retcode; +} + +/* DRM(ioctl) is called whenever a process performs an ioctl on /dev/drm. + */ +int DRM(ioctl)( 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_ioctl_desc_t *ioctl; +	drm_ioctl_t *func; +	int nr = DRM_IOCTL_NR(cmd); +	int retcode = 0; + +	atomic_inc( &dev->ioctl_count ); +	atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] ); +	++priv->ioctl_count; + +	DRM_DEBUG( "pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%x, auth=%d\n", +		   current->pid, cmd, nr, dev->device, priv->authenticated ); + +	if ( nr >= DRIVER_IOCTL_COUNT ) { +		retcode = -EINVAL; +	} else { +		ioctl = &DRM(ioctls)[nr]; +		func = ioctl->func; + +		if ( !func ) { +			DRM_DEBUG( "no function\n" ); +			retcode = -EINVAL; +		} else if ( ( ioctl->root_only && !capable( CAP_SYS_ADMIN ) )|| +			    ( ioctl->auth_needed && !priv->authenticated ) ) { +			retcode = -EACCES; +		} else { +			retcode = func( inode, filp, cmd, arg ); +		} +	} + +	atomic_dec( &dev->ioctl_count ); +	return retcode; +} + +int DRM(lock)( 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; +        DECLARE_WAITQUEUE( entry, current ); +        drm_lock_t lock; +        int ret = 0; +#if __HAVE_MULTIPLE_DMA_QUEUES +	drm_queue_t *q; +#endif +#if DRM_DMA_HISTOGRAM +        cycles_t start; + +        dev->lck_start = start = get_cycles(); +#endif + +        if ( copy_from_user( &lock, (drm_lock_t *)arg, sizeof(lock) ) ) +		return -EFAULT; + +        if ( lock.context == DRM_KERNEL_CONTEXT ) { +                DRM_ERROR( "Process %d using kernel context %d\n", +			   current->pid, lock.context ); +                return -EINVAL; +        } + +        DRM_DEBUG( "%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", +		   lock.context, current->pid, +		   dev->lock.hw_lock->lock, lock.flags ); + +#if __HAVE_DMA_QUEUE +        if ( lock.context < 0 ) +                return -EINVAL; +#elif __HAVE_MULTIPLE_DMA_QUEUES +        if ( lock.context < 0 || lock.context >= dev->queue_count ) +                return -EINVAL; +	q = dev->queuelist[lock.context]; +#endif + +#if __HAVE_DMA_FLUSH +	ret = DRM(flush_block_and_flush)( dev, lock.context, lock.flags ); +#endif +        if ( !ret ) { +                add_wait_queue( &dev->lock.lock_queue, &entry ); +                for (;;) { +                        current->state = TASK_INTERRUPTIBLE; +                        if ( !dev->lock.hw_lock ) { +                                /* Device has been unregistered */ +                                ret = -EINTR; +                                break; +                        } +                        if ( DRM(lock_take)( &dev->lock.hw_lock->lock, +					     lock.context ) ) { +                                dev->lock.pid       = current->pid; +                                dev->lock.lock_time = jiffies; +                                atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); +                                break;  /* Got lock */ +                        } + +                                /* Contention */ +                        schedule(); +                        if ( signal_pending( current ) ) { +                                ret = -ERESTARTSYS; +                                break; +                        } +                } +                current->state = TASK_RUNNING; +                remove_wait_queue( &dev->lock.lock_queue, &entry ); +        } + +#if __HAVE_DMA_FLUSH +	DRM(flush_unblock)( dev, lock.context, lock.flags ); /* cleanup phase */ +#endif + +        if ( !ret ) { +		sigemptyset( &dev->sigmask ); +		sigaddset( &dev->sigmask, SIGSTOP ); +		sigaddset( &dev->sigmask, SIGTSTP ); +		sigaddset( &dev->sigmask, SIGTTIN ); +		sigaddset( &dev->sigmask, SIGTTOU ); +		dev->sigdata.context = lock.context; +		dev->sigdata.lock    = dev->lock.hw_lock; +		block_all_signals( DRM(notifier), +				   &dev->sigdata, &dev->sigmask ); + +#if __HAVE_DMA_READY +                if ( lock.flags & _DRM_LOCK_READY ) { +			DRIVER_DMA_READY(); +		} +#endif +#if __HAVE_DMA_QUIESCENT +                if ( lock.flags & _DRM_LOCK_QUIESCENT ) { +			DRIVER_DMA_QUIESCENT(); +		} +#endif +        } + +        DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); + +#if DRM_DMA_HISTOGRAM +        atomic_inc(&dev->histo.lacq[DRM(histogram_slot)(get_cycles()-start)]); +#endif +        return ret; +} + + +int DRM(unlock)( 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_lock_t lock; + +	if ( copy_from_user( &lock, (drm_lock_t *)arg, sizeof(lock) ) ) +		return -EFAULT; + +	if ( lock.context == DRM_KERNEL_CONTEXT ) { +		DRM_ERROR( "Process %d using kernel context %d\n", +			   current->pid, lock.context ); +		return -EINVAL; +	} + +	atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] ); + +	DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock, +			    DRM_KERNEL_CONTEXT ); +#if __HAVE_DMA_SCHEDULE +	DRM(dma_schedule)( dev, 1 ); +#endif + +	/* FIXME: Do we ever really need to check this??? +	 */ +	if ( 1 /* !dev->context_flag */ ) { +		if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock, +				     DRM_KERNEL_CONTEXT ) ) { +			DRM_ERROR( "\n" ); +		} +	} + +	unblock_all_signals(); +	return 0; +} diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c new file mode 100644 index 00000000..d646f318 --- /dev/null +++ b/linux-core/drm_fops.c @@ -0,0 +1,252 @@ +/* drm_fops.h -- File operations for DRM -*- linux-c -*- + * Created: Mon Jan  4 08:58:31 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Daryll Strauss <daryll@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include <linux/poll.h> + +/* drm_open is called whenever a process opens /dev/drm. */ + +int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) +{ +	kdev_t	     minor = MINOR(inode->i_rdev); +	drm_file_t   *priv; + +	if (filp->f_flags & O_EXCL)   return -EBUSY; /* No exclusive opens */ +	if (!DRM(cpu_valid)())        return -EINVAL; + +	DRM_DEBUG("pid = %d, minor = %d\n", current->pid, minor); + +	priv		    = DRM(alloc)(sizeof(*priv), DRM_MEM_FILES); +	memset(priv, 0, sizeof(*priv)); +	filp->private_data  = priv; +	priv->uid	    = current->euid; +	priv->pid	    = current->pid; +	priv->minor	    = minor; +	priv->dev	    = dev; +	priv->ioctl_count   = 0; +	priv->authenticated = capable(CAP_SYS_ADMIN); + +	down(&dev->struct_sem); +	if (!dev->file_last) { +		priv->next	= NULL; +		priv->prev	= NULL; +		dev->file_first = priv; +		dev->file_last	= priv; +	} else { +		priv->next	     = NULL; +		priv->prev	     = dev->file_last; +		dev->file_last->next = priv; +		dev->file_last	     = priv; +	} +	up(&dev->struct_sem); + +	return 0; +} + +int DRM(flush)(struct file *filp) +{ +	drm_file_t    *priv   = filp->private_data; +	drm_device_t  *dev    = priv->dev; + +	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", +		  current->pid, dev->device, dev->open_count); +	return 0; +} + +#if 0 +/* drm_release is called whenever a process closes /dev/drm*.  Linux calls +   this only if any mappings have been closed. */ + +int drm_release(struct inode *inode, struct file *filp) +{ +	drm_file_t    *priv   = filp->private_data; +	drm_device_t  *dev    = priv->dev; + +	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", +		  current->pid, dev->device, dev->open_count); + +	if (dev->lock.hw_lock +	    && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) +	    && dev->lock.pid == current->pid) { +		DRM_ERROR("Process %d dead, freeing lock for context %d\n", +			  current->pid, +			  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); +		drm_lock_free(dev, +			      &dev->lock.hw_lock->lock, +			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + +				/* FIXME: may require heavy-handed reset of +                                   hardware at this point, possibly +                                   processed via a callback to the X +                                   server. */ +	} +	drm_reclaim_buffers(dev, priv->pid); + +	drm_fasync(-1, filp, 0); + +	down(&dev->struct_sem); +	if (priv->prev) priv->prev->next = priv->next; +	else		dev->file_first	 = priv->next; +	if (priv->next) priv->next->prev = priv->prev; +	else		dev->file_last	 = priv->prev; +	up(&dev->struct_sem); + +	drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + +	return 0; +} +#endif + +int DRM(fasync)(int fd, struct file *filp, int on) +{ +	drm_file_t    *priv   = filp->private_data; +	drm_device_t  *dev    = priv->dev; +	int	      retcode; + +	DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device); +	retcode = fasync_helper(fd, filp, on, &dev->buf_async); +	if (retcode < 0) return retcode; +	return 0; +} + + +/* The drm_read and drm_write_string code (especially that which manages +   the circular buffer), is based on Alessandro Rubini's LINUX DEVICE +   DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */ + +ssize_t DRM(read)(struct file *filp, char *buf, size_t count, loff_t *off) +{ +	drm_file_t    *priv   = filp->private_data; +	drm_device_t  *dev    = priv->dev; +	int	      left; +	int	      avail; +	int	      send; +	int	      cur; + +	DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp); + +	while (dev->buf_rp == dev->buf_wp) { +		DRM_DEBUG("  sleeping\n"); +		if (filp->f_flags & O_NONBLOCK) { +			return -EAGAIN; +		} +		interruptible_sleep_on(&dev->buf_readers); +		if (signal_pending(current)) { +			DRM_DEBUG("  interrupted\n"); +			return -ERESTARTSYS; +		} +		DRM_DEBUG("  awake\n"); +	} + +	left  = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; +	avail = DRM_BSZ - left; +	send  = DRM_MIN(avail, count); + +	while (send) { +		if (dev->buf_wp > dev->buf_rp) { +			cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp); +		} else { +			cur = DRM_MIN(send, dev->buf_end - dev->buf_rp); +		} +		if (copy_to_user(buf, dev->buf_rp, cur)) +			return -EFAULT; +		dev->buf_rp += cur; +		if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf; +		send -= cur; +	} + +	wake_up_interruptible(&dev->buf_writers); +	return DRM_MIN(avail, count);; +} + +int DRM(write_string)(drm_device_t *dev, const char *s) +{ +	int left   = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; +	int send   = strlen(s); +	int count; + +	DRM_DEBUG("%d left, %d to send (%p, %p)\n", +		  left, send, dev->buf_rp, dev->buf_wp); + +	if (left == 1 || dev->buf_wp != dev->buf_rp) { +		DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n", +			  left, +			  dev->buf_wp, +			  dev->buf_rp); +	} + +	while (send) { +		if (dev->buf_wp >= dev->buf_rp) { +			count = DRM_MIN(send, dev->buf_end - dev->buf_wp); +			if (count == left) --count; /* Leave a hole */ +		} else { +			count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1); +		} +		strncpy(dev->buf_wp, s, count); +		dev->buf_wp += count; +		if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf; +		send -= count; +	} + +#if LINUX_VERSION_CODE < 0x020315 && !defined(KILLFASYNCHASTHREEPARAMETERS) +	/* The extra parameter to kill_fasync was added in 2.3.21, and is +           _not_ present in _stock_ 2.2.14 and 2.2.15.  However, some +           distributions patch 2.2.x kernels to add this parameter.  The +           Makefile.linux attempts to detect this addition and defines +           KILLFASYNCHASTHREEPARAMETERS if three parameters are found. */ +	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO); +#else + +				/* Parameter added in 2.3.21. */ +#if LINUX_VERSION_CODE < 0x020400 +	if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN); +#else +				/* Type of first parameter changed in +                                   Linux 2.4.0-test2... */ +	if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN); +#endif +#endif +	DRM_DEBUG("waking\n"); +	wake_up_interruptible(&dev->buf_readers); +	return 0; +} + +unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait) +{ +	drm_file_t   *priv = filp->private_data; +	drm_device_t *dev  = priv->dev; + +	poll_wait(filp, &dev->buf_readers, wait); +	if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM; +	return 0; +} diff --git a/linux-core/drm_init.c b/linux-core/drm_init.c new file mode 100644 index 00000000..9ae98414 --- /dev/null +++ b/linux-core/drm_init.c @@ -0,0 +1,112 @@ +/* drm_init.h -- Setup/Cleanup for DRM -*- linux-c -*- + * Created: Mon Jan  4 08:58:31 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int DRM(flags) = 0; + +/* drm_parse_option parses a single option.  See description for + * drm_parse_options for details. + */ +static void DRM(parse_option)(char *s) +{ +	char *c, *r; + +	DRM_DEBUG("\"%s\"\n", s); +	if (!s || !*s) return; +	for (c = s; *c && *c != ':'; c++); /* find : or \0 */ +	if (*c) r = c + 1; else r = NULL;  /* remember remainder */ +	*c = '\0';			   /* terminate */ +	if (!strcmp(s, "noctx")) { +		DRM(flags) |= DRM_FLAG_NOCTX; +		DRM_INFO("Server-mediated context switching OFF\n"); +		return; +	} +	if (!strcmp(s, "debug")) { +		DRM(flags) |= DRM_FLAG_DEBUG; +		DRM_INFO("Debug messages ON\n"); +		return; +	} +	DRM_ERROR("\"%s\" is not a valid option\n", s); +	return; +} + +/* drm_parse_options parse the insmod "drm=" options, or the command-line + * options passed to the kernel via LILO.  The grammar of the format is as + * follows: + * + * drm		::= 'drm=' option_list + * option_list	::= option [ ';' option_list ] + * option	::= 'device:' major + *		|   'debug' + *		|   'noctx' + * major	::= INTEGER + * + * Note that 's' contains option_list without the 'drm=' part. + * + * device=major,minor specifies the device number used for /dev/drm + *	  if major == 0 then the misc device is used + *	  if major == 0 and minor == 0 then dynamic misc allocation is used + * debug=on specifies that debugging messages will be printk'd + * debug=trace specifies that each function call will be logged via printk + * debug=off turns off all debugging options + * + */ + +void DRM(parse_options)(char *s) +{ +	char *h, *t, *n; + +	DRM_DEBUG("\"%s\"\n", s ?: ""); +	if (!s || !*s) return; + +	for (h = t = n = s; h && *h; h = n) { +		for (; *t && *t != ';'; t++);	       /* find ; or \0 */ +		if (*t) n = t + 1; else n = NULL;      /* remember next */ +		*t = '\0';			       /* terminate */ +		DRM(parse_option)(h);		       /* parse */ +	} +} + +/* drm_cpu_valid returns non-zero if the DRI will run on this CPU, and 0 + * otherwise. + */ +int DRM(cpu_valid)(void) +{ +#if defined(__i386__) +	if (boot_cpu_data.x86 == 3) return 0; /* No cmpxchg on a 386 */ +#endif +#if defined(__sparc__) && !defined(__sparc_v9__) +	return 0; /* No cmpxchg before v9 sparc. */ +#endif +	return 1; +} diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c new file mode 100644 index 00000000..ce6ac2e6 --- /dev/null +++ b/linux-core/drm_ioctl.c @@ -0,0 +1,192 @@ +/* drm_ioctl.h -- IOCTL processing for DRM -*- linux-c -*- + * Created: Fri Jan  8 09:01:26 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int DRM(irq_busid)(struct inode *inode, struct file *filp, +		   unsigned int cmd, unsigned long arg) +{ +	drm_irq_busid_t p; +	struct pci_dev	*dev; + +	if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p))) +		return -EFAULT; +	dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum)); +	if (dev) p.irq = dev->irq; +	else	 p.irq = 0; +	DRM_DEBUG("%d:%d:%d => IRQ %d\n", +		  p.busnum, p.devnum, p.funcnum, p.irq); +	if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p))) +		return -EFAULT; +	return 0; +} + +int DRM(getunique)(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_unique_t	 u; + +	if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u))) +		return -EFAULT; +	if (u.unique_len >= dev->unique_len) { +		if (copy_to_user(u.unique, dev->unique, dev->unique_len)) +			return -EFAULT; +	} +	u.unique_len = dev->unique_len; +	if (copy_to_user((drm_unique_t *)arg, &u, sizeof(u))) +		return -EFAULT; +	return 0; +} + +int DRM(setunique)(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_unique_t	 u; + +	if (dev->unique_len || dev->unique) +		return -EBUSY; + +	if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u))) +		return -EFAULT; + +	if (!u.unique_len) +		return -EINVAL; + +	dev->unique_len = u.unique_len; +	dev->unique	= DRM(alloc)(u.unique_len + 1, DRM_MEM_DRIVER); +	if (copy_from_user(dev->unique, u.unique, dev->unique_len)) +		return -EFAULT; +	dev->unique[dev->unique_len] = '\0'; + +	dev->devname = DRM(alloc)(strlen(dev->name) + strlen(dev->unique) + 2, +				  DRM_MEM_DRIVER); +	sprintf(dev->devname, "%s@%s", dev->name, dev->unique); + +	return 0; +} + + +int DRM(getmap)( 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_map_t    map; +	int          idx; + +	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; +	up(&dev->struct_sem); + +	if (copy_to_user((drm_map_t *)arg, &map, sizeof(map))) return -EFAULT; +	return 0; +} + +int DRM(getclient)( 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_client_t client; +	drm_file_t   *pt; +	int          idx; +	int          i; + +	if (copy_from_user(&client, (drm_client_t *)arg, sizeof(client))) +		return -EFAULT; +	idx = client.idx; +	down(&dev->struct_sem); +	for (i = 0, pt = dev->file_first; i < idx && pt; i++, pt = pt->next) +		; + +	if (!pt) { +		up(&dev->struct_sem); +		return -EINVAL; +	} +	client.auth  = pt->authenticated; +	client.pid   = pt->pid; +	client.uid   = pt->uid; +	client.magic = pt->magic; +	client.iocs  = pt->ioctl_count; +	up(&dev->struct_sem); + +	if (copy_to_user((drm_client_t *)arg, &client, sizeof(client))) +		return -EFAULT; +	return 0; +} + +int DRM(getstats)( 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_stats_t  stats; +	int          i; + +	memset(&stats, 0, sizeof(stats)); +	 +	down(&dev->struct_sem); + +	for (i = 0; i < dev->counters; i++) { +		if (dev->types[i] == _DRM_STAT_LOCK) +			stats.data[i].value +				= (dev->lock.hw_lock +				   ? dev->lock.hw_lock->lock : 0); +		else  +			stats.data[i].value = atomic_read(&dev->counts[i]); +		stats.data[i].type  = dev->types[i]; +	} +	 +	stats.count = dev->counters; + +	up(&dev->struct_sem); + +	if (copy_to_user((drm_stats_t *)arg, &stats, sizeof(stats))) +		return -EFAULT; +	return 0; +} diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c new file mode 100644 index 00000000..c10cfe2c --- /dev/null +++ b/linux-core/drm_lock.c @@ -0,0 +1,251 @@ +/* lock.c -- IOCTLs for locking -*- linux-c -*- + * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include "drmP.h" + +int DRM(block)(struct inode *inode, struct file *filp, unsigned int cmd, +	       unsigned long arg) +{ +	DRM_DEBUG("\n"); +	return 0; +} + +int DRM(unblock)(struct inode *inode, struct file *filp, unsigned int cmd, +		 unsigned long arg) +{ +	DRM_DEBUG("\n"); +	return 0; +} + +int DRM(lock_take)(__volatile__ unsigned int *lock, unsigned int context) +{ +	unsigned int old, new, prev; + +	do { +		old = *lock; +		if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; +		else			  new = context | _DRM_LOCK_HELD; +		prev = cmpxchg(lock, old, new); +	} while (prev != old); +	if (_DRM_LOCKING_CONTEXT(old) == context) { +		if (old & _DRM_LOCK_HELD) { +			if (context != DRM_KERNEL_CONTEXT) { +				DRM_ERROR("%d holds heavyweight lock\n", +					  context); +			} +			return 0; +		} +	} +	if (new == (context | _DRM_LOCK_HELD)) { +				/* Have lock */ +		return 1; +	} +	return 0; +} + +/* This takes a lock forcibly and hands it to context.	Should ONLY be used +   inside *_unlock to give lock to kernel before calling *_dma_schedule. */ +int DRM(lock_transfer)(drm_device_t *dev, +		       __volatile__ unsigned int *lock, unsigned int context) +{ +	unsigned int old, new, prev; + +	dev->lock.pid = 0; +	do { +		old  = *lock; +		new  = context | _DRM_LOCK_HELD; +		prev = cmpxchg(lock, old, new); +	} while (prev != old); +	return 1; +} + +int DRM(lock_free)(drm_device_t *dev, +		   __volatile__ unsigned int *lock, unsigned int context) +{ +	unsigned int old, new, prev; +	pid_t        pid = dev->lock.pid; + +	dev->lock.pid = 0; +	do { +		old  = *lock; +		new  = 0; +		prev = cmpxchg(lock, old, new); +	} while (prev != old); +	if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { +		DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n", +			  context, +			  _DRM_LOCKING_CONTEXT(old), +			  pid); +		return 1; +	} +	wake_up_interruptible(&dev->lock.lock_queue); +	return 0; +} + +static int DRM(flush_queue)(drm_device_t *dev, int context) +{ +	DECLARE_WAITQUEUE(entry, current); +	int		  ret	= 0; +	drm_queue_t	  *q	= dev->queuelist[context]; + +	DRM_DEBUG("\n"); + +	atomic_inc(&q->use_count); +	if (atomic_read(&q->use_count) > 1) { +		atomic_inc(&q->block_write); +		add_wait_queue(&q->flush_queue, &entry); +		atomic_inc(&q->block_count); +		for (;;) { +			current->state = TASK_INTERRUPTIBLE; +			if (!DRM_BUFCOUNT(&q->waitlist)) break; +			schedule(); +			if (signal_pending(current)) { +				ret = -EINTR; /* Can't restart */ +				break; +			} +		} +		atomic_dec(&q->block_count); +		current->state = TASK_RUNNING; +		remove_wait_queue(&q->flush_queue, &entry); +	} +	atomic_dec(&q->use_count); + +				/* NOTE: block_write is still incremented! +				   Use drm_flush_unlock_queue to decrement. */ +	return ret; +} + +static int DRM(flush_unblock_queue)(drm_device_t *dev, int context) +{ +	drm_queue_t	  *q	= dev->queuelist[context]; + +	DRM_DEBUG("\n"); + +	atomic_inc(&q->use_count); +	if (atomic_read(&q->use_count) > 1) { +		if (atomic_read(&q->block_write)) { +			atomic_dec(&q->block_write); +			wake_up_interruptible(&q->write_queue); +		} +	} +	atomic_dec(&q->use_count); +	return 0; +} + +int DRM(flush_block_and_flush)(drm_device_t *dev, int context, +			       drm_lock_flags_t flags) +{ +	int ret = 0; +	int i; + +	DRM_DEBUG("\n"); + +	if (flags & _DRM_LOCK_FLUSH) { +		ret = DRM(flush_queue)(dev, DRM_KERNEL_CONTEXT); +		if (!ret) ret = DRM(flush_queue)(dev, context); +	} +	if (flags & _DRM_LOCK_FLUSH_ALL) { +		for (i = 0; !ret && i < dev->queue_count; i++) { +			ret = DRM(flush_queue)(dev, i); +		} +	} +	return ret; +} + +int DRM(flush_unblock)(drm_device_t *dev, int context, drm_lock_flags_t flags) +{ +	int ret = 0; +	int i; + +	DRM_DEBUG("\n"); + +	if (flags & _DRM_LOCK_FLUSH) { +		ret = DRM(flush_unblock_queue)(dev, DRM_KERNEL_CONTEXT); +		if (!ret) ret = DRM(flush_unblock_queue)(dev, context); +	} +	if (flags & _DRM_LOCK_FLUSH_ALL) { +		for (i = 0; !ret && i < dev->queue_count; i++) { +			ret = DRM(flush_unblock_queue)(dev, i); +		} +	} + +	return ret; +} + +int DRM(finish)(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; +	int		  ret	  = 0; +	drm_lock_t	  lock; + +	DRM_DEBUG("\n"); + +	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) +		return -EFAULT; +	ret = DRM(flush_block_and_flush)(dev, lock.context, lock.flags); +	DRM(flush_unblock)(dev, lock.context, lock.flags); +	return ret; +} + +/* If we get here, it means that the process has called DRM_IOCTL_LOCK +   without calling DRM_IOCTL_UNLOCK. + +   If the lock is not held, then let the signal proceed as usual. + +   If the lock is held, then set the contended flag and keep the signal +   blocked. + + +   Return 1 if the signal should be delivered normally. +   Return 0 if the signal should be blocked.  */ + +int DRM(notifier)(void *priv) +{ +	drm_sigdata_t *s = (drm_sigdata_t *)priv; +	unsigned int  old, new, prev; + + +				/* Allow signal delivery if lock isn't held */ +	if (!_DRM_LOCK_IS_HELD(s->lock->lock) +	    || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1; + +				/* Otherwise, set flag to force call to +                                   drmUnlock */ +	do { +		old  = s->lock->lock; +		new  = old | _DRM_LOCK_CONT; +		prev = cmpxchg(&s->lock->lock, old, new); +	} while (prev != old); +	return 0; +} diff --git a/linux-core/drm_memory.h b/linux-core/drm_memory.h new file mode 100644 index 00000000..caf05394 --- /dev/null +++ b/linux-core/drm_memory.h @@ -0,0 +1,460 @@ +/* drm_memory.h -- Memory management wrappers for DRM -*- linux-c -*- + * Created: Thu Feb  4 14:00:34 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include <linux/config.h> +#include "drmP.h" +#include <linux/wrapper.h> + +typedef struct drm_mem_stats { +	const char	  *name; +	int		  succeed_count; +	int		  free_count; +	int		  fail_count; +	unsigned long	  bytes_allocated; +	unsigned long	  bytes_freed; +} drm_mem_stats_t; + +static spinlock_t	  DRM(mem_lock)	     = SPIN_LOCK_UNLOCKED; +static unsigned long	  DRM(ram_available) = 0; /* In pages */ +static unsigned long	  DRM(ram_used)      = 0; +static drm_mem_stats_t	  DRM(mem_stats)[]   = { +	[DRM_MEM_DMA]	    = { "dmabufs"  }, +	[DRM_MEM_SAREA]	    = { "sareas"   }, +	[DRM_MEM_DRIVER]    = { "driver"   }, +	[DRM_MEM_MAGIC]	    = { "magic"	   }, +	[DRM_MEM_IOCTLS]    = { "ioctltab" }, +	[DRM_MEM_MAPS]	    = { "maplist"  }, +	[DRM_MEM_VMAS]	    = { "vmalist"  }, +	[DRM_MEM_BUFS]	    = { "buflist"  }, +	[DRM_MEM_SEGS]	    = { "seglist"  }, +	[DRM_MEM_PAGES]	    = { "pagelist" }, +	[DRM_MEM_FILES]	    = { "files"	   }, +	[DRM_MEM_QUEUES]    = { "queues"   }, +	[DRM_MEM_CMDS]	    = { "commands" }, +	[DRM_MEM_MAPPINGS]  = { "mappings" }, +	[DRM_MEM_BUFLISTS]  = { "buflists" }, +	[DRM_MEM_AGPLISTS]  = { "agplist"  }, +	[DRM_MEM_TOTALAGP]  = { "totalagp" }, +	[DRM_MEM_BOUNDAGP]  = { "boundagp" }, +	[DRM_MEM_CTXBITMAP] = { "ctxbitmap"}, +	[DRM_MEM_STUB]      = { "stub"     }, +	{ NULL, 0, }		/* Last entry must be null */ +}; + +void DRM(mem_init)(void) +{ +	drm_mem_stats_t *mem; +	struct sysinfo	si; + +	for (mem = DRM(mem_stats); mem->name; ++mem) { +		mem->succeed_count   = 0; +		mem->free_count	     = 0; +		mem->fail_count	     = 0; +		mem->bytes_allocated = 0; +		mem->bytes_freed     = 0; +	} + +	si_meminfo(&si); +#if LINUX_VERSION_CODE < 0x020317 +				/* Changed to page count in 2.3.23 */ +	DRM(ram_available) = si.totalram >> PAGE_SHIFT; +#else +	DRM(ram_available) = si.totalram; +#endif +	DRM(ram_used)	   = 0; +} + +/* drm_mem_info is called whenever a process reads /dev/drm/mem. */ + +static int DRM(_mem_info)(char *buf, char **start, off_t offset, +			  int request, int *eof, void *data) +{ +	drm_mem_stats_t *pt; +	int             len = 0; + +	if (offset > DRM_PROC_LIMIT) { +		*eof = 1; +		return 0; +	} + +	*eof   = 0; +	*start = &buf[offset]; + +	DRM_PROC_PRINT("		  total counts			" +		       " |    outstanding  \n"); +	DRM_PROC_PRINT("type	   alloc freed fail	bytes	   freed" +		       " | allocs      bytes\n\n"); +	DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB         |\n", +		       "system", 0, 0, 0, +		       DRM(ram_available) << (PAGE_SHIFT - 10)); +	DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB         |\n", +		       "locked", 0, 0, 0, DRM(ram_used) >> 10); +	DRM_PROC_PRINT("\n"); +	for (pt = DRM(mem_stats); pt->name; pt++) { +		DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n", +			       pt->name, +			       pt->succeed_count, +			       pt->free_count, +			       pt->fail_count, +			       pt->bytes_allocated, +			       pt->bytes_freed, +			       pt->succeed_count - pt->free_count, +			       (long)pt->bytes_allocated +			       - (long)pt->bytes_freed); +	} + +	if (len > request + offset) return request; +	*eof = 1; +	return len - offset; +} + +int DRM(mem_info)(char *buf, char **start, off_t offset, +		  int len, int *eof, void *data) +{ +	int ret; + +	spin_lock(&DRM(mem_lock)); +	ret = DRM(_mem_info)(buf, start, offset, len, eof, data); +	spin_unlock(&DRM(mem_lock)); +	return ret; +} + +void *DRM(alloc)(size_t size, int area) +{ +	void *pt; + +	if (!size) { +		DRM_MEM_ERROR(area, "Allocating 0 bytes\n"); +		return NULL; +	} + +	if (!(pt = kmalloc(size, GFP_KERNEL))) { +		spin_lock(&DRM(mem_lock)); +		++DRM(mem_stats)[area].fail_count; +		spin_unlock(&DRM(mem_lock)); +		return NULL; +	} +	spin_lock(&DRM(mem_lock)); +	++DRM(mem_stats)[area].succeed_count; +	DRM(mem_stats)[area].bytes_allocated += size; +	spin_unlock(&DRM(mem_lock)); +	return pt; +} + +void *DRM(realloc)(void *oldpt, size_t oldsize, size_t size, int area) +{ +	void *pt; + +	if (!(pt = DRM(alloc)(size, area))) return NULL; +	if (oldpt && oldsize) { +		memcpy(pt, oldpt, oldsize); +		DRM(free)(oldpt, oldsize, area); +	} +	return pt; +} + +char *DRM(strdup)(const char *s, int area) +{ +	char *pt; +	int	 length = s ? strlen(s) : 0; + +	if (!(pt = DRM(alloc)(length+1, area))) return NULL; +	strcpy(pt, s); +	return pt; +} + +void DRM(strfree)(const char *s, int area) +{ +	unsigned int size; + +	if (!s) return; + +	size = 1 + (s ? strlen(s) : 0); +	DRM(free)((void *)s, size, area); +} + +void DRM(free)(void *pt, size_t size, int area) +{ +	int alloc_count; +	int free_count; + +	if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n"); +	else	 kfree(pt); +	spin_lock(&DRM(mem_lock)); +	DRM(mem_stats)[area].bytes_freed += size; +	free_count  = ++DRM(mem_stats)[area].free_count; +	alloc_count =	DRM(mem_stats)[area].succeed_count; +	spin_unlock(&DRM(mem_lock)); +	if (free_count > alloc_count) { +		DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n", +			      free_count, alloc_count); +	} +} + +unsigned long DRM(alloc_pages)(int order, int area) +{ +	unsigned long address; +	unsigned long bytes	  = PAGE_SIZE << order; +	unsigned long addr; +	unsigned int  sz; + +	spin_lock(&DRM(mem_lock)); +	if ((DRM(ram_used) >> PAGE_SHIFT) +	    > (DRM_RAM_PERCENT * DRM(ram_available)) / 100) { +		spin_unlock(&DRM(mem_lock)); +		return 0; +	} +	spin_unlock(&DRM(mem_lock)); + +	address = __get_free_pages(GFP_KERNEL, order); +	if (!address) { +		spin_lock(&DRM(mem_lock)); +		++DRM(mem_stats)[area].fail_count; +		spin_unlock(&DRM(mem_lock)); +		return 0; +	} +	spin_lock(&DRM(mem_lock)); +	++DRM(mem_stats)[area].succeed_count; +	DRM(mem_stats)[area].bytes_allocated += bytes; +	DRM(ram_used)		             += bytes; +	spin_unlock(&DRM(mem_lock)); + + +				/* Zero outside the lock */ +	memset((void *)address, 0, bytes); + +				/* Reserve */ +	for (addr = address, sz = bytes; +	     sz > 0; +	     addr += PAGE_SIZE, sz -= PAGE_SIZE) { +#if LINUX_VERSION_CODE >= 0x020400 +				/* Argument type changed in 2.4.0-test6/pre8 */ +		mem_map_reserve(virt_to_page(addr)); +#else +		mem_map_reserve(MAP_NR(addr)); +#endif +	} + +	return address; +} + +void DRM(free_pages)(unsigned long address, int order, int area) +{ +	unsigned long bytes = PAGE_SIZE << order; +	int		  alloc_count; +	int		  free_count; +	unsigned long addr; +	unsigned int  sz; + +	if (!address) { +		DRM_MEM_ERROR(area, "Attempt to free address 0\n"); +	} else { +				/* Unreserve */ +		for (addr = address, sz = bytes; +		     sz > 0; +		     addr += PAGE_SIZE, sz -= PAGE_SIZE) { +#if LINUX_VERSION_CODE >= 0x020400 +				/* Argument type changed in 2.4.0-test6/pre8 */ +			mem_map_unreserve(virt_to_page(addr)); +#else +			mem_map_unreserve(MAP_NR(addr)); +#endif +		} +		free_pages(address, order); +	} + +	spin_lock(&DRM(mem_lock)); +	free_count  = ++DRM(mem_stats)[area].free_count; +	alloc_count =	DRM(mem_stats)[area].succeed_count; +	DRM(mem_stats)[area].bytes_freed += bytes; +	DRM(ram_used)			 -= bytes; +	spin_unlock(&DRM(mem_lock)); +	if (free_count > alloc_count) { +		DRM_MEM_ERROR(area, +			      "Excess frees: %d frees, %d allocs\n", +			      free_count, alloc_count); +	} +} + +void *DRM(ioremap)(unsigned long offset, unsigned long size) +{ +	void *pt; + +	if (!size) { +		DRM_MEM_ERROR(DRM_MEM_MAPPINGS, +			      "Mapping 0 bytes at 0x%08lx\n", offset); +		return NULL; +	} + +	if (!(pt = ioremap(offset, size))) { +		spin_lock(&DRM(mem_lock)); +		++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; +		spin_unlock(&DRM(mem_lock)); +		return NULL; +	} +	spin_lock(&DRM(mem_lock)); +	++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; +	DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; +	spin_unlock(&DRM(mem_lock)); +	return pt; +} + +void DRM(ioremapfree)(void *pt, unsigned long size) +{ +	int alloc_count; +	int free_count; + +	if (!pt) +		DRM_MEM_ERROR(DRM_MEM_MAPPINGS, +			      "Attempt to free NULL pointer\n"); +	else +		iounmap(pt); + +	spin_lock(&DRM(mem_lock)); +	DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_freed += size; +	free_count  = ++DRM(mem_stats)[DRM_MEM_MAPPINGS].free_count; +	alloc_count =	DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; +	spin_unlock(&DRM(mem_lock)); +	if (free_count > alloc_count) { +		DRM_MEM_ERROR(DRM_MEM_MAPPINGS, +			      "Excess frees: %d frees, %d allocs\n", +			      free_count, alloc_count); +	} +} + +#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) +#if __MUST_HAVE_AGP + +agp_memory *DRM(alloc_agp)(int pages, u32 type) +{ +	agp_memory *handle; + +	if (!pages) { +		DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n"); +		return NULL; +	} + +	if ((handle = DRM(agp_allocate_memory)(pages, type))) { +		spin_lock(&DRM(mem_lock)); +		++DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count; +		DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_allocated +			+= pages << PAGE_SHIFT; +		spin_unlock(&DRM(mem_lock)); +		return handle; +	} +	spin_lock(&DRM(mem_lock)); +	++DRM(mem_stats)[DRM_MEM_TOTALAGP].fail_count; +	spin_unlock(&DRM(mem_lock)); +	return NULL; +} + +int DRM(free_agp)(agp_memory *handle, int pages) +{ +	int           alloc_count; +	int           free_count; +	int           retval = -EINVAL; + +	if (!handle) { +		DRM_MEM_ERROR(DRM_MEM_TOTALAGP, +			      "Attempt to free NULL AGP handle\n"); +		return retval;; +	} + +	if (DRM(agp_free_memory)(handle)) { +		spin_lock(&DRM(mem_lock)); +		free_count  = ++DRM(mem_stats)[DRM_MEM_TOTALAGP].free_count; +		alloc_count =   DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count; +		DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_freed +			+= pages << PAGE_SHIFT; +		spin_unlock(&DRM(mem_lock)); +		if (free_count > alloc_count) { +			DRM_MEM_ERROR(DRM_MEM_TOTALAGP, +				      "Excess frees: %d frees, %d allocs\n", +				      free_count, alloc_count); +		} +		return 0; +	} +	return retval; +} + +int DRM(bind_agp)(agp_memory *handle, unsigned int start) +{ +	int retcode = -EINVAL; + +	if (!handle) { +		DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, +			      "Attempt to bind NULL AGP handle\n"); +		return retcode; +	} + +	if (!(retcode = DRM(agp_bind_memory)(handle, start))) { +		spin_lock(&DRM(mem_lock)); +		++DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count; +		DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_allocated +			+= handle->page_count << PAGE_SHIFT; +		spin_unlock(&DRM(mem_lock)); +		return retcode; +	} +	spin_lock(&DRM(mem_lock)); +	++DRM(mem_stats)[DRM_MEM_BOUNDAGP].fail_count; +	spin_unlock(&DRM(mem_lock)); +	return retcode; +} + +int DRM(unbind_agp)(agp_memory *handle) +{ +	int alloc_count; +	int free_count; +	int retcode = -EINVAL; + +	if (!handle) { +		DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, +			      "Attempt to unbind NULL AGP handle\n"); +		return retcode; +	} + +	if ((retcode = DRM(agp_unbind_memory)(handle))) return retcode; +	spin_lock(&DRM(mem_lock)); +	free_count  = ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].free_count; +	alloc_count = DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count; +	DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_freed +		+= handle->page_count << PAGE_SHIFT; +	spin_unlock(&DRM(mem_lock)); +	if (free_count > alloc_count) { +		DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, +			      "Excess frees: %d frees, %d allocs\n", +			      free_count, alloc_count); +	} +	return retcode; +} +#endif +#endif /* defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) */ diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c new file mode 100644 index 00000000..634673d9 --- /dev/null +++ b/linux-core/drm_proc.c @@ -0,0 +1,623 @@ +/* drm_proc.h -- /proc support for DRM -*- linux-c -*- + * Created: Mon Jan 11 09:48:47 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + * + * Acknowledgements: + *    Matthew J Sottek <matthew.j.sottek@intel.com> sent in a patch to fix + *    the problem with the proc files not outputting all their information. + */ + +#define __NO_VERSION__ +#include "drmP.h" + +static int	   DRM(name_info)(char *buf, char **start, off_t offset, +				  int request, int *eof, void *data); +static int	   DRM(vm_info)(char *buf, char **start, off_t offset, +				int request, int *eof, void *data); +static int	   DRM(clients_info)(char *buf, char **start, off_t offset, +				     int request, int *eof, void *data); +static int	   DRM(queues_info)(char *buf, char **start, off_t offset, +				    int request, int *eof, void *data); +static int	   DRM(bufs_info)(char *buf, char **start, off_t offset, +				  int request, int *eof, void *data); +#if DRM_DEBUG_CODE +static int	   DRM(vma_info)(char *buf, char **start, off_t offset, +				 int request, int *eof, void *data); +#endif +#if DRM_DMA_HISTOGRAM +static int	   DRM(histo_info)(char *buf, char **start, off_t offset, +				   int request, int *eof, void *data); +#endif + +struct drm_proc_list { +	const char *name; +	int	   (*f)(char *, char **, off_t, int, int *, void *); +} DRM(proc_list)[] = { +	{ "name",    DRM(name_info)    }, +	{ "mem",     DRM(mem_info)     }, +	{ "vm",	     DRM(vm_info)      }, +	{ "clients", DRM(clients_info) }, +	{ "queues",  DRM(queues_info)  }, +	{ "bufs",    DRM(bufs_info)    }, +#if DRM_DEBUG_CODE +	{ "vma",     DRM(vma_info)     }, +#endif +#if DRM_DMA_HISTOGRAM +	{ "histo",   DRM(histo_info)   }, +#endif +}; +#define DRM_PROC_ENTRIES (sizeof(DRM(proc_list))/sizeof(DRM(proc_list)[0])) + +struct proc_dir_entry *DRM(proc_init)(drm_device_t *dev, int minor, +				      struct proc_dir_entry *root, +				      struct proc_dir_entry **dev_root) +{ +	struct proc_dir_entry *ent; +	int		      i, j; +	char                  name[64]; + +	if (!minor) root = create_proc_entry("dri", S_IFDIR, NULL); +	if (!root) { +		DRM_ERROR("Cannot create /proc/dri\n"); +		return NULL; +	} + +	sprintf(name, "%d", minor); +	*dev_root = create_proc_entry(name, S_IFDIR, root); +	if (!*dev_root) { +		DRM_ERROR("Cannot create /proc/%s\n", name); +		return NULL; +	} + +	for (i = 0; i < DRM_PROC_ENTRIES; i++) { +		ent = create_proc_entry(DRM(proc_list)[i].name, +					S_IFREG|S_IRUGO, *dev_root); +		if (!ent) { +			DRM_ERROR("Cannot create /proc/dri/%s/%s\n", +				  name, DRM(proc_list)[i].name); +			for (j = 0; j < i; j++) +				remove_proc_entry(DRM(proc_list)[i].name, +						  *dev_root); +			remove_proc_entry(name, root); +			if (!minor) remove_proc_entry("dri", NULL); +			return NULL; +		} +		ent->read_proc = DRM(proc_list)[i].f; +		ent->data      = dev; +	} + +	return root; +} + + +int DRM(proc_cleanup)(int minor, struct proc_dir_entry *root, +		      struct proc_dir_entry *dev_root) +{ +	int  i; +	char name[64]; + +	if (!root || !dev_root) return 0; + +	for (i = 0; i < DRM_PROC_ENTRIES; i++) +		remove_proc_entry(DRM(proc_list)[i].name, dev_root); +	sprintf(name, "%d", minor); +	remove_proc_entry(name, root); +	if (!minor) remove_proc_entry("dri", NULL); + +	return 0; +} + +static int DRM(name_info)(char *buf, char **start, off_t offset, int request, +			  int *eof, void *data) +{ +	drm_device_t *dev = (drm_device_t *)data; +	int          len  = 0; + +	if (offset > DRM_PROC_LIMIT) { +		*eof = 1; +		return 0; +	} + +	*start = &buf[offset]; +	*eof   = 0; + +	if (dev->unique) { +		DRM_PROC_PRINT("%s 0x%x %s\n", +			       dev->name, dev->device, dev->unique); +	} else { +		DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device); +	} + +	if (len > request + offset) return request; +	*eof = 1; +	return len - offset; +} + +static int DRM(_vm_info)(char *buf, char **start, off_t offset, int request, +			 int *eof, void *data) +{ +	drm_device_t *dev = (drm_device_t *)data; +	int          len  = 0; +	drm_map_t    *map; +				/* Hardcoded from _DRM_FRAME_BUFFER, +                                   _DRM_REGISTERS, _DRM_SHM, and +                                   _DRM_AGP. */ +	const char   *types[] = { "FB", "REG", "SHM", "AGP" }; +	const char   *type; +	int	     i; + +	if (offset > DRM_PROC_LIMIT) { +		*eof = 1; +		return 0; +	} + +	*start = &buf[offset]; +	*eof   = 0; + +	DRM_PROC_PRINT("slot	 offset	      size type flags	 " +		       "address mtrr\n\n"); +	for (i = 0; i < dev->map_count; i++) { +		map = dev->maplist[i]; +		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 ", +			       i, +			       map->offset, +			       map->size, +			       type, +			       map->flags, +			       (unsigned long)map->handle); +		if (map->mtrr < 0) { +			DRM_PROC_PRINT("none\n"); +		} else { +			DRM_PROC_PRINT("%4d\n", map->mtrr); +		} +	} + +	if (len > request + offset) return request; +	*eof = 1; +	return len - offset; +} + +static int DRM(vm_info)(char *buf, char **start, off_t offset, int request, +			int *eof, void *data) +{ +	drm_device_t *dev = (drm_device_t *)data; +	int	     ret; + +	down(&dev->struct_sem); +	ret = DRM(_vm_info)(buf, start, offset, request, eof, data); +	up(&dev->struct_sem); +	return ret; +} + + +static int DRM(_queues_info)(char *buf, char **start, off_t offset, +			     int request, int *eof, void *data) +{ +	drm_device_t *dev = (drm_device_t *)data; +	int          len  = 0; +	int	     i; +	drm_queue_t  *q; + +	if (offset > DRM_PROC_LIMIT) { +		*eof = 1; +		return 0; +	} + +	*start = &buf[offset]; +	*eof   = 0; + +	DRM_PROC_PRINT("  ctx/flags   use   fin" +		       "   blk/rw/rwf  wait    flushed	   queued" +		       "      locks\n\n"); +	for (i = 0; i < dev->queue_count; i++) { +		q = dev->queuelist[i]; +		atomic_inc(&q->use_count); +		DRM_PROC_PRINT_RET(atomic_dec(&q->use_count), +				   "%5d/0x%03x %5d %5d" +				   " %5d/%c%c/%c%c%c %5Zd\n", +				   i, +				   q->flags, +				   atomic_read(&q->use_count), +				   atomic_read(&q->finalization), +				   atomic_read(&q->block_count), +				   atomic_read(&q->block_read) ? 'r' : '-', +				   atomic_read(&q->block_write) ? 'w' : '-', +				   waitqueue_active(&q->read_queue) ? 'r':'-', +				   waitqueue_active(&q->write_queue) ? 'w':'-', +				   waitqueue_active(&q->flush_queue) ? 'f':'-', +				   DRM_BUFCOUNT(&q->waitlist)); +		atomic_dec(&q->use_count); +	} + +	if (len > request + offset) return request; +	*eof = 1; +	return len - offset; +} + +static int DRM(queues_info)(char *buf, char **start, off_t offset, int request, +			    int *eof, void *data) +{ +	drm_device_t *dev = (drm_device_t *)data; +	int	     ret; + +	down(&dev->struct_sem); +	ret = DRM(_queues_info)(buf, start, offset, request, eof, data); +	up(&dev->struct_sem); +	return ret; +} + +/* drm_bufs_info is called whenever a process reads +   /dev/dri/<dev>/bufs. */ + +static int DRM(_bufs_info)(char *buf, char **start, off_t offset, int request, +			   int *eof, void *data) +{ +	drm_device_t	 *dev = (drm_device_t *)data; +	int              len  = 0; +	drm_device_dma_t *dma = dev->dma; +	int		 i; + +	if (!dma || offset > DRM_PROC_LIMIT) { +		*eof = 1; +		return 0; +	} + +	*start = &buf[offset]; +	*eof   = 0; + +	DRM_PROC_PRINT(" o     size count  free	 segs pages    kB\n\n"); +	for (i = 0; i <= DRM_MAX_ORDER; i++) { +		if (dma->bufs[i].buf_count) +			DRM_PROC_PRINT("%2d %8d %5d %5d %5d %5d %5ld\n", +				       i, +				       dma->bufs[i].buf_size, +				       dma->bufs[i].buf_count, +				       atomic_read(&dma->bufs[i] +						   .freelist.count), +				       dma->bufs[i].seg_count, +				       dma->bufs[i].seg_count +				       *(1 << dma->bufs[i].page_order), +				       (dma->bufs[i].seg_count +					* (1 << dma->bufs[i].page_order)) +				       * PAGE_SIZE / 1024); +	} +	DRM_PROC_PRINT("\n"); +	for (i = 0; i < dma->buf_count; i++) { +		if (i && !(i%32)) DRM_PROC_PRINT("\n"); +		DRM_PROC_PRINT(" %d", dma->buflist[i]->list); +	} +	DRM_PROC_PRINT("\n"); + +	if (len > request + offset) return request; +	*eof = 1; +	return len - offset; +} + +static int DRM(bufs_info)(char *buf, char **start, off_t offset, int request, +			  int *eof, void *data) +{ +	drm_device_t *dev = (drm_device_t *)data; +	int	     ret; + +	down(&dev->struct_sem); +	ret = DRM(_bufs_info)(buf, start, offset, request, eof, data); +	up(&dev->struct_sem); +	return ret; +} + + +static int DRM(_clients_info)(char *buf, char **start, off_t offset, +			      int request, int *eof, void *data) +{ +	drm_device_t *dev = (drm_device_t *)data; +	int          len  = 0; +	drm_file_t   *priv; + +	if (offset > DRM_PROC_LIMIT) { +		*eof = 1; +		return 0; +	} + +	*start = &buf[offset]; +	*eof   = 0; + +	DRM_PROC_PRINT("a dev	pid    uid	magic	  ioctls\n\n"); +	for (priv = dev->file_first; priv; priv = priv->next) { +		DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n", +			       priv->authenticated ? 'y' : 'n', +			       priv->minor, +			       priv->pid, +			       priv->uid, +			       priv->magic, +			       priv->ioctl_count); +	} + +	if (len > request + offset) return request; +	*eof = 1; +	return len - offset; +} + +static int DRM(clients_info)(char *buf, char **start, off_t offset, +			     int request, int *eof, void *data) +{ +	drm_device_t *dev = (drm_device_t *)data; +	int	     ret; + +	down(&dev->struct_sem); +	ret = DRM(_clients_info)(buf, start, offset, request, eof, data); +	up(&dev->struct_sem); +	return ret; +} + +#if DRM_DEBUG_CODE + +#define DRM_VMA_VERBOSE 0 + +static int DRM(_vma_info)(char *buf, char **start, off_t offset, int request, +			  int *eof, void *data) +{ +	drm_device_t	      *dev = (drm_device_t *)data; +	int                   len  = 0; +	drm_vma_entry_t	      *pt; +	struct vm_area_struct *vma; +#if DRM_VMA_VERBOSE +	unsigned long	      i; +	unsigned long	      address; +	pgd_t		      *pgd; +	pmd_t		      *pmd; +	pte_t		      *pte; +#endif +#if defined(__i386__) +	unsigned int	      pgprot; +#endif + +	if (offset > DRM_PROC_LIMIT) { +		*eof = 1; +		return 0; +	} + +	*start = &buf[offset]; +	*eof   = 0; + +	DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n", +		       atomic_read(&dev->vma_count), +		       high_memory, virt_to_phys(high_memory)); +	for (pt = dev->vmalist; pt; pt = pt->next) { +		if (!(vma = pt->vma)) continue; +		DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx", +			       pt->pid, +			       vma->vm_start, +			       vma->vm_end, +			       vma->vm_flags & VM_READ	   ? 'r' : '-', +			       vma->vm_flags & VM_WRITE	   ? 'w' : '-', +			       vma->vm_flags & VM_EXEC	   ? 'x' : '-', +			       vma->vm_flags & VM_MAYSHARE ? 's' : 'p', +			       vma->vm_flags & VM_LOCKED   ? 'l' : '-', +			       vma->vm_flags & VM_IO	   ? 'i' : '-', +			       VM_OFFSET(vma)); + +#if defined(__i386__) +		pgprot = pgprot_val(vma->vm_page_prot); +		DRM_PROC_PRINT(" %c%c%c%c%c%c%c%c%c", +			       pgprot & _PAGE_PRESENT  ? 'p' : '-', +			       pgprot & _PAGE_RW       ? 'w' : 'r', +			       pgprot & _PAGE_USER     ? 'u' : 's', +			       pgprot & _PAGE_PWT      ? 't' : 'b', +			       pgprot & _PAGE_PCD      ? 'u' : 'c', +			       pgprot & _PAGE_ACCESSED ? 'a' : '-', +			       pgprot & _PAGE_DIRTY    ? 'd' : '-', +			       pgprot & _PAGE_PSE      ? 'm' : 'k', +			       pgprot & _PAGE_GLOBAL   ? 'g' : 'l' ); +#endif +		DRM_PROC_PRINT("\n"); +#if 0 +		for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) { +			pgd = pgd_offset(vma->vm_mm, i); +			pmd = pmd_offset(pgd, i); +			pte = pte_offset(pmd, i); +			if (pte_present(*pte)) { +				address = __pa(pte_page(*pte)) +					+ (i & (PAGE_SIZE-1)); +				DRM_PROC_PRINT("      0x%08lx -> 0x%08lx" +					       " %c%c%c%c%c\n", +					       i, +					       address, +					       pte_read(*pte)  ? 'r' : '-', +					       pte_write(*pte) ? 'w' : '-', +					       pte_exec(*pte)  ? 'x' : '-', +					       pte_dirty(*pte) ? 'd' : '-', +					       pte_young(*pte) ? 'a' : '-' ); +			} else { +				DRM_PROC_PRINT("      0x%08lx\n", i); +			} +		} +#endif +	} + +	if (len > request + offset) return request; +	*eof = 1; +	return len - offset; +} + +static int DRM(vma_info)(char *buf, char **start, off_t offset, int request, +			 int *eof, void *data) +{ +	drm_device_t *dev = (drm_device_t *)data; +	int	     ret; + +	down(&dev->struct_sem); +	ret = DRM(_vma_info)(buf, start, offset, request, eof, data); +	up(&dev->struct_sem); +	return ret; +} +#endif + + +#if DRM_DMA_HISTOGRAM +static int DRM(_histo_info)(char *buf, char **start, off_t offset, int request, +			    int *eof, void *data) +{ +	drm_device_t	 *dev = (drm_device_t *)data; +	int              len  = 0; +	drm_device_dma_t *dma = dev->dma; +	int		 i; +	unsigned long	 slot_value = DRM_DMA_HISTOGRAM_INITIAL; +	unsigned long	 prev_value = 0; +	drm_buf_t	 *buffer; + +	if (offset > DRM_PROC_LIMIT) { +		*eof = 1; +		return 0; +	} + +	*start = &buf[offset]; +	*eof   = 0; + +	DRM_PROC_PRINT("general statistics:\n"); +	DRM_PROC_PRINT("total	 %10u\n", atomic_read(&dev->histo.total)); +	DRM_PROC_PRINT("open	 %10u\n", +		       atomic_read(&dev->counts[_DRM_STAT_OPENS])); +	DRM_PROC_PRINT("close	 %10u\n", +		       atomic_read(&dev->counts[_DRM_STAT_CLOSES])); +	DRM_PROC_PRINT("ioctl	 %10u\n", +		       atomic_read(&dev->counts[_DRM_STAT_IOCTLS])); + +	DRM_PROC_PRINT("\nlock statistics:\n"); +	DRM_PROC_PRINT("locks	 %10u\n", +		       atomic_read(&dev->counts[_DRM_STAT_LOCKS])); +	DRM_PROC_PRINT("unlocks	 %10u\n", +		       atomic_read(&dev->counts[_DRM_STAT_UNLOCKS])); + +	if (dma) { +#if 0 +		DRM_PROC_PRINT("\ndma statistics:\n"); +		DRM_PROC_PRINT("prio	 %10u\n", +			       atomic_read(&dma->total_prio)); +		DRM_PROC_PRINT("bytes	 %10u\n", +			       atomic_read(&dma->total_bytes)); +		DRM_PROC_PRINT("dmas	 %10u\n", +			       atomic_read(&dma->total_dmas)); +		DRM_PROC_PRINT("missed:\n"); +		DRM_PROC_PRINT("  dma	 %10u\n", +			       atomic_read(&dma->total_missed_dma)); +		DRM_PROC_PRINT("  lock	 %10u\n", +			       atomic_read(&dma->total_missed_lock)); +		DRM_PROC_PRINT("  free	 %10u\n", +			       atomic_read(&dma->total_missed_free)); +		DRM_PROC_PRINT("  sched	 %10u\n", +			       atomic_read(&dma->total_missed_sched)); +		DRM_PROC_PRINT("tried	 %10u\n", +			       atomic_read(&dma->total_tried)); +		DRM_PROC_PRINT("hit	 %10u\n", +			       atomic_read(&dma->total_hit)); +		DRM_PROC_PRINT("lost	 %10u\n", +			       atomic_read(&dma->total_lost)); +#endif + +		buffer = dma->next_buffer; +		if (buffer) { +			DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx); +		} else { +			DRM_PROC_PRINT("next_buffer    none\n"); +		} +		buffer = dma->this_buffer; +		if (buffer) { +			DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx); +		} else { +			DRM_PROC_PRINT("this_buffer    none\n"); +		} +	} + + +	DRM_PROC_PRINT("\nvalues:\n"); +	if (dev->lock.hw_lock) { +		DRM_PROC_PRINT("lock	       0x%08x\n", +			       dev->lock.hw_lock->lock); +	} else { +		DRM_PROC_PRINT("lock		     none\n"); +	} +	DRM_PROC_PRINT("context_flag   0x%08lx\n", dev->context_flag); +	DRM_PROC_PRINT("interrupt_flag 0x%08lx\n", dev->interrupt_flag); +	DRM_PROC_PRINT("dma_flag       0x%08lx\n", dev->dma_flag); + +	DRM_PROC_PRINT("queue_count    %10d\n",	 dev->queue_count); +	DRM_PROC_PRINT("last_context   %10d\n",	 dev->last_context); +	DRM_PROC_PRINT("last_switch    %10lu\n", dev->last_switch); +	DRM_PROC_PRINT("last_checked   %10d\n",	 dev->last_checked); + + +	DRM_PROC_PRINT("\n		       q2d	  d2c	     c2f" +		       "	q2c	   q2f	      dma	 sch" +		       "	ctx	  lacq	     lhld\n\n"); +	for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) { +		DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u" +			       " %10u %10u %10u %10u %10u\n", +			       i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ", +			       i == DRM_DMA_HISTOGRAM_SLOTS - 1 +			       ? prev_value : slot_value , + +			       atomic_read(&dev->histo +					   .queued_to_dispatched[i]), +			       atomic_read(&dev->histo +					   .dispatched_to_completed[i]), +			       atomic_read(&dev->histo +					   .completed_to_freed[i]), + +			       atomic_read(&dev->histo +					   .queued_to_completed[i]), +			       atomic_read(&dev->histo +					   .queued_to_freed[i]), +			       atomic_read(&dev->histo.dma[i]), +			       atomic_read(&dev->histo.schedule[i]), +			       atomic_read(&dev->histo.ctx[i]), +			       atomic_read(&dev->histo.lacq[i]), +			       atomic_read(&dev->histo.lhld[i])); +		prev_value = slot_value; +		slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value); +	} + +	if (len > request + offset) return request; +	*eof = 1; +	return len - offset; +} + +static int DRM(histo_info)(char *buf, char **start, off_t offset, int request, +			   int *eof, void *data) +{ +	drm_device_t *dev = (drm_device_t *)data; +	int	     ret; + +	down(&dev->struct_sem); +	ret = DRM(_histo_info)(buf, start, offset, request, eof, data); +	up(&dev->struct_sem); +	return ret; +} +#endif diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c new file mode 100644 index 00000000..ed37af4d --- /dev/null +++ b/linux-core/drm_stub.c @@ -0,0 +1,142 @@ +/* drm_stub.c -- -*- linux-c -*- + * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org + * + * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + * + */ + +#define DRM_STUB_MAXCARDS 16	/* Enough for one machine */ + +static struct drm_stub_list { +	const char             *name; +	struct file_operations *fops; +	struct proc_dir_entry  *dev_root; +} *DRM(stub_list); + +static struct proc_dir_entry *DRM(stub_root); + +static struct drm_stub_info { +	int (*info_register)(const char *name, struct file_operations *fops, +			     drm_device_t *dev); +	int (*info_unregister)(int minor); +} DRM(stub_info); + +static int DRM(stub_open)(struct inode *inode, struct file *filp) +{ +	int                    minor = MINOR(inode->i_rdev); +	int                    err   = -ENODEV; +	struct file_operations *old_fops; + +	if (!DRM(stub_list) || !DRM(stub_list)[minor].fops) return -ENODEV; +	old_fops   = filp->f_op; +	filp->f_op = fops_get(DRM(stub_list)[minor].fops); +	if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) { +		fops_put(filp->f_op); +		filp->f_op = fops_get(old_fops); +	} +	fops_put(old_fops); +		 +	return err; +} + +static struct file_operations DRM(stub_fops) = { +#if LINUX_VERSION_CODE >= 0x020400 +	owner:   THIS_MODULE, +#endif +	open:	 DRM(stub_open) +}; + +static int DRM(stub_getminor)(const char *name, struct file_operations *fops, +			      drm_device_t *dev) +{ +	int i; +	 +	if (!DRM(stub_list)) { +		DRM(stub_list) = DRM(alloc)(sizeof(*DRM(stub_list)) +					    * DRM_STUB_MAXCARDS, DRM_MEM_STUB); +		for (i = 0; i < DRM_STUB_MAXCARDS; i++) { +			DRM(stub_list)[i].name = NULL; +			DRM(stub_list)[i].fops = NULL; +		} +	} +	for (i = 0; i < DRM_STUB_MAXCARDS; i++) { +		if (!DRM(stub_list)[i].fops) { +			DRM(stub_list)[i].name = name; +			DRM(stub_list)[i].fops = fops; +			DRM(stub_root) = DRM(proc_init)(dev, i, DRM(stub_root), +							&DRM(stub_list)[i] +							.dev_root); +			return i; +		} +	} +	return -1; +} + +static int DRM(stub_putminor)(int minor) +{ +	if (minor < 0 || minor >= DRM_STUB_MAXCARDS) return -1; +	DRM(stub_list)[minor].name = NULL; +	DRM(stub_list)[minor].fops = NULL; +	DRM(proc_cleanup)(minor, DRM(stub_root), +			  DRM(stub_list)[minor].dev_root); +	if (minor) { +		inter_module_put("drm"); +	} else { +		inter_module_unregister("drm"); +		DRM(free)(DRM(stub_list), +			  sizeof(*DRM(stub_list)) * DRM_STUB_MAXCARDS, +			  DRM_MEM_STUB); +		unregister_chrdev(DRM_MAJOR, "drm"); +	} +	return 0; +} + +int DRM(stub_register)(const char *name, struct file_operations *fops, +		       drm_device_t *dev) +{ +	if (register_chrdev(DRM_MAJOR, "drm", &DRM(stub_fops))) { +				/* Already registered */ +		struct drm_stub_info *i; +		i = (struct drm_stub_info *)inter_module_get("drm"); +		DRM(stub_info).info_register   = i->info_register; +		DRM(stub_info).info_unregister = i->info_unregister; +	} else { +		DRM(stub_info).info_register   = DRM(stub_getminor); +		DRM(stub_info).info_unregister = DRM(stub_putminor); +		inter_module_register("drm", THIS_MODULE, &DRM(stub_info)); +	} +	if (DRM(stub_info).info_register) +		return DRM(stub_info).info_register(name, fops, dev); +	return -1; +} + +int DRM(stub_unregister)(int minor) +{ +	DRM_DEBUG("%d\n", minor); +	if (DRM(stub_info).info_unregister) +		return DRM(stub_info).info_unregister(minor); +	return -1; +} diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c new file mode 100644 index 00000000..347816ac --- /dev/null +++ b/linux-core/drm_vm.c @@ -0,0 +1,370 @@ +/* drm_vm.h -- Memory mapping for DRM -*- linux-c -*- + * Created: Mon Jan  4 08:58:31 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include "drmP.h" + +struct vm_operations_struct   drm_vm_ops = { +	nopage:	 DRM(vm_nopage), +	open:	 DRM(vm_open), +	close:	 DRM(vm_close), +}; + +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), +}; + +struct vm_operations_struct   drm_vm_dma_ops = { +	nopage:	 DRM(vm_dma_nopage), +	open:	 DRM(vm_open), +	close:	 DRM(vm_close), +}; + +#if LINUX_VERSION_CODE < 0x020317 +unsigned long DRM(vm_nopage)(struct vm_area_struct *vma, +			     unsigned long address, +			     int write_access) +#else +				/* Return type changed in 2.3.23 */ +struct page *DRM(vm_nopage)(struct vm_area_struct *vma, +			    unsigned long address, +			    int write_access) +#endif +{ +	return NOPAGE_SIGBUS;		/* Disallow mremap */ +} + +#if LINUX_VERSION_CODE < 0x020317 +unsigned long DRM(vm_shm_nopage)(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)(struct vm_area_struct *vma, +				unsigned long address, +				int write_access) +#endif +{ +#if LINUX_VERSION_CODE >= 0x020300 +	drm_map_t	 *map	 = (drm_map_t *)vma->vm_private_data; +#else +	drm_map_t	 *map	 = (drm_map_t *)vma->vm_pte; +#endif +	unsigned long	 physical; +	unsigned long	 offset; + +	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; +	atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */ + +	DRM_DEBUG("0x%08lx => 0x%08lx\n", address, physical); +#if LINUX_VERSION_CODE < 0x020317 +	return physical; +#else +	return virt_to_page(physical); +#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 +{ +	drm_file_t	 *priv	 = vma->vm_file->private_data; +	drm_device_t	 *dev	 = priv->dev; +	unsigned long	 physical; +	unsigned long	 offset; +	unsigned long	 page; + +	if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ +	if (!dev->lock.hw_lock)    return NOPAGE_OOM;  /* Nothing allocated */ + +	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 */ + +	DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical); +#if LINUX_VERSION_CODE < 0x020317 +	return physical; +#else +	return virt_to_page(physical); +#endif +} + +#if LINUX_VERSION_CODE < 0x020317 +unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma, +				 unsigned long address, +				 int write_access) +#else +				/* Return type changed in 2.3.23 */ +struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, +				unsigned long address, +				int write_access) +#endif +{ +	drm_file_t	 *priv	 = vma->vm_file->private_data; +	drm_device_t	 *dev	 = priv->dev; +	drm_device_dma_t *dma	 = dev->dma; +	unsigned long	 physical; +	unsigned long	 offset; +	unsigned long	 page; + +	if (!dma)		   return NOPAGE_SIGBUS; /* Error */ +	if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ +	if (!dma->pagelist)	   return NOPAGE_OOM ; /* Nothing allocated */ + +	offset	 = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */ +	page	 = offset >> PAGE_SHIFT; +	physical = dma->pagelist[page] + (offset & (~PAGE_MASK)); +	atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */ + +	DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical); +#if LINUX_VERSION_CODE < 0x020317 +	return physical; +#else +	return virt_to_page(physical); +#endif +} + +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); +	atomic_inc(&dev->vma_count); +#if LINUX_VERSION_CODE < 0x020333 +				/* The map can exist after the fd is closed. */ +	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); +		vma_entry->vma	= vma; +		vma_entry->next = dev->vmalist; +		vma_entry->pid	= current->pid; +		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); +#if LINUX_VERSION_CODE < 0x020333 +	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ +#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) { +			if (prev) { +				prev->next = pt->next; +			} else { +				dev->vmalist = pt->next; +			} +			DRM(free)(pt, sizeof(*pt), DRM_MEM_VMAS); +			break; +		} +	} +	up(&dev->struct_sem); +#endif +} + +int DRM(mmap_dma)(struct file *filp, struct vm_area_struct *vma) +{ +	drm_file_t	 *priv	 = filp->private_data; +	drm_device_t	 *dev; +	drm_device_dma_t *dma; +	unsigned long	 length	 = vma->vm_end - vma->vm_start; + +	lock_kernel(); +	dev	 = priv->dev; +	dma	 = dev->dma; +	DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", +		  vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + +				/* Length must match exact page count */ +	if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { +		unlock_kernel(); +		return -EINVAL; +	} +	unlock_kernel(); + +	vma->vm_ops   = &drm_vm_dma_ops; +	vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + +#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ +				/* In Linux 2.2.3 and above, this is +				   handled in do_mmap() in mm/mmap.c. */ +	++filp->f_count; +#endif +	vma->vm_file  =	 filp;	/* Needed for drm_vm_open() */ +	DRM(vm_open)(vma); +	return 0; +} + +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_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", +		  vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + +	if (!VM_OFFSET(vma)) return DRM(mmap_dma)(filp, vma); + +				/* A sequential search of a linked list is +				   fine here because: 1) there will only be +				   about 5-10 entries in the list and, 2) a +				   DRI client only has to do this mapping +				   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]; +		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; + +				/* Check for valid size. */ +	if (map->size != vma->vm_end - vma->vm_start) return -EINVAL; + +	if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) { +		vma->vm_flags &= VM_MAYWRITE; +#if defined(__i386__) +		pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; +#else +				/* Ye gads this is ugly.  With more thought +                                   we could move this up higher and use +                                   `protection_map' instead.  */ +		vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect( +			__pte(pgprot_val(vma->vm_page_prot))))); +#endif +	} + +	switch (map->type) { +	case _DRM_FRAME_BUFFER: +	case _DRM_REGISTERS: +	case _DRM_AGP: +		if (VM_OFFSET(vma) >= __pa(high_memory)) { +#if defined(__i386__) +			if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { +				pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; +				pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; +			} +#elif defined(__ia64__) +			if (map->type != _DRM_AGP) +				vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +#endif +			vma->vm_flags |= VM_IO;	/* not in core dump */ +		} +		if (remap_page_range(vma->vm_start, +				     VM_OFFSET(vma), +				     vma->vm_end - vma->vm_start, +				     vma->vm_page_prot)) +				return -EAGAIN; +		DRM_DEBUG("   Type = %d; start = 0x%lx, end = 0x%lx," +			  " offset = 0x%lx\n", +			  map->type, +			  vma->vm_start, vma->vm_end, VM_OFFSET(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; +#if LINUX_VERSION_CODE >= 0x020300 +			vma->vm_private_data = (void *)map; +#else +			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; +		break; +	default: +		return -EINVAL;	/* This should never happen. */ +	} +	vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ + +#if LINUX_VERSION_CODE < 0x020203 /* KERNEL_VERSION(2,2,3) */ +				/* In Linux 2.2.3 and above, this is +				   handled in do_mmap() in mm/mmap.c. */ +	++filp->f_count; +#endif +	vma->vm_file  =	 filp;	/* Needed for drm_vm_open() */ +	DRM(vm_open)(vma); +	return 0; +} diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index aa824a79..8585fef1 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -11,11 +11,11 @@   * the rights to use, copy, modify, merge, publish, distribute, sublicense,   * and/or sell copies of the Software, and to permit persons to whom the   * Software is furnished to do so, subject to the following conditions: - *  + *   * The above copyright notice and this permission notice (including the next   * paragraph) shall be included in all copies or substantial portions of the   * Software. - *  + *   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL @@ -31,6 +31,7 @@   */  #define __NO_VERSION__ +#include "i810.h"  #include "drmP.h"  #include "i810_drv.h"  #include <linux/interrupt.h>	/* For task queue support */ @@ -107,14 +108,14 @@ static drm_buf_t *i810_freelist_get(drm_device_t *dev)     	drm_device_dma_t *dma = dev->dma;  	int		 i;     	int 		 used; -    +  	/* Linear search might not be the best solution */     	for (i = 0; i < dma->buf_count; i++) {  	   	drm_buf_t *buf = dma->buflist[ i ];  	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private;  		/* In use is already a pointer */ -	   	used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,  +	   	used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,  			       I810_BUF_CLIENT);  	   	if(used == I810_BUF_FREE) {  			return buf; @@ -131,26 +132,26 @@ static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)  {     	drm_i810_buf_priv_t *buf_priv = buf->dev_private;     	int used; -    +     	/* In use is already a pointer */     	used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);     	if(used != I810_BUF_CLIENT) {  	   	DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);  	   	return -EINVAL;  	} -    +     	return 0;  }  static struct file_operations i810_buffer_fops = { -	open:	 i810_open, -	flush:	 drm_flush, -	release: i810_release, -	ioctl:	 i810_ioctl, +	open:	 DRM(open), +	flush:	 DRM(flush), +	release: DRM(release), +	ioctl:	 DRM(ioctl),  	mmap:	 i810_mmap_buffers, -	read:	 drm_read, -	fasync:	 drm_fasync, -      	poll:	 drm_poll, +	read:	 DRM(read), +	fasync:	 DRM(fasync), +      	poll:	 DRM(poll),  };  int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) @@ -166,10 +167,10 @@ int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)  	dev_priv = dev->dev_private;  	buf      = dev_priv->mmap_buffer;  	buf_priv = buf->dev_private; -    +  	vma->vm_flags |= (VM_IO | VM_DONTCOPY);  	vma->vm_file = filp; -    +     	buf_priv->currently_mapped = I810_BUF_MAPPED;  	unlock_kernel(); @@ -196,9 +197,9 @@ static int i810_map_buffer(drm_buf_t *buf, struct file *filp)  		old_fops = filp->f_op;  		filp->f_op = &i810_buffer_fops;  		dev_priv->mmap_buffer = buf; -		buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,  +		buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,  						    PROT_READ|PROT_WRITE, -						    MAP_SHARED,  +						    MAP_SHARED,  						    buf->bus_address);  		dev_priv->mmap_buffer = NULL;     		filp->f_op = old_fops; @@ -222,15 +223,15 @@ static int i810_unmap_buffer(drm_buf_t *buf)  	int retcode = 0;  	if(VM_DONTCOPY != 0) { -		if(buf_priv->currently_mapped != I810_BUF_MAPPED)  +		if(buf_priv->currently_mapped != I810_BUF_MAPPED)  			return -EINVAL;  		down(¤t->mm->mmap_sem);  #if LINUX_VERSION_CODE < 0x020399 -        	retcode = do_munmap((unsigned long)buf_priv->virtual,  +        	retcode = do_munmap((unsigned long)buf_priv->virtual,  				    (size_t) buf->total);  #else -        	retcode = do_munmap(current->mm,  -				    (unsigned long)buf_priv->virtual,  +        	retcode = do_munmap(current->mm, +				    (unsigned long)buf_priv->virtual,  				    (size_t) buf->total);  #endif     		up(¤t->mm->mmap_sem); @@ -241,7 +242,7 @@ static int i810_unmap_buffer(drm_buf_t *buf)  	return retcode;  } -static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,  +static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,  			       struct file *filp)  {  	drm_file_t	  *priv	  = filp->private_data; @@ -255,7 +256,7 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,  	   	DRM_DEBUG("retcode=%d\n", retcode);  		return retcode;  	} -    +  	retcode = i810_map_buffer(buf, filp);  	if(retcode) {  		i810_freelist_put(dev, buf); @@ -263,7 +264,7 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,  		return retcode;  	}  	buf->pid     = priv->pid; -	buf_priv = buf->dev_private;	 +	buf_priv = buf->dev_private;  	d->granted = 1;     	d->request_idx = buf->idx;     	d->request_size = buf->total; @@ -275,22 +276,22 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,  static unsigned long i810_alloc_page(drm_device_t *dev)  {  	unsigned long address; -    +  	address = __get_free_page(GFP_KERNEL); -	if(address == 0UL)  +	if(address == 0UL)  		return 0; -	 +  	atomic_inc(&virt_to_page(address)->count);  	set_bit(PG_locked, &virt_to_page(address)->flags); -    +  	return address;  }  static void i810_free_page(drm_device_t *dev, unsigned long page)  { -	if(page == 0UL)  +	if(page == 0UL)  		return; -	 +  	atomic_dec(&virt_to_page(page)->count);  	clear_bit(PG_locked, &virt_to_page(page)->flags);  	wake_up(&virt_to_page(page)->wait); @@ -304,26 +305,26 @@ static int i810_dma_cleanup(drm_device_t *dev)  	if(dev->dev_private) {  		int i; -	   	drm_i810_private_t *dev_priv =  +	   	drm_i810_private_t *dev_priv =  	     		(drm_i810_private_t *) dev->dev_private; -	    +  	   	if(dev_priv->ring.virtual_start) { -		   	drm_ioremapfree((void *) dev_priv->ring.virtual_start, -					dev_priv->ring.Size); +		   	DRM(ioremapfree)((void *) dev_priv->ring.virtual_start, +					 dev_priv->ring.Size);  		}  	   	if(dev_priv->hw_status_page != 0UL) {  		   	i810_free_page(dev, dev_priv->hw_status_page);  		   	/* Need to rewrite hardware status page */  		   	I810_WRITE(0x02080, 0x1ffff000);  		} -	   	drm_free(dev->dev_private, sizeof(drm_i810_private_t),  +	   	DRM(free)(dev->dev_private, sizeof(drm_i810_private_t),  			 DRM_MEM_DRIVER);  	   	dev->dev_private = NULL;  		for (i = 0; i < dma->buf_count; i++) {  			drm_buf_t *buf = dma->buflist[ i ];  			drm_i810_buf_priv_t *buf_priv = buf->dev_private; -			drm_ioremapfree(buf_priv->kernel_virtual, buf->total); +			DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total);  		}  	}     	return 0; @@ -340,14 +341,14 @@ static int i810_wait_ring(drm_device_t *dev, int n)  	end = jiffies + (HZ*3);     	while (ring->space < n) {  	   	int i; -	 +  	   	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;  	   	ring->space = ring->head - (ring->tail+8);  		if (ring->space < 0) ring->space += ring->Size; -	    +  		if (ring->head != last_head)  		   end = jiffies + (HZ*3); -	   +  	   	iters++;  		if((signed)(end - jiffies) <= 0) {  		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n); @@ -358,7 +359,7 @@ static int i810_wait_ring(drm_device_t *dev, int n)  	   	for (i = 0 ; i < 2000 ; i++) ;  	} -out_wait_ring:    +out_wait_ring:     	return iters;  } @@ -366,7 +367,7 @@ static void i810_kernel_lost_context(drm_device_t *dev)  {        	drm_i810_private_t *dev_priv = dev->dev_private;     	drm_i810_ring_buffer_t *ring = &(dev_priv->ring); -       +     	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;       	ring->tail = I810_READ(LP_RING + RING_TAIL);       	ring->space = ring->head - (ring->tail+8); @@ -380,7 +381,7 @@ static int i810_freelist_init(drm_device_t *dev)     	int my_idx = 24;     	u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);     	int i; -    +     	if(dma->buf_count > 1019) {  	   	/* Not enough space in the status page for the freelist */  	   	return -EINVAL; @@ -389,20 +390,20 @@ static int i810_freelist_init(drm_device_t *dev)     	for (i = 0; i < dma->buf_count; i++) {  	   	drm_buf_t *buf = dma->buflist[ i ];  	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private; -	    +  	   	buf_priv->in_use = hw_status++;  	   	buf_priv->my_use_idx = my_idx;  	   	my_idx += 4;  	   	*buf_priv->in_use = I810_BUF_FREE; -		buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,  -						       buf->total); +		buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address, +							buf->total);  	}  	return 0;  } -static int i810_dma_initialize(drm_device_t *dev,  +static int i810_dma_initialize(drm_device_t *dev,  			       drm_i810_private_t *dev_priv,  			       drm_i810_init_t *init)  { @@ -417,27 +418,27 @@ static int i810_dma_initialize(drm_device_t *dev,  	   	DRM_ERROR("ring_map or buffer_map are invalid\n");  	   	return -EINVAL;  	} -    +     	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 +  +	dev_priv->sarea_priv = (drm_i810_sarea_t *) +		((u8 *)sarea_map->handle +  		 init->sarea_priv_offset);     	atomic_set(&dev_priv->flush_done, 0);  	init_waitqueue_head(&dev_priv->flush_queue); -   	 +     	dev_priv->ring.Start = init->ring_start;     	dev_priv->ring.End = init->ring_end;     	dev_priv->ring.Size = init->ring_size; -   	dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +  -						   init->ring_start,  -						   init->ring_size); +   	dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + +						    init->ring_start, +						    init->ring_size);     	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; -    +     	if (dev_priv->ring.virtual_start == NULL) {  	   	i810_dma_cleanup(dev);  	   	DRM_ERROR("can not ioremap virtual address for" @@ -454,8 +455,8 @@ static int i810_dma_initialize(drm_device_t *dev,  	dev_priv->front_di1 = init->front_offset | init->pitch_bits;  	dev_priv->back_di1 = init->back_offset | init->pitch_bits;  	dev_priv->zi1 = init->depth_offset | init->pitch_bits; -	 -    + +     	/* Program Hardware Status Page */     	dev_priv->hw_status_page = i810_alloc_page(dev);     	memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE); @@ -465,10 +466,10 @@ static int i810_dma_initialize(drm_device_t *dev,  		return -ENOMEM;  	}     	DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page); -    +     	I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));     	DRM_DEBUG("Enabled hardware status page\n"); -    +     	/* Now we need to init our freelist */     	if(i810_freelist_init(dev) != 0) {  	   	i810_dma_cleanup(dev); @@ -487,13 +488,13 @@ int i810_dma_init(struct inode *inode, struct file *filp,     	drm_i810_private_t *dev_priv;     	drm_i810_init_t init;     	int retcode = 0; -	 +    	if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init)))  		return -EFAULT; -	 +     	switch(init.func) {  	 	case I810_INIT_DMA: -	   		dev_priv = drm_alloc(sizeof(drm_i810_private_t),  +	   		dev_priv = DRM(alloc)(sizeof(drm_i810_private_t),  					     DRM_MEM_DRIVER);  	   		if(dev_priv == NULL) return -ENOMEM;  	   		retcode = i810_dma_initialize(dev, dev_priv, &init); @@ -505,7 +506,7 @@ int i810_dma_init(struct inode *inode, struct file *filp,  	   		retcode = -EINVAL;  	   	break;  	} -    +     	return retcode;  } @@ -517,9 +518,9 @@ int i810_dma_init(struct inode *inode, struct file *filp,   * Use 'volatile' & local var tmp to force the emitted values to be   * identical to the verified ones.   */ -static void i810EmitContextVerified( drm_device_t *dev,  -				     volatile unsigned int *code )  -{	 +static void i810EmitContextVerified( drm_device_t *dev, +				     volatile unsigned int *code ) +{     	drm_i810_private_t *dev_priv = dev->dev_private;  	int i, j = 0;  	unsigned int tmp; @@ -537,22 +538,22 @@ static void i810EmitContextVerified( drm_device_t *dev,  		tmp = code[i];  		if ((tmp & (7<<29)) == (3<<29) && -		    (tmp & (0x1f<<24)) < (0x1d<<24))  +		    (tmp & (0x1f<<24)) < (0x1d<<24))  		{ -			OUT_RING( tmp );  +			OUT_RING( tmp );  			j++; -		}  +		}  	} -	if (j & 1)  -		OUT_RING( 0 );  +	if (j & 1) +		OUT_RING( 0 );  	ADVANCE_LP_RING();  } -static void i810EmitTexVerified( drm_device_t *dev,  -				 volatile unsigned int *code )  -{	 +static void i810EmitTexVerified( drm_device_t *dev, +				 volatile unsigned int *code ) +{     	drm_i810_private_t *dev_priv = dev->dev_private;  	int i, j = 0;  	unsigned int tmp; @@ -569,15 +570,15 @@ static void i810EmitTexVerified( drm_device_t *dev,  		tmp = code[i];  		if ((tmp & (7<<29)) == (3<<29) && -		    (tmp & (0x1f<<24)) < (0x1d<<24))  +		    (tmp & (0x1f<<24)) < (0x1d<<24))  		{ -			OUT_RING( tmp );  +			OUT_RING( tmp );  			j++;  		} -	}  -		 -	if (j & 1)  -		OUT_RING( 0 );  +	} + +	if (j & 1) +		OUT_RING( 0 );  	ADVANCE_LP_RING();  } @@ -585,9 +586,9 @@ static void i810EmitTexVerified( drm_device_t *dev,  /* Need to do some additional checking when setting the dest buffer.   */ -static void i810EmitDestVerified( drm_device_t *dev,  -				  volatile unsigned int *code )  -{	 +static void i810EmitDestVerified( drm_device_t *dev, +				  volatile unsigned int *code ) +{     	drm_i810_private_t *dev_priv = dev->dev_private;  	unsigned int tmp;  	RING_LOCALS; @@ -651,9 +652,9 @@ static void i810EmitState( drm_device_t *dev ) -/* need to verify  +/* need to verify   */ -static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,  +static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,  				     unsigned int clear_color,  				     unsigned int clear_zval )  { @@ -684,10 +685,10 @@ static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,  		    pbox->y2 > dev_priv->h)  			continue; -	   	if ( flags & I810_FRONT ) {	     +	   	if ( flags & I810_FRONT ) {  		   	DRM_DEBUG("clear front\n"); -			BEGIN_LP_RING( 6 );	     -			OUT_RING( BR00_BITBLT_CLIENT |  +			BEGIN_LP_RING( 6 ); +			OUT_RING( BR00_BITBLT_CLIENT |  				  BR00_OP_COLOR_BLT | 0x3 );  			OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );  			OUT_RING( (height << 16) | width ); @@ -699,8 +700,8 @@ static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,  		if ( flags & I810_BACK ) {  			DRM_DEBUG("clear back\n"); -			BEGIN_LP_RING( 6 );	     -			OUT_RING( BR00_BITBLT_CLIENT |  +			BEGIN_LP_RING( 6 ); +			OUT_RING( BR00_BITBLT_CLIENT |  				  BR00_OP_COLOR_BLT | 0x3 );  			OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );  			OUT_RING( (height << 16) | width ); @@ -712,8 +713,8 @@ static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,  		if ( flags & I810_DEPTH ) {  			DRM_DEBUG("clear depth\n"); -			BEGIN_LP_RING( 6 );	     -			OUT_RING( BR00_BITBLT_CLIENT |  +			BEGIN_LP_RING( 6 ); +			OUT_RING( BR00_BITBLT_CLIENT |  				  BR00_OP_COLOR_BLT | 0x3 );  			OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );  			OUT_RING( (height << 16) | width ); @@ -744,7 +745,7 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )        	if (nbox > I810_NR_SAREA_CLIPRECTS)       		nbox = I810_NR_SAREA_CLIPRECTS; -	for (i = 0 ; i < nbox; i++, pbox++)  +	for (i = 0 ; i < nbox; i++, pbox++)  	{  		unsigned int w = pbox->x2 - pbox->x1;  		unsigned int h = pbox->y2 - pbox->y1; @@ -756,7 +757,7 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )  		    pbox->x2 > dev_priv->w ||  		    pbox->y2 > dev_priv->h)  			continue; -  +  	   	DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",  			  pbox[i].x1, pbox[i].y1,  			  pbox[i].x2, pbox[i].y2); @@ -766,14 +767,14 @@ static void i810_dma_dispatch_swap( drm_device_t *dev )  		OUT_RING( pitch | (0xCC << 16));  		OUT_RING( (h << 16) | (w * cpp));  		OUT_RING( dst ); -		OUT_RING( pitch );	 +		OUT_RING( pitch );  		OUT_RING( start );  		ADVANCE_LP_RING();  	}  } -static void i810_dma_dispatch_vertex(drm_device_t *dev,  +static void i810_dma_dispatch_vertex(drm_device_t *dev,  				     drm_buf_t *buf,  				     int discard,  				     int used) @@ -784,30 +785,30 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,     	drm_clip_rect_t *box = sarea_priv->boxes;     	int nbox = sarea_priv->nbox;  	unsigned long address = (unsigned long)buf->bus_address; -	unsigned long start = address - dev->agp->base;      +	unsigned long start = address - dev->agp->base;  	int i = 0, u;     	RING_LOCALS;     	i810_kernel_lost_context(dev); -   	if (nbox > I810_NR_SAREA_CLIPRECTS)  +   	if (nbox > I810_NR_SAREA_CLIPRECTS)  		nbox = I810_NR_SAREA_CLIPRECTS;  	if (discard) { -		u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,  +		u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,  			    I810_BUF_HARDWARE);  		if(u != I810_BUF_CLIENT) {  			DRM_DEBUG("xxxx 2\n");  		}  	} -	if (used > 4*1024)  +	if (used > 4*1024)  		used = 0;  	if (sarea_priv->dirty)  	   i810EmitState( dev ); -  	DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",  +  	DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",  		  address, used, nbox);     	dev_priv->counter++; @@ -821,7 +822,7 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,  		*(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE |  					     sarea_priv->vertex_prim |  					     ((used/4)-2)); -		 +  		if (used & 4) {  			*(u32 *)((u32)buf_priv->virtual + used) = 0;  			used += 4; @@ -829,26 +830,26 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,  		i810_unmap_buffer(buf);  	} -		    +  	if (used) {  		do {  			if (i < nbox) {  				BEGIN_LP_RING(4); -				OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR |  +				OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR |  					  SC_ENABLE );  				OUT_RING( GFX_OP_SCISSOR_INFO );  				OUT_RING( box[i].x1 | (box[i].y1<<16) );  				OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) );  				ADVANCE_LP_RING();  			} -			 +  			BEGIN_LP_RING(4);  			OUT_RING( CMD_OP_BATCH_BUFFER );  			OUT_RING( start | BB1_PROTECTED );  			OUT_RING( start + used - 4 );  			OUT_RING( 0 );  			ADVANCE_LP_RING(); -			 +  		} while (++i < nbox);  	} @@ -876,15 +877,15 @@ static void i810_dma_service(int irq, void *device, struct pt_regs *regs)  {  	drm_device_t	 *dev = (drm_device_t *)device;     	u16 temp; -    -	atomic_inc(&dev->total_irq); + +	atomic_inc(&dev->counts[_DRM_STAT_IRQ]);        	temp = I810_READ16(I810REG_INT_IDENTITY_R);     	temp = temp & ~(0x6000); -   	if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,  +   	if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,  				   temp); /* Clear all interrupts */  	else  	   return; -  +     	queue_task(&dev->tq, &tq_immediate);     	mark_bh(IMMEDIATE_BH);  } @@ -902,9 +903,9 @@ int i810_irq_install(drm_device_t *dev, int irq)  {  	int retcode;  	u16 temp; -    +  	if (!irq)     return -EINVAL; -	 +  	down(&dev->struct_sem);  	if (dev->irq) {  		up(&dev->struct_sem); @@ -912,14 +913,14 @@ int i810_irq_install(drm_device_t *dev, int irq)  	}  	dev->irq = irq;  	up(&dev->struct_sem); -	 +     	DRM_DEBUG(  "Interrupt Install : %d\n", irq);  	DRM_DEBUG("%d\n", irq);  	dev->context_flag     = 0;  	dev->interrupt_flag   = 0;  	dev->dma_flag	      = 0; -	 +  	dev->dma->next_buffer = NULL;  	dev->dma->next_queue  = NULL;  	dev->dma->this_buffer = NULL; @@ -933,7 +934,7 @@ int i810_irq_install(drm_device_t *dev, int irq)     	temp = I810_READ16(I810REG_HWSTAM);     	temp = temp & 0x6000;     	I810_WRITE16(I810REG_HWSTAM, temp); -   	 +        	temp = I810_READ16(I810REG_INT_MASK_R);     	temp = temp & 0x6000;     	I810_WRITE16(I810REG_INT_MASK_R, temp); /* Unmask interrupts */ @@ -955,7 +956,7 @@ int i810_irq_install(drm_device_t *dev, int irq)     	temp = I810_READ16(I810REG_INT_ENABLE_R);     	temp = temp & 0x6000;     	temp = temp | 0x0003; -   	I810_WRITE16(I810REG_INT_ENABLE_R,  +   	I810_WRITE16(I810REG_INT_ENABLE_R,  		     temp); /* Enable bp & user interrupts */  	return 0;  } @@ -972,20 +973,20 @@ int i810_irq_uninstall(drm_device_t *dev)  	irq	 = dev->irq;  	dev->irq = 0;  	up(&dev->struct_sem); -	 +  	if (!irq) return -EINVAL; -   	DRM_DEBUG(  "Interrupt UnInstall: %d\n", irq);	 +   	DRM_DEBUG(  "Interrupt UnInstall: %d\n", irq);  	DRM_DEBUG("%d\n", irq); -    +     	temp = I810_READ16(I810REG_INT_IDENTITY_R);     	temp = temp & ~(0x6000); -   	if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,  +   	if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,  				   temp); /* Clear all interrupts */ -    +     	temp = I810_READ16(I810REG_INT_ENABLE_R);     	temp = temp & 0x6000; -   	I810_WRITE16(I810REG_INT_ENABLE_R,  +   	I810_WRITE16(I810REG_INT_ENABLE_R,  		     temp);                     /* Disable all interrupts */     	free_irq(irq, dev); @@ -1000,12 +1001,12 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,  	drm_device_t	*dev	= priv->dev;  	drm_control_t	ctl;  	int		retcode; -    +     	DRM_DEBUG(  "i810_control\n");  	if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl)))  		return -EFAULT; -	 +  	switch (ctl.func) {  	case DRM_INST_HANDLER:  		if ((retcode = i810_irq_install(dev, ctl.irq))) @@ -1057,11 +1058,11 @@ static inline void i810_dma_quiescent_emit(drm_device_t *dev)  /*     	wake_up_interruptible(&dev_priv->flush_queue); */  } -static void i810_dma_quiescent(drm_device_t *dev) +void i810_dma_quiescent(drm_device_t *dev)  {        	DECLARE_WAITQUEUE(entry, current);    	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; -	unsigned long end;       +	unsigned long end;     	if(dev_priv == NULL) {  	   	return; @@ -1069,7 +1070,7 @@ static void i810_dma_quiescent(drm_device_t *dev)        	atomic_set(&dev_priv->flush_done, 0);     	add_wait_queue(&dev_priv->flush_queue, &entry);     	end = jiffies + (HZ*3); -    +     	for (;;) {  		current->state = TASK_INTERRUPTIBLE;  	      	i810_dma_quiescent_emit(dev); @@ -1077,16 +1078,16 @@ static void i810_dma_quiescent(drm_device_t *dev)  		if((signed)(end - jiffies) <= 0) {  		   	DRM_ERROR("lockup\n");  		   	break; -		}	    +		}  	      	schedule_timeout(HZ*3);  	      	if (signal_pending(current)) {  		   	break;  		}  	} -    +     	current->state = TASK_RUNNING;     	remove_wait_queue(&dev_priv->flush_queue, &entry); -    +     	return;  } @@ -1096,7 +1097,7 @@ static int i810_flush_queue(drm_device_t *dev)    	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;  	drm_device_dma_t *dma = dev->dma;  	unsigned long end; -   	int i, ret = 0;       +   	int i, ret = 0;     	if(dev_priv == NULL) {  	   	return 0; @@ -1111,14 +1112,14 @@ static int i810_flush_queue(drm_device_t *dev)  		if((signed)(end - jiffies) <= 0) {  		   	DRM_ERROR("lockup\n");  		   	break; -		}	    +		}  	      	schedule_timeout(HZ*3);  	      	if (signal_pending(current)) {  		   	ret = -EINTR; /* Can't restart */  		   	break;  		}  	} -    +     	current->state = TASK_RUNNING;     	remove_wait_queue(&dev_priv->flush_queue, &entry); @@ -1126,8 +1127,8 @@ static int i810_flush_queue(drm_device_t *dev)     	for (i = 0; i < dma->buf_count; i++) {  	   	drm_buf_t *buf = dma->buflist[ i ];  	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private; -	    -		int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE,  + +		int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE,  				   I810_BUF_FREE);  		if (used == I810_BUF_HARDWARE) @@ -1154,9 +1155,9 @@ void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)  	for (i = 0; i < dma->buf_count; i++) {  	   	drm_buf_t *buf = dma->buflist[ i ];  	   	drm_i810_buf_priv_t *buf_priv = buf->dev_private; -	    +  		if (buf->pid == pid && buf_priv) { -			int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,  +			int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,  					   I810_BUF_FREE);  			if (used == I810_BUF_CLIENT) @@ -1167,91 +1168,12 @@ void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)  	}  } -int i810_lock(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; - -	DECLARE_WAITQUEUE(entry, current); -	int		  ret	= 0; -	drm_lock_t	  lock; - -	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) -		return -EFAULT; - -	if (lock.context == DRM_KERNEL_CONTEXT) { -		DRM_ERROR("Process %d using kernel context %d\n", -			  current->pid, lock.context); -		return -EINVAL; -	} -    -   	DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", -		  lock.context, current->pid, dev->lock.hw_lock->lock, -		  lock.flags); - -	if (lock.context < 0) { -		return -EINVAL; -	} -	/* Only one queue: -	 */ - -	if (!ret) { -		add_wait_queue(&dev->lock.lock_queue, &entry); -		for (;;) { -			current->state = TASK_INTERRUPTIBLE; -			if (!dev->lock.hw_lock) { -				/* Device has been unregistered */ -				ret = -EINTR; -				break; -			} -			if (drm_lock_take(&dev->lock.hw_lock->lock, -					  lock.context)) { -				dev->lock.pid	    = current->pid; -				dev->lock.lock_time = jiffies; -				atomic_inc(&dev->total_locks); -				break;	/* Got lock */ -			} -			 -				/* Contention */ -			atomic_inc(&dev->total_sleeps); -		   	DRM_DEBUG("Calling lock schedule\n"); -			schedule(); -			if (signal_pending(current)) { -				ret = -ERESTARTSYS; -				break; -			} -		} -		current->state = TASK_RUNNING; -		remove_wait_queue(&dev->lock.lock_queue, &entry); -	} -	 -	if (!ret) { -		sigemptyset(&dev->sigmask); -		sigaddset(&dev->sigmask, SIGSTOP); -		sigaddset(&dev->sigmask, SIGTSTP); -		sigaddset(&dev->sigmask, SIGTTIN); -		sigaddset(&dev->sigmask, SIGTTOU); -		dev->sigdata.context = lock.context; -		dev->sigdata.lock    = dev->lock.hw_lock; -		block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); - -		if (lock.flags & _DRM_LOCK_QUIESCENT) { -		   DRM_DEBUG("_DRM_LOCK_QUIESCENT\n"); -		   DRM_DEBUG("fred\n"); -		   i810_dma_quiescent(dev); -		} -	} -	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); -	return ret; -} - -int i810_flush_ioctl(struct inode *inode, struct file *filp,  +int i810_flush_ioctl(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_DEBUG("i810_flush_ioctl\n");     	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {  		DRM_ERROR("i810_flush_ioctl called without lock held\n"); @@ -1271,8 +1193,8 @@ int i810_dma_vertex(struct inode *inode, struct file *filp,  	drm_device_dma_t *dma = dev->dma;     	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;        	u32 *hw_status = (u32 *)dev_priv->hw_status_page; -   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)  -     					dev_priv->sarea_priv;  +   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) +     					dev_priv->sarea_priv;  	drm_i810_vertex_t vertex;  	if (copy_from_user(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex))) @@ -1286,15 +1208,15 @@ int i810_dma_vertex(struct inode *inode, struct file *filp,  	DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",  		  vertex.idx, vertex.used, vertex.discard); -	i810_dma_dispatch_vertex( dev,  -				  dma->buflist[ vertex.idx ],  +	i810_dma_dispatch_vertex( dev, +				  dma->buflist[ vertex.idx ],  				  vertex.discard, vertex.used ); -   	atomic_add(vertex.used, &dma->total_bytes); -	atomic_inc(&dma->total_dmas); +   	atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]); +	atomic_inc(&dev->counts[_DRM_STAT_DMA]);  	sarea_priv->last_enqueue = dev_priv->counter-1;     	sarea_priv->last_dispatch = (int) hw_status[5]; -    +  	return 0;  } @@ -1309,14 +1231,14 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,     	if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear)))  		return -EFAULT; -    +     	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {  		DRM_ERROR("i810_clear_bufs called without lock held\n");  		return -EINVAL;  	} -	i810_dma_dispatch_clear( dev, clear.flags,  -				 clear.clear_color,  +	i810_dma_dispatch_clear( dev, clear.flags, +				 clear.clear_color,  				 clear.clear_depth );     	return 0;  } @@ -1326,7 +1248,7 @@ int i810_swap_bufs(struct inode *inode, struct file *filp,  {  	drm_file_t *priv = filp->private_data;  	drm_device_t *dev = priv->dev; -    +  	DRM_DEBUG("i810_swap_bufs\n");     	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { @@ -1345,8 +1267,8 @@ int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,  	drm_device_t	  *dev	    = priv->dev;     	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;        	u32 *hw_status = (u32 *)dev_priv->hw_status_page; -   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)  -     					dev_priv->sarea_priv;  +   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) +     					dev_priv->sarea_priv;        	sarea_priv->last_dispatch = (int) hw_status[5];  	return 0; @@ -1361,18 +1283,18 @@ int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,  	drm_i810_dma_t	  d;     	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;     	u32 *hw_status = (u32 *)dev_priv->hw_status_page; -   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)  -     					dev_priv->sarea_priv;  +   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) +     					dev_priv->sarea_priv;  	DRM_DEBUG("getbuf\n");     	if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d)))  		return -EFAULT; -    +  	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {  		DRM_ERROR("i810_dma called without lock held\n");  		return -EINVAL;  	} -	 +  	d.granted = 0;  	retcode = i810_dma_get_buffer(dev, &d, filp); @@ -1395,8 +1317,8 @@ int i810_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,  	drm_i810_copy_t	  d;     	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;     	u32 *hw_status = (u32 *)dev_priv->hw_status_page; -   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)  -     					dev_priv->sarea_priv;  +   	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) +     					dev_priv->sarea_priv;  	drm_buf_t *buf;  	drm_i810_buf_priv_t *buf_priv;  	drm_device_dma_t *dma = dev->dma; @@ -1405,7 +1327,7 @@ int i810_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,  		DRM_ERROR("i810_dma called without lock held\n");  		return -EINVAL;  	} -    +     	if (copy_from_user(&d, (drm_i810_copy_t *)arg, sizeof(d)))  		return -EFAULT; diff --git a/linux-core/i810_drv.c b/linux-core/i810_drv.c index 7152eac3..5b4d1c34 100644 --- a/linux-core/i810_drv.c +++ b/linux-core/i810_drv.c @@ -19,630 +19,84 @@   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: Rickard E. (Rik) Faith <faith@valinux.com> - *	    Jeff Hartmann <jhartmann@valinux.com> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE.   * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Jeff Hartmann <jhartmann@valinux.com> + *    Gareth Hughes <gareth@valinux.com>   */  #include <linux/config.h> +#include "i810.h"  #include "drmP.h"  #include "i810_drv.h" -#define I810_NAME	 "i810" -#define I810_DESC	 "Intel I810" -#define I810_DATE	 "20000928" -#define I810_MAJOR	 1 -#define I810_MINOR	 1 -#define I810_PATCHLEVEL	 0 - -static drm_device_t	      i810_device; -drm_ctx_t		      i810_res_ctx; - -static struct file_operations i810_fops = { -#if LINUX_VERSION_CODE >= 0x020400 -				/* This started being used during 2.4.0-test */ -	owner:   THIS_MODULE, -#endif -	open:	 i810_open, -	flush:	 drm_flush, -	release: i810_release, -	ioctl:	 i810_ioctl, -	mmap:	 drm_mmap, -	read:	 drm_read, -	fasync:	 drm_fasync, -      	poll:	 drm_poll, -}; - -static struct miscdevice      i810_misc = { -	minor: MISC_DYNAMIC_MINOR, -	name:  I810_NAME, -	fops:  &i810_fops, -}; - -static drm_ioctl_desc_t	      i810_ioctls[] = { -	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]     = { i810_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_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_CONTROL)]     = { i810_control,	  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_BUFS)]    = { i810_addbufs,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]   = { i810_markbufs,  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]   = { i810_infobufs,  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]   = { i810_freebufs,  1, 0 }, - -	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]     = { i810_addctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]      = { i810_rmctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]     = { i810_modctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]     = { i810_getctx,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]  = { i810_switchctx,  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]     = { i810_newctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]     = { i810_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)]	      = { i810_lock,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]      = { i810_unlock,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]      = { drm_finish,	  1, 0 }, - -	[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_I810_INIT)]   = { i810_dma_init,   1, 1 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_I810_VERTEX)] = { i810_dma_vertex, 1, 0 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_I810_CLEAR)]  = { i810_clear_bufs, 1, 0 }, -      	[DRM_IOCTL_NR(DRM_IOCTL_I810_FLUSH)]  = { i810_flush_ioctl,1, 0 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_I810_GETAGE)] = { i810_getage,     1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf,     1, 0 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)]   = { i810_swap_bufs,  1, 0 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)]   = { i810_copybuf,    1, 0 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy,     1, 0 }, -}; - -#define I810_IOCTL_COUNT DRM_ARRAY_SIZE(i810_ioctls) - -#ifdef MODULE -static char		      *i810 = NULL; -#endif - -MODULE_AUTHOR("VA Linux Systems, Inc."); -MODULE_DESCRIPTION("Intel I810"); -MODULE_PARM(i810, "s"); - -#ifndef MODULE -/* i810_options is called by the kernel to parse command-line options - * passed via the boot-loader (e.g., LILO).  It calls the insmod option - * routine, drm_parse_drm. - */ - -static int __init i810_options(char *str) -{ -	drm_parse_options(str); -	return 1; -} - -__setup("i810=", i810_options); -#endif - -static int i810_setup(drm_device_t *dev) -{ -	int i; - -	atomic_set(&dev->ioctl_count, 0); -	atomic_set(&dev->vma_count, 0); -	dev->buf_use	  = 0; -	atomic_set(&dev->buf_alloc, 0); - -	drm_dma_setup(dev); - -	atomic_set(&dev->total_open, 0); -	atomic_set(&dev->total_close, 0); -	atomic_set(&dev->total_ioctl, 0); -	atomic_set(&dev->total_irq, 0); -	atomic_set(&dev->total_ctx, 0); -	atomic_set(&dev->total_locks, 0); -	atomic_set(&dev->total_unlocks, 0); -	atomic_set(&dev->total_contends, 0); -	atomic_set(&dev->total_sleeps, 0); - -	for (i = 0; i < DRM_HASH_SIZE; i++) { -		dev->magiclist[i].head = NULL; -		dev->magiclist[i].tail = NULL; -	} -	dev->maplist	    = NULL; -	dev->map_count	    = 0; -	dev->vmalist	    = NULL; -	dev->lock.hw_lock   = NULL; -	init_waitqueue_head(&dev->lock.lock_queue); -	dev->queue_count    = 0; -	dev->queue_reserved = 0; -	dev->queue_slots    = 0; -	dev->queuelist	    = NULL; -	dev->irq	    = 0; -	dev->context_flag   = 0; -	dev->interrupt_flag = 0; -	dev->dma_flag	    = 0; -	dev->last_context   = 0; -	dev->last_switch    = 0; -	dev->last_checked   = 0; -	init_timer(&dev->timer); -	init_waitqueue_head(&dev->context_wait); -#if DRM_DMA_HISTO -	memset(&dev->histo, 0, sizeof(dev->histo)); -#endif -	dev->ctx_start	    = 0; -	dev->lck_start	    = 0; - -	dev->buf_rp	  = dev->buf; -	dev->buf_wp	  = dev->buf; -	dev->buf_end	  = dev->buf + DRM_BSZ; -	dev->buf_async	  = NULL; -	init_waitqueue_head(&dev->buf_readers); -	init_waitqueue_head(&dev->buf_writers); - -	DRM_DEBUG("\n"); - -	/* The kernel's context could be created here, but is now created -	   in drm_dma_enqueue.	This is more resource-efficient for -	   hardware that does not do DMA, but may mean that -	   drm_select_queue fails between the time the interrupt is -	   initialized and the time the queues are initialized. */ - -	return 0; -} - - -static int i810_takedown(drm_device_t *dev) -{ -	int		  i; -	drm_magic_entry_t *pt, *next; -	drm_map_t	  *map; -	drm_vma_entry_t	  *vma, *vma_next; - -	DRM_DEBUG("\n"); - -	if (dev->irq) i810_irq_uninstall(dev); - -	down(&dev->struct_sem); -	del_timer(&dev->timer); - -	if (dev->devname) { -		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); -		dev->devname = NULL; -	} - -	if (dev->unique) { -		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); -		dev->unique = NULL; -		dev->unique_len = 0; -	} -				/* Clear pid list */ -	for (i = 0; i < DRM_HASH_SIZE; i++) { -		for (pt = dev->magiclist[i].head; pt; pt = next) { -			next = pt->next; -			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); -		} -		dev->magiclist[i].head = dev->magiclist[i].tail = NULL; -	} -   				/* Clear AGP information */ -	if (dev->agp) { -		drm_agp_mem_t *entry; -		drm_agp_mem_t *nexte; - -				/* Remove AGP resources, but leave dev->agp -                                   intact until r128_cleanup is called. */ -		for (entry = dev->agp->memory; entry; entry = nexte) { -			nexte = entry->next; -			if (entry->bound) drm_unbind_agp(entry->memory); -			drm_free_agp(entry->memory, entry->pages); -			drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); -		} -		dev->agp->memory = NULL; - -		if (dev->agp->acquired) _drm_agp_release(); - -		dev->agp->acquired = 0; -		dev->agp->enabled  = 0; -	} -				/* Clear vma list (only built for debugging) */ -	if (dev->vmalist) { -		for (vma = dev->vmalist; vma; vma = vma_next) { -			vma_next = vma->next; -			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); -		} -		dev->vmalist = NULL; -	} - -				/* Clear map area and mtrr information */ -	if (dev->maplist) { -		for (i = 0; i < dev->map_count; i++) { -			map = dev->maplist[i]; -			switch (map->type) { -			case _DRM_REGISTERS: -			case _DRM_FRAME_BUFFER: -#ifdef CONFIG_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: -				drm_free_pages((unsigned long)map->handle, -					       drm_order(map->size) -					       - PAGE_SHIFT, -					       DRM_MEM_SAREA); -				break; -			case _DRM_AGP: -				break; -			} -			drm_free(map, sizeof(*map), DRM_MEM_MAPS); -		} -		drm_free(dev->maplist, -			 dev->map_count * sizeof(*dev->maplist), -			 DRM_MEM_MAPS); -		dev->maplist   = NULL; -		dev->map_count = 0; -	} - -	if (dev->queuelist) { -		for (i = 0; i < dev->queue_count; i++) { -			drm_waitlist_destroy(&dev->queuelist[i]->waitlist); -			if (dev->queuelist[i]) { -				drm_free(dev->queuelist[i], -					 sizeof(*dev->queuelist[0]), -					 DRM_MEM_QUEUES); -				dev->queuelist[i] = NULL; -			} -		} -		drm_free(dev->queuelist, -			 dev->queue_slots * sizeof(*dev->queuelist), -			 DRM_MEM_QUEUES); -		dev->queuelist	 = NULL; -	} - -	drm_dma_takedown(dev); - -	dev->queue_count     = 0; -	if (dev->lock.hw_lock) { -		dev->lock.hw_lock    = NULL; /* SHM removed */ -		dev->lock.pid	     = 0; -		wake_up_interruptible(&dev->lock.lock_queue); -	} -	up(&dev->struct_sem); - -	return 0; -} - -/* i810_init is called via init_module at module load time, or via - * linux/init/main.c (this is not currently supported). */ - -static int __init i810_init(void) -{ -	int		      retcode; -	drm_device_t	      *dev = &i810_device; - -	DRM_DEBUG("\n"); - -	memset((void *)dev, 0, sizeof(*dev)); -	dev->count_lock	  = SPIN_LOCK_UNLOCKED; -	sema_init(&dev->struct_sem, 1); - -#ifdef MODULE -	drm_parse_options(i810); -#endif -	DRM_DEBUG("doing misc_register\n"); -	if ((retcode = misc_register(&i810_misc))) { -		DRM_ERROR("Cannot register \"%s\"\n", I810_NAME); -		return retcode; -	} -	dev->device = MKDEV(MISC_MAJOR, i810_misc.minor); -	dev->name   = I810_NAME; - -   	DRM_DEBUG("doing mem init\n"); -	drm_mem_init(); -	DRM_DEBUG("doing proc init\n"); -	drm_proc_init(dev); -	DRM_DEBUG("doing agp init\n"); -	dev->agp    = drm_agp_init(); -   	if(dev->agp == NULL) { -	   	DRM_INFO("The i810 drm module requires the agpgart module" -			 " to function correctly\nPlease load the agpgart" -			 " module before you load the i810 module\n"); -	   	drm_proc_cleanup(); -	   	misc_deregister(&i810_misc); -	   	i810_takedown(dev); -	   	return -ENOMEM; -	} -	DRM_DEBUG("doing ctxbitmap init\n"); -	if((retcode = drm_ctxbitmap_init(dev))) { -		DRM_ERROR("Cannot allocate memory for context bitmap.\n"); -		drm_proc_cleanup(); -		misc_deregister(&i810_misc); -		i810_takedown(dev); -		return retcode; -	} - -	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", -		 I810_NAME, -		 I810_MAJOR, -		 I810_MINOR, -		 I810_PATCHLEVEL, -		 I810_DATE, -		 i810_misc.minor); - -	return 0; -} - -/* i810_cleanup is called via cleanup_module at module unload time. */ - -static void __exit i810_cleanup(void) -{ -	drm_device_t	      *dev = &i810_device; - -	DRM_DEBUG("\n"); - -	drm_proc_cleanup(); -	if (misc_deregister(&i810_misc)) { -		DRM_ERROR("Cannot unload module\n"); -	} else { -		DRM_INFO("Module unloaded\n"); -	} -	drm_ctxbitmap_cleanup(dev); -	i810_takedown(dev); -	if (dev->agp) { -		drm_agp_uninit(); -		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); -		dev->agp = NULL; -	} -} - -module_init(i810_init); -module_exit(i810_cleanup); - - -int i810_version(struct inode *inode, struct file *filp, unsigned int cmd, -		  unsigned long arg) -{ -	drm_version_t version; -	int	      len; - -	if (copy_from_user(&version, -			   (drm_version_t *)arg, -			   sizeof(version))) -		return -EFAULT; - -#define DRM_COPY(name,value)				     \ -	len = strlen(value);				     \ -	if (len > name##_len) len = name##_len;		     \ -	name##_len = strlen(value);			     \ -	if (len && name) {				     \ -		if (copy_to_user(name, value, len))          \ -			return -EFAULT;			     \ -	} - -	version.version_major	   = I810_MAJOR; -	version.version_minor	   = I810_MINOR; -	version.version_patchlevel = I810_PATCHLEVEL; - -	DRM_COPY(version.name, I810_NAME); -	DRM_COPY(version.date, I810_DATE); -	DRM_COPY(version.desc, I810_DESC); - -	if (copy_to_user((drm_version_t *)arg, -			 &version, -			 sizeof(version))) -		return -EFAULT; -	return 0; -} - -int i810_open(struct inode *inode, struct file *filp) -{ -	drm_device_t  *dev    = &i810_device; -	int	      retcode = 0; - -	DRM_DEBUG("open_count = %d\n", dev->open_count); -	if (!(retcode = drm_open_helper(inode, filp, dev))) { -#if LINUX_VERSION_CODE < 0x020333 -		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif -		atomic_inc(&dev->total_open); -		spin_lock(&dev->count_lock); -		if (!dev->open_count++) { -			spin_unlock(&dev->count_lock); -			return i810_setup(dev); -		} -		spin_unlock(&dev->count_lock); -	} -	return retcode; -} - -int i810_release(struct inode *inode, struct file *filp) -{ -	drm_file_t    *priv   = filp->private_data; -	drm_device_t  *dev; -	int	      retcode = 0; - -	lock_kernel(); -	dev    = priv->dev; -	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", -		  current->pid, dev->device, dev->open_count); - -	if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) -	    && dev->lock.pid == current->pid) { -	      	i810_reclaim_buffers(dev, priv->pid); -		DRM_ERROR("Process %d dead, freeing lock for context %d\n", -			  current->pid, -			  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); -		drm_lock_free(dev, -			      &dev->lock.hw_lock->lock, -			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - -				/* FIXME: may require heavy-handed reset of -                                   hardware at this point, possibly -                                   processed via a callback to the X -                                   server. */ -	} else if (dev->lock.hw_lock) { -	   	/* The lock is required to reclaim buffers */ -	   	DECLARE_WAITQUEUE(entry, current); -	   	add_wait_queue(&dev->lock.lock_queue, &entry); -		for (;;) { -			current->state = TASK_INTERRUPTIBLE; -			if (!dev->lock.hw_lock) { -				/* Device has been unregistered */ -				retcode = -EINTR; -				break; -			} -			if (drm_lock_take(&dev->lock.hw_lock->lock, -					  DRM_KERNEL_CONTEXT)) { -				dev->lock.pid	    = priv->pid; -				dev->lock.lock_time = jiffies; -				atomic_inc(&dev->total_locks); -				break;	/* Got lock */ -			} -				/* Contention */ -			atomic_inc(&dev->total_sleeps); -			schedule(); -			if (signal_pending(current)) { -				retcode = -ERESTARTSYS; -				break; -			} -		} -		current->state = TASK_RUNNING; -		remove_wait_queue(&dev->lock.lock_queue, &entry); -	   	if(!retcode) { -		   	i810_reclaim_buffers(dev, priv->pid); -		   	drm_lock_free(dev, &dev->lock.hw_lock->lock, -				      DRM_KERNEL_CONTEXT); -		} -	} -	drm_fasync(-1, filp, 0); - -	down(&dev->struct_sem); -	if (priv->prev) priv->prev->next = priv->next; -	else		dev->file_first	 = priv->next; -	if (priv->next) priv->next->prev = priv->prev; -	else		dev->file_last	 = priv->prev; -	up(&dev->struct_sem); - -	drm_free(priv, sizeof(*priv), DRM_MEM_FILES); -#if LINUX_VERSION_CODE < 0x020333 -	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif -   	atomic_inc(&dev->total_close); -   	spin_lock(&dev->count_lock); -   	if (!--dev->open_count) { -	   	if (atomic_read(&dev->ioctl_count) || dev->blocked) { -		   	DRM_ERROR("Device busy: %d %d\n", -				  atomic_read(&dev->ioctl_count), -				  dev->blocked); -		   	spin_unlock(&dev->count_lock); -			unlock_kernel(); -		   	return -EBUSY; -		} -	   	spin_unlock(&dev->count_lock); -		unlock_kernel(); -		return i810_takedown(dev); -	} -	spin_unlock(&dev->count_lock); -	unlock_kernel(); -	return retcode; -} - -/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */ - -int i810_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, -		unsigned long arg) -{ -	int		 nr	 = DRM_IOCTL_NR(cmd); -	drm_file_t	 *priv	 = filp->private_data; -	drm_device_t	 *dev	 = priv->dev; -	int		 retcode = 0; -	drm_ioctl_desc_t *ioctl; -	drm_ioctl_t	 *func; - -	atomic_inc(&dev->ioctl_count); -	atomic_inc(&dev->total_ioctl); -	++priv->ioctl_count; - -	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", -		  current->pid, cmd, nr, dev->device, priv->authenticated); - -	if (nr >= I810_IOCTL_COUNT) { -		retcode = -EINVAL; -	} else { -		ioctl	  = &i810_ioctls[nr]; -		func	  = ioctl->func; - -		if (!func) { -			DRM_DEBUG("no function\n"); -			retcode = -EINVAL; -		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) -			    || (ioctl->auth_needed && !priv->authenticated)) { -			retcode = -EACCES; -		} else { -			retcode = (func)(inode, filp, cmd, arg); -		} -	} - -	atomic_dec(&dev->ioctl_count); -	return retcode; -} - -int i810_unlock(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_lock_t	  lock; - -	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) -		return -EFAULT; - -	if (lock.context == DRM_KERNEL_CONTEXT) { -		DRM_ERROR("Process %d using kernel context %d\n", -			  current->pid, lock.context); -		return -EINVAL; -	} - -	DRM_DEBUG("%d frees lock (%d holds)\n", -		  lock.context, -		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); -	atomic_inc(&dev->total_unlocks); -	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) -		atomic_inc(&dev->total_contends); -   	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); -	if (!dev->context_flag) { -		if (drm_lock_free(dev, &dev->lock.hw_lock->lock, -				  DRM_KERNEL_CONTEXT)) { -			DRM_ERROR("\n"); -		} -	} -#if DRM_DMA_HISTOGRAM -	atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles() -						       - dev->lck_start)]); -#endif - -	unblock_all_signals(); -	return 0; -} +#define DRIVER_AUTHOR		"VA Linux Systems Inc." + +#define DRIVER_NAME		"i810" +#define DRIVER_DESC		"Intel i810" +#define DRIVER_DATE		"20010215" + +#define DRIVER_MAJOR		1 +#define DRIVER_MINOR		1 +#define DRIVER_PATCHLEVEL	0 + +#define DRIVER_IOCTLS							    \ +	[DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)]   = { i810_dma_init,    1, 1 }, \ +   	[DRM_IOCTL_NR(DRM_IOCTL_I810_VERTEX)] = { i810_dma_vertex,  1, 0 }, \ +   	[DRM_IOCTL_NR(DRM_IOCTL_I810_CLEAR)]  = { i810_clear_bufs,  1, 0 }, \ +      	[DRM_IOCTL_NR(DRM_IOCTL_I810_FLUSH)]  = { i810_flush_ioctl, 1, 0 }, \ +   	[DRM_IOCTL_NR(DRM_IOCTL_I810_GETAGE)] = { i810_getage,      1, 0 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_I810_GETBUF)] = { i810_getbuf,      1, 0 }, \ +   	[DRM_IOCTL_NR(DRM_IOCTL_I810_SWAP)]   = { i810_swap_bufs,   1, 0 }, \ +   	[DRM_IOCTL_NR(DRM_IOCTL_I810_COPY)]   = { i810_copybuf,     1, 0 }, \ +   	[DRM_IOCTL_NR(DRM_IOCTL_I810_DOCOPY)] = { i810_docopy,      1, 0 }, + +#define __HAVE_COUNTERS         4 +#define __HAVE_COUNTER6         _DRM_STAT_IRQ +#define __HAVE_COUNTER7         _DRM_STAT_PRIMARY +#define __HAVE_COUNTER8         _DRM_STAT_SECONDARY +#define __HAVE_COUNTER9         _DRM_STAT_DMA + +#define __HAVE_DMA_QUIESCENT	1 +#define DRIVER_DMA_QUIESCENT() do {					\ +	i810_dma_quiescent( dev );					\ +} while (0) + +#define __HAVE_RELEASE		1 +#define DRIVER_RELEASE() do {						\ +	i810_reclaim_buffers( dev, priv->pid );				\ +} while (0) + +#include "drm_drv.h" + + +#define DRIVER_BUF_PRIV_T	drm_i810_buf_priv_t + +#define DRIVER_AGP_BUFFERS_MAP( dev )					\ +({									\ +	drm_i810_private_t *dev_priv = (dev)->dev_private;		\ +	drm_map_t *map = (dev)->maplist[dev_priv->buffer_map_idx];	\ +	map;								\ +}) + +#include "drm_bufs.h" + + +#include "drm_agpsupport.h" +#include "drm_auth.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_drawable.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" diff --git a/linux-core/i810_drv.h b/linux-core/i810_drv.h index 1c957401..e7824093 100644 --- a/linux-core/i810_drv.h +++ b/linux-core/i810_drv.h @@ -11,11 +11,11 @@   * the rights to use, copy, modify, merge, publish, distribute, sublicense,   * and/or sell copies of the Software, and to permit persons to whom the   * Software is furnished to do so, subject to the following conditions: - *  + *   * The above copyright notice and this permission notice (including the next   * paragraph) shall be included in all copies or substantial portions of the   * Software. - *  + *   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL @@ -67,25 +67,15 @@ typedef struct drm_i810_private {     	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */  	drm_buf_t *mmap_buffer; -	 +  	u32 front_di1, back_di1, zi1; -	 +  	int back_offset;  	int depth_offset;  	int w, h;  	int pitch;  } drm_i810_private_t; -				/* i810_drv.c */ -extern int  i810_version(struct inode *inode, struct file *filp, -			  unsigned int cmd, unsigned long arg); -extern int  i810_open(struct inode *inode, struct file *filp); -extern int  i810_release(struct inode *inode, struct file *filp); -extern int  i810_ioctl(struct inode *inode, struct file *filp, -			unsigned int cmd, unsigned long arg); -extern int  i810_unlock(struct inode *inode, struct file *filp, -			 unsigned int cmd, unsigned long arg); -  				/* i810_dma.c */  extern int  i810_dma_schedule(drm_device_t *dev, int locked);  extern int  i810_getbuf(struct inode *inode, struct file *filp, @@ -101,44 +91,15 @@ extern int  i810_dma_init(struct inode *inode, struct file *filp,  extern int  i810_flush_ioctl(struct inode *inode, struct file *filp,  			     unsigned int cmd, unsigned long arg);  extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid); -extern int  i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, -			unsigned long arg); -extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma); -extern int i810_copybuf(struct inode *inode, struct file *filp,  +extern int  i810_getage(struct inode *inode, struct file *filp,  			unsigned int cmd, unsigned long arg); -extern int i810_docopy(struct inode *inode, struct file *filp,  -		       unsigned int cmd, unsigned long arg); - -				/* i810_bufs.c */ -extern int  i810_addbufs(struct inode *inode, struct file *filp,  +extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma); +extern int i810_copybuf(struct inode *inode, struct file *filp,  			unsigned int cmd, unsigned long arg); -extern int  i810_infobufs(struct inode *inode, struct file *filp,  -			 unsigned int cmd, unsigned long arg); -extern int  i810_markbufs(struct inode *inode, struct file *filp, -			 unsigned int cmd, unsigned long arg); -extern int  i810_freebufs(struct inode *inode, struct file *filp, -			 unsigned int cmd, unsigned long arg); -extern int  i810_addmap(struct inode *inode, struct file *filp, +extern int i810_docopy(struct inode *inode, struct file *filp,  		       unsigned int cmd, unsigned long arg); -				/* i810_context.c */ -extern int  i810_resctx(struct inode *inode, struct file *filp, -		       unsigned int cmd, unsigned long arg); -extern int  i810_addctx(struct inode *inode, struct file *filp, -		       unsigned int cmd, unsigned long arg); -extern int  i810_modctx(struct inode *inode, struct file *filp, -		       unsigned int cmd, unsigned long arg); -extern int  i810_getctx(struct inode *inode, struct file *filp, -		       unsigned int cmd, unsigned long arg); -extern int  i810_switchctx(struct inode *inode, struct file *filp, -			  unsigned int cmd, unsigned long arg); -extern int  i810_newctx(struct inode *inode, struct file *filp, -		       unsigned int cmd, unsigned long arg); -extern int  i810_rmctx(struct inode *inode, struct file *filp, -		      unsigned int cmd, unsigned long arg); - -extern int  i810_context_switch(drm_device_t *dev, int old, int new); -extern int  i810_context_switch_complete(drm_device_t *dev, int new); +extern void i810_dma_quiescent(drm_device_t *dev);  #define I810_VERBOSE 0 @@ -184,7 +145,7 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,  #define RING_START     		0x08  #define START_ADDR          	0x00FFFFF8  #define RING_LEN       		0x0C -#define RING_NR_PAGES       	0x000FF000  +#define RING_NR_PAGES       	0x000FF000  #define RING_REPORT_MASK    	0x00000006  #define RING_REPORT_64K     	0x00000002  #define RING_REPORT_128K    	0x00000004 @@ -222,4 +183,3 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,  #endif - diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index d1c39e99..b498a3e1 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -1,4 +1,4 @@ -/* mga_drv.c -- Matrox g200/g400 driver -*- linux-c -*- +/* mga_drv.c -- Matrox G200/G400 driver -*- linux-c -*-   * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com   *   * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -19,648 +19,80 @@   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: Rickard E. (Rik) Faith <faith@valinux.com> - *	    Jeff Hartmann <jhartmann@valinux.com> - * + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE.   * + * Authors: + *    Rickard E. (Rik) Faith <faith@valinux.com> + *    Gareth Hughes <gareth@valinux.com>   */  #include <linux/config.h> +#include "mga.h"  #include "drmP.h"  #include "mga_drv.h" -#define MGA_NAME	 "mga" -#define MGA_DESC	 "Matrox G200/G400" -#define MGA_DATE	 "20000928" -#define MGA_MAJOR	 2 -#define MGA_MINOR	 1 -#define MGA_PATCHLEVEL	 1 - -static drm_device_t	      mga_device; -drm_ctx_t		      mga_res_ctx; - -static struct file_operations mga_fops = { -#if LINUX_VERSION_CODE >= 0x020400 -				/* This started being used during 2.4.0-test */ -	owner:   THIS_MODULE, -#endif -	open:	 mga_open, -	flush:	 drm_flush, -	release: mga_release, -	ioctl:	 mga_ioctl, -	mmap:	 drm_mmap, -	read:	 drm_read, -	fasync:	 drm_fasync, -   	poll:	 drm_poll, -}; - -static struct miscdevice      mga_misc = { -	minor: MISC_DYNAMIC_MINOR, -	name:  MGA_NAME, -	fops:  &mga_fops, -}; - -static drm_ioctl_desc_t	      mga_ioctls[] = { -	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]     = { mga_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_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_CONTROL)]     = { mga_control,	  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_BUFS)]    = { mga_addbufs,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS)]   = { mga_markbufs,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)]   = { mga_infobufs,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]    = { mga_mapbufs,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]   = { mga_freebufs,	  1, 0 }, - -	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]     = { mga_addctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]      = { mga_rmctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]     = { mga_modctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]     = { mga_getctx,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]  = { mga_switchctx,  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]     = { mga_newctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]     = { mga_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_DMA)]	      = { mga_dma,	  1, 0 }, - -	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	      = { mga_lock,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]      = { mga_unlock,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]      = { drm_finish,	  1, 0 }, - -	[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_MGA_INIT)]    = { mga_dma_init,    1, 1 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)]    = { mga_swap_bufs,   1, 0 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)]   = { mga_clear_bufs,  1, 0 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)]   = { mga_iload,       1, 0 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)]  = { mga_vertex,      1, 0 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)]   = { mga_flush_ioctl, 1, 0 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_indices,     1, 0 }, -     	[DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)]    = { mga_blit,        1, 0 },  -}; - -#define MGA_IOCTL_COUNT DRM_ARRAY_SIZE(mga_ioctls) - -#ifdef MODULE -static char		      *mga = NULL; -#endif - -MODULE_AUTHOR("VA Linux Systems, Inc."); -MODULE_DESCRIPTION("Matrox G200/G400"); -MODULE_PARM(mga, "s"); - -#ifndef MODULE -/* mga_options is called by the kernel to parse command-line options passed - * via the boot-loader (e.g., LILO).  It calls the insmod option routine, - * drm_parse_drm. - */ - -static int __init mga_options(char *str) -{ -	drm_parse_options(str); -	return 1; -} - -__setup("mga=", mga_options); -#endif - -static int mga_setup(drm_device_t *dev) -{ -	int i; - -	atomic_set(&dev->ioctl_count, 0); -	atomic_set(&dev->vma_count, 0); -	dev->buf_use	  = 0; -	atomic_set(&dev->buf_alloc, 0); - -	drm_dma_setup(dev); - -	atomic_set(&dev->total_open, 0); -	atomic_set(&dev->total_close, 0); -	atomic_set(&dev->total_ioctl, 0); -	atomic_set(&dev->total_irq, 0); -	atomic_set(&dev->total_ctx, 0); -	atomic_set(&dev->total_locks, 0); -	atomic_set(&dev->total_unlocks, 0); -	atomic_set(&dev->total_contends, 0); -	atomic_set(&dev->total_sleeps, 0); - -	for (i = 0; i < DRM_HASH_SIZE; i++) { -		dev->magiclist[i].head = NULL; -		dev->magiclist[i].tail = NULL; -	} -	dev->maplist	    = NULL; -	dev->map_count	    = 0; -	dev->vmalist	    = NULL; -	dev->lock.hw_lock   = NULL; -	init_waitqueue_head(&dev->lock.lock_queue); -	dev->queue_count    = 0; -	dev->queue_reserved = 0; -	dev->queue_slots    = 0; -	dev->queuelist	    = NULL; -	dev->irq	    = 0; -	dev->context_flag   = 0; -	dev->interrupt_flag = 0; -	dev->dma_flag	    = 0; -	dev->last_context   = 0; -	dev->last_switch    = 0; -	dev->last_checked   = 0; -	init_timer(&dev->timer); -	init_waitqueue_head(&dev->context_wait); - -	dev->ctx_start	    = 0; -	dev->lck_start	    = 0; - -	dev->buf_rp	  = dev->buf; -	dev->buf_wp	  = dev->buf; -	dev->buf_end	  = dev->buf + DRM_BSZ; -	dev->buf_async	  = NULL; -	init_waitqueue_head(&dev->buf_readers); -	init_waitqueue_head(&dev->buf_writers); - -	DRM_DEBUG("\n"); - -	/* The kernel's context could be created here, but is now created -	   in drm_dma_enqueue.	This is more resource-efficient for -	   hardware that does not do DMA, but may mean that -	   drm_select_queue fails between the time the interrupt is -	   initialized and the time the queues are initialized. */ - -	return 0; -} - - -static int mga_takedown(drm_device_t *dev) -{ -	int		  i; -	drm_magic_entry_t *pt, *next; -	drm_map_t	  *map; -	drm_vma_entry_t	  *vma, *vma_next; - -	DRM_DEBUG("\n"); - -	if (dev->dev_private) mga_dma_cleanup(dev); -	if (dev->irq) mga_irq_uninstall(dev); - -	down(&dev->struct_sem); -	del_timer(&dev->timer); - -	if (dev->devname) { -		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); -		dev->devname = NULL; -	} - -	if (dev->unique) { -		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); -		dev->unique = NULL; -		dev->unique_len = 0; -	} -				/* Clear pid list */ -	for (i = 0; i < DRM_HASH_SIZE; i++) { -		for (pt = dev->magiclist[i].head; pt; pt = next) { -			next = pt->next; -			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); -		} -		dev->magiclist[i].head = dev->magiclist[i].tail = NULL; -	} -   				/* Clear AGP information */ -	if (dev->agp) { -		drm_agp_mem_t *entry; -		drm_agp_mem_t *nexte; - -				/* Remove AGP resources, but leave dev->agp -                                   intact until cleanup is called. */ -		for (entry = dev->agp->memory; entry; entry = nexte) { -			nexte = entry->next; -			if (entry->bound) drm_unbind_agp(entry->memory); -			drm_free_agp(entry->memory, entry->pages); -			drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); -		} -		dev->agp->memory = NULL; - -		if (dev->agp->acquired)	_drm_agp_release(); - -		dev->agp->acquired = 0; -		dev->agp->enabled  = 0; -	} -				/* Clear vma list (only built for debugging) */ -	if (dev->vmalist) { -		for (vma = dev->vmalist; vma; vma = vma_next) { -			vma_next = vma->next; -			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); -		} -		dev->vmalist = NULL; -	} - -				/* Clear map area and mtrr information */ -	if (dev->maplist) { -		for (i = 0; i < dev->map_count; i++) { -			map = dev->maplist[i]; -			switch (map->type) { -			case _DRM_REGISTERS: -			case _DRM_FRAME_BUFFER: -#ifdef CONFIG_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: -				drm_free_pages((unsigned long)map->handle, -					       drm_order(map->size) -					       - PAGE_SHIFT, -					       DRM_MEM_SAREA); -				break; -			case _DRM_AGP: -				break; -			} -			drm_free(map, sizeof(*map), DRM_MEM_MAPS); -		} -		drm_free(dev->maplist, -			 dev->map_count * sizeof(*dev->maplist), -			 DRM_MEM_MAPS); -		dev->maplist   = NULL; -		dev->map_count = 0; -	} - -	if (dev->queuelist) { -		for (i = 0; i < dev->queue_count; i++) { -			drm_waitlist_destroy(&dev->queuelist[i]->waitlist); -			if (dev->queuelist[i]) { -				drm_free(dev->queuelist[i], -					 sizeof(*dev->queuelist[0]), -					 DRM_MEM_QUEUES); -				dev->queuelist[i] = NULL; -			} -		} -		drm_free(dev->queuelist, -			 dev->queue_slots * sizeof(*dev->queuelist), -			 DRM_MEM_QUEUES); -		dev->queuelist	 = NULL; -	} - -	drm_dma_takedown(dev); - -	dev->queue_count     = 0; -	if (dev->lock.hw_lock) { -		dev->lock.hw_lock    = NULL; /* SHM removed */ -		dev->lock.pid	     = 0; -		wake_up_interruptible(&dev->lock.lock_queue); -	} -	up(&dev->struct_sem); - -	return 0; -} - -/* mga_init is called via init_module at module load time, or via - * linux/init/main.c (this is not currently supported). */ - -static int __init mga_init(void) -{ -	int		      retcode; -	drm_device_t	      *dev = &mga_device; - -	DRM_DEBUG("\n"); - -	memset((void *)dev, 0, sizeof(*dev)); -	dev->count_lock	  = SPIN_LOCK_UNLOCKED; -	sema_init(&dev->struct_sem, 1); - -#ifdef MODULE -	drm_parse_options(mga); -#endif -	if ((retcode = misc_register(&mga_misc))) { -		DRM_ERROR("Cannot register \"%s\"\n", MGA_NAME); -		return retcode; -	} -	dev->device = MKDEV(MISC_MAJOR, mga_misc.minor); -	dev->name   = MGA_NAME; - -	drm_mem_init(); -	drm_proc_init(dev); -	dev->agp    = drm_agp_init(); -      	if(dev->agp == NULL) { -	   	DRM_INFO("The mga drm module requires the agpgart module" -		         " to function correctly\nPlease load the agpgart" -		         " module before you load the mga module\n"); -	   	drm_proc_cleanup(); -	   	misc_deregister(&mga_misc); -	   	mga_takedown(dev); -	   	return -ENOMEM; -	} -#ifdef CONFIG_MTRR -   	dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base, -				      dev->agp->agp_info.aper_size * 1024 * 1024, -				      MTRR_TYPE_WRCOMB, -				      1); -#endif -	if((retcode = drm_ctxbitmap_init(dev))) { -		DRM_ERROR("Cannot allocate memory for context bitmap.\n"); -		drm_proc_cleanup(); -		misc_deregister(&mga_misc); -		mga_takedown(dev); -		return retcode; -	} - -	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", -		 MGA_NAME, -		 MGA_MAJOR, -		 MGA_MINOR, -		 MGA_PATCHLEVEL, -		 MGA_DATE, -		 mga_misc.minor); - -	return 0; -} - -/* mga_cleanup is called via cleanup_module at module unload time. */ - -static void __exit mga_cleanup(void) -{ -	drm_device_t	      *dev = &mga_device; - -	DRM_DEBUG("\n"); - -	drm_proc_cleanup(); -	if (misc_deregister(&mga_misc)) { -		DRM_ERROR("Cannot unload module\n"); -	} else { -		DRM_INFO("Module unloaded\n"); -	} -	drm_ctxbitmap_cleanup(dev); -#ifdef CONFIG_MTRR -   	if(dev->agp && dev->agp->agp_mtrr) { -	   	int retval; -	   	retval = mtrr_del(dev->agp->agp_mtrr, -				  dev->agp->agp_info.aper_base, -				  dev->agp->agp_info.aper_size * 1024*1024); -	   	DRM_DEBUG("mtrr_del = %d\n", retval); -	} -#endif - -	mga_takedown(dev); -	if (dev->agp) { -		drm_agp_uninit(); -		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); -		dev->agp = NULL; -	} -} - -module_init(mga_init); -module_exit(mga_cleanup); - - -int mga_version(struct inode *inode, struct file *filp, unsigned int cmd, -		  unsigned long arg) -{ -	drm_version_t version; -	int	      len; - -	if (copy_from_user(&version, -			   (drm_version_t *)arg, -			   sizeof(version))) -		return -EFAULT; - -#define DRM_COPY(name,value)				     \ -	len = strlen(value);				     \ -	if (len > name##_len) len = name##_len;		     \ -	name##_len = strlen(value);			     \ -	if (len && name) {				     \ -		if (copy_to_user(name, value, len))	     \ -			return -EFAULT;			     \ -	} - -	version.version_major	   = MGA_MAJOR; -	version.version_minor	   = MGA_MINOR; -	version.version_patchlevel = MGA_PATCHLEVEL; - -	DRM_COPY(version.name, MGA_NAME); -	DRM_COPY(version.date, MGA_DATE); -	DRM_COPY(version.desc, MGA_DESC); - -	if (copy_to_user((drm_version_t *)arg, -			 &version, -			 sizeof(version))) -		return -EFAULT; -	return 0; -} - -int mga_open(struct inode *inode, struct file *filp) -{ -	drm_device_t  *dev    = &mga_device; -	int	      retcode = 0; - -	DRM_DEBUG("open_count = %d\n", dev->open_count); -	if (!(retcode = drm_open_helper(inode, filp, dev))) { -#if LINUX_VERSION_CODE < 0x020333 -		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif -		atomic_inc(&dev->total_open); -		spin_lock(&dev->count_lock); -		if (!dev->open_count++) { -			spin_unlock(&dev->count_lock); -			return mga_setup(dev); -		} -		spin_unlock(&dev->count_lock); -	} -	return retcode; -} - -int mga_release(struct inode *inode, struct file *filp) -{ -	drm_file_t    *priv   = filp->private_data; -	drm_device_t  *dev; -	int	      retcode = 0; - -	lock_kernel(); -	dev    = priv->dev; -	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", -		  current->pid, dev->device, dev->open_count); - -	if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) -	    && dev->lock.pid == current->pid) { -	      	mga_reclaim_buffers(dev, priv->pid); -		DRM_INFO("Process %d dead (ctx %d, d_s = 0x%02lx)\n", -			 current->pid, -			 _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock), -			 dev->dev_private ? -			 ((drm_mga_private_t *)dev->dev_private) -			 ->dispatch_status -			 : 0); - -		if (dev->dev_private) -			((drm_mga_private_t *)dev->dev_private) -				->dispatch_status &= MGA_IN_DISPATCH; -		 -		drm_lock_free(dev, -			      &dev->lock.hw_lock->lock, -			      _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); -	} else if (dev->lock.hw_lock) { -	   	/* The lock is required to reclaim buffers */ -	   	DECLARE_WAITQUEUE(entry, current); -	   	add_wait_queue(&dev->lock.lock_queue, &entry); -		for (;;) { -			current->state = TASK_INTERRUPTIBLE; -			if (!dev->lock.hw_lock) { -				/* Device has been unregistered */ -				retcode = -EINTR; -				break; -			} -			if (drm_lock_take(&dev->lock.hw_lock->lock, -					  DRM_KERNEL_CONTEXT)) { -				dev->lock.pid	    = priv->pid; -				dev->lock.lock_time = jiffies; -				atomic_inc(&dev->total_locks); -				break;	/* Got lock */ -			} -				/* Contention */ -			atomic_inc(&dev->total_sleeps); -			schedule(); -			if (signal_pending(current)) { -				retcode = -ERESTARTSYS; -				break; -			} -		} -		current->state = TASK_RUNNING; -		remove_wait_queue(&dev->lock.lock_queue, &entry); -	   	if(!retcode) { -		   	mga_reclaim_buffers(dev, priv->pid); -			if (dev->dev_private) -				((drm_mga_private_t *)dev->dev_private) -					->dispatch_status &= MGA_IN_DISPATCH; -		   	drm_lock_free(dev, &dev->lock.hw_lock->lock, -				      DRM_KERNEL_CONTEXT); -		} -	} -	drm_fasync(-1, filp, 0); - -	down(&dev->struct_sem); -	if (priv->remove_auth_on_close == 1) { -		drm_file_t *temp = dev->file_first; -		while(temp) { -			temp->authenticated = 0; -			temp = temp->next; -		} -	} -	if (priv->prev) priv->prev->next = priv->next; -	else		dev->file_first	 = priv->next; -	if (priv->next) priv->next->prev = priv->prev; -	else		dev->file_last	 = priv->prev; -	up(&dev->struct_sem); - -	drm_free(priv, sizeof(*priv), DRM_MEM_FILES); -#if LINUX_VERSION_CODE < 0x020333 -	MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif -   	atomic_inc(&dev->total_close); -   	spin_lock(&dev->count_lock); -   	if (!--dev->open_count) { -	   	if (atomic_read(&dev->ioctl_count) || dev->blocked) { -		   	DRM_ERROR("Device busy: %d %d\n", -				  atomic_read(&dev->ioctl_count), -				  dev->blocked); -		   	spin_unlock(&dev->count_lock); -			unlock_kernel(); -		   	return -EBUSY; -		} -	   	spin_unlock(&dev->count_lock); -		unlock_kernel(); -	   	return mga_takedown(dev); -	} -	spin_unlock(&dev->count_lock); -	unlock_kernel(); -	return retcode; -} - - -/* drm_ioctl is called whenever a process performs an ioctl on /dev/drm. */ - -int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, -		unsigned long arg) -{ -	int		 nr	 = DRM_IOCTL_NR(cmd); -	drm_file_t	 *priv	 = filp->private_data; -	drm_device_t	 *dev	 = priv->dev; -	int		 retcode = 0; -	drm_ioctl_desc_t *ioctl; -	drm_ioctl_t	 *func; - -	atomic_inc(&dev->ioctl_count); -	atomic_inc(&dev->total_ioctl); -	++priv->ioctl_count; - -	if (nr >= MGA_IOCTL_COUNT) { -		retcode = -EINVAL; -	} else { -		ioctl	  = &mga_ioctls[nr]; -		func	  = ioctl->func; - -		if (!func) { -			DRM_DEBUG("no function: pid = %d, cmd = 0x%02x," -				  " nr = 0x%02x, dev 0x%x, auth = %d\n", -				  current->pid, cmd, nr, dev->device, -				  priv->authenticated); -			retcode = -EINVAL; -		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) -			    || (ioctl->auth_needed && !priv->authenticated)) { -			retcode = -EACCES; -		} else { -			retcode = (func)(inode, filp, cmd, arg); -		} -	} - -	atomic_dec(&dev->ioctl_count); -	return retcode; -} - -int mga_unlock(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_lock_t	  lock; - -	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) -		return -EFAULT; - -	if (lock.context == DRM_KERNEL_CONTEXT) { -		DRM_ERROR("Process %d using kernel context %d\n", -			  current->pid, lock.context); -		return -EINVAL; -	} - -	atomic_inc(&dev->total_unlocks); -	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) -		atomic_inc(&dev->total_contends); -	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); -	mga_dma_schedule(dev, 1); - -	if (drm_lock_free(dev, &dev->lock.hw_lock->lock, -			  DRM_KERNEL_CONTEXT)) DRM_ERROR("\n"); - -	unblock_all_signals(); -	return 0; -} +#define DRIVER_AUTHOR		"Gareth Hughes, VA Linux Systems Inc." + +#define DRIVER_NAME		"mga" +#define DRIVER_DESC		"Matrox G200/G400" +#define DRIVER_DATE		"20010212" + +#define DRIVER_MAJOR		3 +#define DRIVER_MINOR		0 +#define DRIVER_PATCHLEVEL	0 + +#define DRIVER_IOCTLS							   \ +	[DRM_IOCTL_NR(DRM_IOCTL_DMA)]	      = { mga_dma_buffers, 1, 0 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_MGA_INIT)]    = { mga_dma_init,    1, 1 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_MGA_FLUSH)]   = { mga_dma_flush,   1, 0 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_MGA_RESET)]   = { mga_dma_reset,   1, 0 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_MGA_SWAP)]    = { mga_dma_swap,    1, 0 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)]   = { mga_dma_clear,   1, 0 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)]  = { mga_dma_vertex,  1, 0 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_dma_indices, 1, 0 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)]   = { mga_dma_iload,   1, 0 }, \ +	[DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)]    = { mga_dma_blit,    1, 0 }, + +#define __HAVE_COUNTERS         3 +#define __HAVE_COUNTER6         _DRM_STAT_IRQ +#define __HAVE_COUNTER7         _DRM_STAT_PRIMARY +#define __HAVE_COUNTER8         _DRM_STAT_SECONDARY + +#define __HAVE_DMA_QUIESCENT	1 +#define DRIVER_DMA_QUIESCENT()						\ +do {									\ +	drm_mga_private_t *dev_priv = dev->dev_private;			\ +	return mga_do_wait_for_idle( dev_priv );			\ +} while (0) + +#define DRIVER_PRETAKEDOWN() do {					\ +	if ( dev->dev_private ) mga_do_cleanup_dma( dev );		\ +} while (0) + +#include "drm_drv.h" + + +#define DRIVER_BUF_PRIV_T	drm_mga_buf_priv_t + +#define DRIVER_AGP_BUFFERS_MAP( dev )					\ +	((drm_mga_private_t *)((dev)->dev_private))->buffers + +#include "drm_bufs.h" + + +#include "drm_agpsupport.h" +#include "drm_auth.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_drawable.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index cd5c0e88..08de2039 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -1,7 +1,7 @@  /* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-   * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com   * - * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.   * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.   * All Rights Reserved.   * @@ -19,687 +19,98 @@   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE.   *   * Authors:   *    Rickard E. (Rik) Faith <faith@valinux.com> - *    Kevin E. Martin <martin@valinux.com>   *    Gareth Hughes <gareth@valinux.com> - *   */  #include <linux/config.h> +#include "r128.h"  #include "drmP.h"  #include "r128_drv.h" -#define R128_NAME		"r128" -#define R128_DESC		"ATI Rage 128" -#define R128_DATE		"20010130" -#define R128_MAJOR		2 -#define R128_MINOR		1 -#define R128_PATCHLEVEL		4 - -static drm_device_t	r128_device; -drm_ctx_t		r128_res_ctx; - -static struct file_operations r128_fops = { -#if LINUX_VERSION_CODE >= 0x020400 -				/* This started being used during 2.4.0-test */ -	owner:   THIS_MODULE, -#endif -	open:	 r128_open, -	flush:	 drm_flush, -	release: r128_release, -	ioctl:	 r128_ioctl, -	mmap:	 drm_mmap, -	read:	 drm_read, -	fasync:	 drm_fasync, -	poll:	 drm_poll, -}; - -static struct miscdevice      r128_misc = { -	minor: MISC_DYNAMIC_MINOR, -	name:  R128_NAME, -	fops:  &r128_fops, -}; - -static drm_ioctl_desc_t	      r128_ioctls[] = { -	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]      = { r128_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_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_BUFS)]     = { r128_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)]     = { r128_mapbufs,      1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]    = { drm_freebufs,      1, 0 }, - -	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]      = { r128_addctx,	      1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]       = { r128_rmctx,	      1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]      = { r128_modctx,	      1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]      = { r128_getctx,	      1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]   = { r128_switchctx,    1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]      = { r128_newctx,	      1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]      = { r128_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_DMA)]	       = { r128_cce_buffers,  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	       = { r128_lock,	      1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]       = { r128_unlock,	      1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]       = { drm_finish,	      1, 0 }, - -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -	[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 - -	[DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)]      = { r128_cce_init,     1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_START)] = { r128_cce_start,    1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_STOP)]  = { r128_cce_stop,     1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_RESET)] = { r128_cce_reset,    1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_IDLE)]  = { r128_cce_idle,     1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)]     = { r128_engine_reset, 1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_FULLSCREEN)]= { r128_fullscreen,   1, 0 }, - -	[DRM_IOCTL_NR(DRM_IOCTL_R128_SWAP)]     = { r128_cce_swap,      1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_CLEAR)]    = { r128_cce_clear,     1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)]   = { r128_cce_vertex,    1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_INDICES)]  = { r128_cce_indices,   1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_BLIT)]     = { r128_cce_blit,      1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_DEPTH)]    = { r128_cce_depth,     1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_STIPPLE)]  = { r128_cce_stipple,   1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect,  1, 1 }, -}; -#define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls) - -#ifdef MODULE -static char		      *r128 = NULL; -#endif - -MODULE_AUTHOR("VA Linux Systems, Inc."); -MODULE_DESCRIPTION("r128"); -MODULE_PARM(r128, "s"); - -#ifndef MODULE -/* r128_options is called by the kernel to parse command-line options - * passed via the boot-loader (e.g., LILO).  It calls the insmod option - * routine, drm_parse_drm. - */ - -static int __init r128_options(char *str) -{ -	drm_parse_options(str); -	return 1; -} - -__setup("r128=", r128_options); -#endif - -static int r128_setup(drm_device_t *dev) -{ -	int i; - -	atomic_set(&dev->ioctl_count, 0); -	atomic_set(&dev->vma_count, 0); -	dev->buf_use	  = 0; -	atomic_set(&dev->buf_alloc, 0); - -	drm_dma_setup(dev); - -	atomic_set(&dev->total_open, 0); -	atomic_set(&dev->total_close, 0); -	atomic_set(&dev->total_ioctl, 0); -	atomic_set(&dev->total_irq, 0); -	atomic_set(&dev->total_ctx, 0); -	atomic_set(&dev->total_locks, 0); -	atomic_set(&dev->total_unlocks, 0); -	atomic_set(&dev->total_contends, 0); -	atomic_set(&dev->total_sleeps, 0); - -	for (i = 0; i < DRM_HASH_SIZE; i++) { -		dev->magiclist[i].head = NULL; -		dev->magiclist[i].tail = NULL; -	} -	dev->maplist	    = NULL; -	dev->map_count	    = 0; -	dev->vmalist	    = NULL; -	dev->lock.hw_lock   = NULL; -	init_waitqueue_head(&dev->lock.lock_queue); -	dev->queue_count    = 0; -	dev->queue_reserved = 0; -	dev->queue_slots    = 0; -	dev->queuelist	    = NULL; -	dev->irq	    = 0; -	dev->context_flag   = 0; -	dev->interrupt_flag = 0; -	dev->dma_flag	    = 0; -	dev->last_context   = 0; -	dev->last_switch    = 0; -	dev->last_checked   = 0; -	init_timer(&dev->timer); -	init_waitqueue_head(&dev->context_wait); - -	dev->ctx_start	    = 0; -	dev->lck_start	    = 0; - -	dev->buf_rp	  = dev->buf; -	dev->buf_wp	  = dev->buf; -	dev->buf_end	  = dev->buf + DRM_BSZ; -	dev->buf_async	  = NULL; -	init_waitqueue_head(&dev->buf_readers); -	init_waitqueue_head(&dev->buf_writers); - -	r128_res_ctx.handle=-1; - -	DRM_DEBUG("\n"); - -	/* The kernel's context could be created here, but is now created -	   in drm_dma_enqueue.	This is more resource-efficient for -	   hardware that does not do DMA, but may mean that -	   drm_select_queue fails between the time the interrupt is -	   initialized and the time the queues are initialized. */ - -	return 0; -} - - -static int r128_takedown(drm_device_t *dev) -{ -	int		  i; -	drm_magic_entry_t *pt, *next; -	drm_map_t	  *map; -	drm_vma_entry_t	  *vma, *vma_next; - -	DRM_DEBUG("\n"); - -	down(&dev->struct_sem); -	del_timer(&dev->timer); - -	if (dev->devname) { -		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); -		dev->devname = NULL; -	} - -	if (dev->unique) { -		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); -		dev->unique = NULL; -		dev->unique_len = 0; -	} -				/* Clear pid list */ -	for (i = 0; i < DRM_HASH_SIZE; i++) { -		for (pt = dev->magiclist[i].head; pt; pt = next) { -			next = pt->next; -			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); -		} -		dev->magiclist[i].head = dev->magiclist[i].tail = NULL; -	} - -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -				/* Clear AGP information */ -	if (dev->agp) { -		drm_agp_mem_t *entry; -		drm_agp_mem_t *nexte; - -				/* Remove AGP resources, but leave dev->agp -                                   intact until r128_cleanup is called. */ -		for (entry = dev->agp->memory; entry; entry = nexte) { -			nexte = entry->next; -			if (entry->bound) drm_unbind_agp(entry->memory); -			drm_free_agp(entry->memory, entry->pages); -			drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); -		} -		dev->agp->memory = NULL; - -		if (dev->agp->acquired)	_drm_agp_release(); - -		dev->agp->acquired = 0; -		dev->agp->enabled  = 0; -	} -#endif - -				/* Clear vma list (only built for debugging) */ -	if (dev->vmalist) { -		for (vma = dev->vmalist; vma; vma = vma_next) { -			vma_next = vma->next; -			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); -		} -		dev->vmalist = NULL; -	} - -				/* Clear map area and mtrr information */ -	if (dev->maplist) { -		for (i = 0; i < dev->map_count; i++) { -			map = dev->maplist[i]; -			switch (map->type) { -			case _DRM_REGISTERS: -			case _DRM_FRAME_BUFFER: -#ifdef CONFIG_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: -				drm_free_pages((unsigned long)map->handle, -					       drm_order(map->size) -					       - PAGE_SHIFT, -					       DRM_MEM_SAREA); -				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); -		dev->maplist   = NULL; -		dev->map_count = 0; -	} - -	drm_dma_takedown(dev); - -	dev->queue_count     = 0; -	if (dev->lock.hw_lock) { -		dev->lock.hw_lock    = NULL; /* SHM removed */ -		dev->lock.pid	     = 0; -		wake_up_interruptible(&dev->lock.lock_queue); -	} -	up(&dev->struct_sem); - -	return 0; -} - -/* r128_init is called via init_module at module load time, or via - * linux/init/main.c (this is not currently supported). */ - -static int __init r128_init(void) -{ -	int		      retcode; -	drm_device_t	      *dev = &r128_device; - -	DRM_DEBUG("\n"); - -	memset((void *)dev, 0, sizeof(*dev)); -	dev->count_lock	  = SPIN_LOCK_UNLOCKED; -	sema_init(&dev->struct_sem, 1); - -#ifdef MODULE -	drm_parse_options(r128); -#endif - -	if ((retcode = misc_register(&r128_misc))) { -		DRM_ERROR("Cannot register \"%s\"\n", R128_NAME); -		return retcode; -	} -	dev->device = MKDEV(MISC_MAJOR, r128_misc.minor); -	dev->name   = R128_NAME; - -	drm_mem_init(); -	drm_proc_init(dev); - -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -	dev->agp    = drm_agp_init(); -	if (dev->agp == NULL) { -		DRM_ERROR("Cannot initialize agpgart module.\n"); -		drm_proc_cleanup(); -		misc_deregister(&r128_misc); -		r128_takedown(dev); -		return -ENOMEM; -	} - -#ifdef CONFIG_MTRR -	dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base, -				      dev->agp->agp_info.aper_size*1024*1024, -				      MTRR_TYPE_WRCOMB, -				      1); -#endif -#endif - -	if((retcode = drm_ctxbitmap_init(dev))) { -		DRM_ERROR("Cannot allocate memory for context bitmap.\n"); -		drm_proc_cleanup(); -		misc_deregister(&r128_misc); -		r128_takedown(dev); -		return retcode; -	} - -	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", -		 R128_NAME, -		 R128_MAJOR, -		 R128_MINOR, -		 R128_PATCHLEVEL, -		 R128_DATE, -		 r128_misc.minor); - -	return 0; -} - -/* r128_cleanup is called via cleanup_module at module unload time. */ - -static void __exit r128_cleanup(void) -{ -	drm_device_t	      *dev = &r128_device; - -	DRM_DEBUG("\n"); - -	drm_proc_cleanup(); -	if (misc_deregister(&r128_misc)) { -		DRM_ERROR("Cannot unload module\n"); -	} else { -		DRM_INFO("Module unloaded\n"); -	} -	drm_ctxbitmap_cleanup(dev); -	r128_takedown(dev); -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -	if (dev->agp) { -		drm_agp_uninit(); -		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); -		dev->agp = NULL; -	} -#endif -} - -module_init(r128_init); -module_exit(r128_cleanup); - - -int r128_version(struct inode *inode, struct file *filp, -		 unsigned int cmd, unsigned long arg) -{ -	drm_version_t version; -	int	      len; - -	if (copy_from_user(&version, -			   (drm_version_t *)arg, -			   sizeof(version))) -		return -EFAULT; - -#define DRM_COPY(name,value)					\ -	len = strlen(value);					\ -	if (len > name##_len) len = name##_len;			\ -	name##_len = strlen(value);				\ -	if (len && name) {					\ -		if (copy_to_user(name, value, len))		\ -			return -EFAULT;				\ -	} - -	version.version_major	   = R128_MAJOR; -	version.version_minor	   = R128_MINOR; -	version.version_patchlevel = R128_PATCHLEVEL; - -	DRM_COPY(version.name, R128_NAME); -	DRM_COPY(version.date, R128_DATE); -	DRM_COPY(version.desc, R128_DESC); - -	if (copy_to_user((drm_version_t *)arg, -			 &version, -			 sizeof(version))) -		return -EFAULT; -	return 0; -} - -int r128_open(struct inode *inode, struct file *filp) -{ -	drm_device_t  *dev    = &r128_device; -	int	      retcode = 0; - -	DRM_DEBUG("open_count = %d\n", dev->open_count); -	if (!(retcode = drm_open_helper(inode, filp, dev))) { -#if LINUX_VERSION_CODE < 0x020333 -		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif -		atomic_inc(&dev->total_open); -		spin_lock(&dev->count_lock); -		if (!dev->open_count++) { -			spin_unlock(&dev->count_lock); -			return r128_setup(dev); -		} -		spin_unlock(&dev->count_lock); -	} - -	return retcode; -} - -int r128_release(struct inode *inode, struct file *filp) -{ -	drm_file_t    *priv   = filp->private_data; -	drm_device_t  *dev; -	int	      retcode = 0; - -	lock_kernel(); -	dev = priv->dev; - -	DRM_DEBUG("open_count = %d\n", dev->open_count); - -	/* Force the cleanup of page flipping when required */ -	if ( dev->dev_private ) { -		drm_r128_private_t *dev_priv = dev->dev_private; -		if ( dev_priv->page_flipping ) { -			r128_do_cleanup_pageflip( dev ); -		} -	} - -	if (!(retcode = drm_release(inode, filp))) { -#if LINUX_VERSION_CODE < 0x020333 -		MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif -		atomic_inc(&dev->total_close); -		spin_lock(&dev->count_lock); -		if (!--dev->open_count) { -			if (atomic_read(&dev->ioctl_count) || dev->blocked) { -				DRM_ERROR("Device busy: %d %d\n", -					  atomic_read(&dev->ioctl_count), -					  dev->blocked); -				spin_unlock(&dev->count_lock); -				unlock_kernel(); -				return -EBUSY; -			} -			spin_unlock(&dev->count_lock); -			unlock_kernel(); -			return r128_takedown(dev); -		} -		spin_unlock(&dev->count_lock); -	} - -	unlock_kernel(); -	return retcode; -} +#define DRIVER_AUTHOR		"Gareth Hughes, VA Linux Systems Inc." + +#define DRIVER_NAME		"r128" +#define DRIVER_DESC		"ATI Rage 128" +#define DRIVER_DATE		"20010214" + +#define DRIVER_MAJOR		2 +#define DRIVER_MINOR		1 +#define DRIVER_PATCHLEVEL	4 + +#define DRIVER_IOCTLS							    \ +   [DRM_IOCTL_NR(DRM_IOCTL_DMA)]             = { r128_cce_buffers,  1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)]       = { r128_cce_init,     1, 1 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_START)]  = { r128_cce_start,    1, 1 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_STOP)]   = { r128_cce_stop,     1, 1 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_RESET)]  = { r128_cce_reset,    1, 1 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_CCE_IDLE)]   = { r128_cce_idle,     1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)]      = { r128_engine_reset, 1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_FULLSCREEN)] = { r128_fullscreen,   1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_SWAP)]       = { r128_cce_swap,     1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_CLEAR)]      = { r128_cce_clear,    1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)]     = { r128_cce_vertex,   1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_INDICES)]    = { r128_cce_indices,  1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_BLIT)]       = { r128_cce_blit,     1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_DEPTH)]      = { r128_cce_depth,    1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_STIPPLE)]    = { r128_cce_stipple,  1, 0 }, \ +   [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)]   = { r128_cce_indirect, 1, 1 }, -/* r128_ioctl is called whenever a process performs an ioctl on /dev/drm. */ -int r128_ioctl(struct inode *inode, struct file *filp, -	       unsigned int cmd, unsigned long arg) -{ -	int		 nr	 = DRM_IOCTL_NR(cmd); -	drm_file_t	 *priv	 = filp->private_data; -	drm_device_t	 *dev	 = priv->dev; -	int		 retcode = 0; -	drm_ioctl_desc_t *ioctl; -	drm_ioctl_t	 *func; - -	atomic_inc(&dev->ioctl_count); -	atomic_inc(&dev->total_ioctl); -	++priv->ioctl_count; - -	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", -		  current->pid, cmd, nr, dev->device, priv->authenticated); - -	if (nr >= R128_IOCTL_COUNT) { -		retcode = -EINVAL; -	} else { -		ioctl	  = &r128_ioctls[nr]; -		func	  = ioctl->func; - -		if (!func) { -			DRM_DEBUG("no function\n"); -			retcode = -EINVAL; -		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) -			   || (ioctl->auth_needed && !priv->authenticated)) { -			retcode = -EACCES; -		} else { -			retcode = (func)(inode, filp, cmd, arg); -		} -	} - -	atomic_dec(&dev->ioctl_count); -	return retcode; -} - -int r128_lock(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; -        DECLARE_WAITQUEUE(entry, current); -        int               ret   = 0; -        drm_lock_t        lock; -#if DRM_DMA_HISTOGRAM -        cycles_t          start; - -        dev->lck_start = start = get_cycles(); -#endif - -        if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) -		return -EFAULT; - -        if (lock.context == DRM_KERNEL_CONTEXT) { -                DRM_ERROR("Process %d using kernel context %d\n", -                          current->pid, lock.context); -                return -EINVAL; -        } - -        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", -                  lock.context, current->pid, dev->lock.hw_lock->lock, -                  lock.flags); - -        if (lock.context < 0) -                return -EINVAL; - -        if (!ret) { -                add_wait_queue(&dev->lock.lock_queue, &entry); -                for (;;) { -                        current->state = TASK_INTERRUPTIBLE; -                        if (!dev->lock.hw_lock) { -                                /* Device has been unregistered */ -                                ret = -EINTR; -                                break; -                        } -                        if (drm_lock_take(&dev->lock.hw_lock->lock, -                                          lock.context)) { -                                dev->lock.pid       = current->pid; -                                dev->lock.lock_time = jiffies; -                                atomic_inc(&dev->total_locks); -                                break;  /* Got lock */ -                        } - -                                /* Contention */ -                        atomic_inc(&dev->total_sleeps); -                        schedule(); -                        if (signal_pending(current)) { -                                ret = -ERESTARTSYS; -                                break; -                        } -                } -                current->state = TASK_RUNNING; -                remove_wait_queue(&dev->lock.lock_queue, &entry); -        } - -        if (!ret) { -		sigemptyset(&dev->sigmask); -		sigaddset(&dev->sigmask, SIGSTOP); -		sigaddset(&dev->sigmask, SIGTSTP); -		sigaddset(&dev->sigmask, SIGTTIN); -		sigaddset(&dev->sigmask, SIGTTOU); -		dev->sigdata.context = lock.context; -		dev->sigdata.lock    = dev->lock.hw_lock; -		block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); -                if (lock.flags & _DRM_LOCK_READY) { -				/* Wait for space in DMA/FIFO */ -		} -                if (lock.flags & _DRM_LOCK_QUIESCENT) { -				/* Make hardware quiescent */ -			DRM_DEBUG( "not quiescent!\n" );  #if 0 -                        r128_quiescent(dev); -#endif -		} -        } - -#if LINUX_VERSION_CODE < 0x020400 -	if (lock.context != r128_res_ctx.handle) { -		current->counter = 5; -		current->priority = DEF_PRIORITY/4; -	} -#endif -        DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); - -#if DRM_DMA_HISTOGRAM -        atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); -#endif - -        return ret; -} - - -int r128_unlock(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_lock_t	  lock; - -	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) -		return -EFAULT; - -	if (lock.context == DRM_KERNEL_CONTEXT) { -		DRM_ERROR("Process %d using kernel context %d\n", -			  current->pid, lock.context); -		return -EINVAL; -	} - -	DRM_DEBUG("%d frees lock (%d holds)\n", -		  lock.context, -		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); -	atomic_inc(&dev->total_unlocks); -	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) -		atomic_inc(&dev->total_contends); -	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); -				/* FIXME: Try to send data to card here */ -	if (!dev->context_flag) { -		if (drm_lock_free(dev, &dev->lock.hw_lock->lock, -				  DRM_KERNEL_CONTEXT)) { -			DRM_ERROR("\n"); -		} -	} - -#if LINUX_VERSION_CODE < 0x020400 -	if (lock.context != r128_res_ctx.handle) { -		current->counter = 5; -		current->priority = DEF_PRIORITY; -	} -#endif -	unblock_all_signals(); -	return 0; -} +/* GH: Count data sent to card via ring or vertex/indirect buffers. + */ +#define __HAVE_COUNTERS         3 +#define __HAVE_COUNTER6         _DRM_STAT_IRQ +#define __HAVE_COUNTER7         _DRM_STAT_PRIMARY +#define __HAVE_COUNTER8         _DRM_STAT_SECONDARY +#endif + +#define __HAVE_DMA_QUIESCENT	1 +#define DRIVER_DMA_QUIESCENT() do {					\ +	drm_r128_private_t *dev_priv = dev->dev_private;		\ +	return r128_do_cce_idle( dev_priv );				\ +} while (0) + +#define DRIVER_PRERELEASE() do {					\ +	if ( dev->dev_private ) {					\ +		drm_r128_private_t *dev_priv = dev->dev_private;	\ +		if ( dev_priv->page_flipping ) {			\ +			r128_do_cleanup_pageflip( dev );		\ +		}							\ +	}								\ +} while (0) + +#define DRIVER_PRETAKEDOWN() do {					\ +	if ( dev->dev_private ) r128_do_cleanup_cce( dev );		\ +} while (0) + +#include "drm_drv.h" + + +#define DRIVER_BUF_PRIV_T	drm_r128_buf_priv_t + +#define DRIVER_AGP_BUFFERS_MAP( dev )					\ +	((drm_r128_private_t *)((dev)->dev_private))->buffers + +#include "drm_bufs.h" + + +#include "drm_agpsupport.h" +#include "drm_auth.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_drawable.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index 0113ed97..da046106 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -1,7 +1,7 @@  /* radeon_drv.c -- ATI Radeon driver -*- linux-c -*- + * Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com   * - * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.   * All Rights Reserved.   *   * Permission is hereby granted, free of charge, to any person obtaining a @@ -18,685 +18,96 @@   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL - * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR   * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Authors: Kevin E. Martin <martin@valinux.com> - *          Rickard E. (Rik) Faith <faith@valinux.com> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE.   * + * Authors: + *    Gareth Hughes <gareth@valinux.com>   */  #include <linux/config.h> +#include "radeon.h"  #include "drmP.h"  #include "radeon_drv.h" -#define RADEON_NAME		"radeon" -#define RADEON_DESC		"ATI Radeon" -#define RADEON_DATE		"20010105" -#define RADEON_MAJOR		1 -#define RADEON_MINOR		0 -#define RADEON_PATCHLEVEL	0 - -static drm_device_t	      radeon_device; -drm_ctx_t	              radeon_res_ctx; - -static struct file_operations radeon_fops = { -#if LINUX_VERSION_CODE >= 0x020400 -				/* This started being used during 2.4.0-test */ -	owner:   THIS_MODULE, -#endif -	open:	 radeon_open, -	flush:	 drm_flush, -	release: radeon_release, -	ioctl:	 radeon_ioctl, -	mmap:	 drm_mmap, -	read:	 drm_read, -	fasync:	 drm_fasync, -	poll:	 drm_poll, -}; - -static struct miscdevice      radeon_misc = { -	minor: MISC_DYNAMIC_MINOR, -	name:  RADEON_NAME, -	fops:  &radeon_fops, -}; - -static drm_ioctl_desc_t	      radeon_ioctls[] = { -	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]       = { radeon_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_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_BUFS)]      = { radeon_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)]      = { radeon_mapbufs,	1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]     = { drm_freebufs,	1, 0 }, - -	[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)]       = { radeon_addctx,	1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]        = { radeon_rmctx,	1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]       = { radeon_modctx,	1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]       = { radeon_getctx,	1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)]    = { radeon_switchctx,	1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]       = { radeon_newctx,	1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]       = { radeon_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_DMA)]	        = { radeon_cp_buffers,	1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_LOCK)]	        = { radeon_lock,	1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]        = { radeon_unlock,	1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]        = { drm_finish,		1, 0 }, - -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -	[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 - -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_INIT)]  = { radeon_cp_init,   1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_START)] = { radeon_cp_start,  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_STOP)]  = { radeon_cp_stop,   1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_RESET)] = { radeon_cp_reset,  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_IDLE)]  = { radeon_cp_idle,   1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_RESET)] = { radeon_engine_reset, 1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_FULLSCREEN)] = { radeon_fullscreen, 1, 0 }, - -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_SWAP)]    = { radeon_cp_swap,    1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_CLEAR)]   = { radeon_cp_clear,   1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_VERTEX)]  = { radeon_cp_vertex,  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDICES)] = { radeon_cp_indices, 1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_BLIT)]    = { radeon_cp_blit,    1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_STIPPLE)] = { radeon_cp_stipple, 1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDIRECT)]= { radeon_cp_indirect,1, 1 }, -}; -#define RADEON_IOCTL_COUNT DRM_ARRAY_SIZE(radeon_ioctls) - -#ifdef MODULE -static char		      *radeon = NULL; -#endif - -MODULE_AUTHOR("VA Linux Systems, Inc."); -MODULE_DESCRIPTION("radeon"); -MODULE_PARM(radeon, "s"); - -#ifndef MODULE -/* radeon_options is called by the kernel to parse command-line options - * passed via the boot-loader (e.g., LILO).  It calls the insmod option - * routine, drm_parse_drm. - */ - -static int __init radeon_options(char *str) -{ -	drm_parse_options(str); -	return 1; -} - -__setup("radeon=", radeon_options); -#endif - -static int radeon_setup(drm_device_t *dev) -{ -	int i; - -	atomic_set(&dev->ioctl_count, 0); -	atomic_set(&dev->vma_count, 0); -	dev->buf_use	  = 0; -	atomic_set(&dev->buf_alloc, 0); - -	drm_dma_setup(dev); - -	atomic_set(&dev->total_open, 0); -	atomic_set(&dev->total_close, 0); -	atomic_set(&dev->total_ioctl, 0); -	atomic_set(&dev->total_irq, 0); -	atomic_set(&dev->total_ctx, 0); -	atomic_set(&dev->total_locks, 0); -	atomic_set(&dev->total_unlocks, 0); -	atomic_set(&dev->total_contends, 0); -	atomic_set(&dev->total_sleeps, 0); - -	for (i = 0; i < DRM_HASH_SIZE; i++) { -		dev->magiclist[i].head = NULL; -		dev->magiclist[i].tail = NULL; -	} -	dev->maplist	    = NULL; -	dev->map_count	    = 0; -	dev->vmalist	    = NULL; -	dev->lock.hw_lock   = NULL; -	init_waitqueue_head(&dev->lock.lock_queue); -	dev->queue_count    = 0; -	dev->queue_reserved = 0; -	dev->queue_slots    = 0; -	dev->queuelist	    = NULL; -	dev->irq	    = 0; -	dev->context_flag   = 0; -	dev->interrupt_flag = 0; -	dev->dma_flag	    = 0; -	dev->last_context   = 0; -	dev->last_switch    = 0; -	dev->last_checked   = 0; -	init_timer(&dev->timer); -	init_waitqueue_head(&dev->context_wait); - -	dev->ctx_start	    = 0; -	dev->lck_start	    = 0; - -	dev->buf_rp	    = dev->buf; -	dev->buf_wp	    = dev->buf; -	dev->buf_end	    = dev->buf + DRM_BSZ; -	dev->buf_async	    = NULL; -	init_waitqueue_head(&dev->buf_readers); -	init_waitqueue_head(&dev->buf_writers); - -	radeon_res_ctx.handle = -1; - -	DRM_DEBUG("\n"); - -	/* The kernel's context could be created here, but is now created -	   in drm_dma_enqueue.	This is more resource-efficient for -	   hardware that does not do DMA, but may mean that -	   drm_select_queue fails between the time the interrupt is -	   initialized and the time the queues are initialized. */ +#define DRIVER_AUTHOR		"Gareth Hughes, VA Linux Systems Inc." + +#define DRIVER_NAME		"radeon" +#define DRIVER_DESC		"ATI Radeon" +#define DRIVER_DATE		"20010214" + +#define DRIVER_MAJOR		1 +#define DRIVER_MINOR		0 +#define DRIVER_PATCHLEVEL	0 + +#define DRIVER_IOCTLS							     \ + [DRM_IOCTL_NR(DRM_IOCTL_DMA)]               = { radeon_cp_buffers,  1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_INIT)]    = { radeon_cp_init,     1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_START)]   = { radeon_cp_start,    1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_STOP)]    = { radeon_cp_stop,     1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_RESET)]   = { radeon_cp_reset,    1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_IDLE)]    = { radeon_cp_idle,     1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_RESET)]    = { radeon_engine_reset,  1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FULLSCREEN)] = { radeon_fullscreen,  1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SWAP)]       = { radeon_cp_swap,     1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CLEAR)]      = { radeon_cp_clear,    1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_VERTEX)]     = { radeon_cp_vertex,   1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDICES)]    = { radeon_cp_indices,  1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_BLIT)]       = { radeon_cp_blit,     1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_STIPPLE)]    = { radeon_cp_stipple,  1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INDIRECT)]   = { radeon_cp_indirect, 1, 1 }, -	return 0; -} - - -static int radeon_takedown(drm_device_t *dev) -{ -	int		  i; -	drm_magic_entry_t *pt, *next; -	drm_map_t	  *map; -	drm_vma_entry_t	  *vma, *vma_next; - -	DRM_DEBUG("\n"); - -	down(&dev->struct_sem); -	del_timer(&dev->timer); - -	if (dev->devname) { -		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); -		dev->devname = NULL; -	} - -	if (dev->unique) { -		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); -		dev->unique = NULL; -		dev->unique_len = 0; -	} -				/* Clear pid list */ -	for (i = 0; i < DRM_HASH_SIZE; i++) { -		for (pt = dev->magiclist[i].head; pt; pt = next) { -			next = pt->next; -			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); -		} -		dev->magiclist[i].head = dev->magiclist[i].tail = NULL; -	} - -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -				/* Clear AGP information */ -	if (dev->agp) { -		drm_agp_mem_t *entry; -		drm_agp_mem_t *nexte; - -				/* Remove AGP resources, but leave dev->agp -                                   intact until radeon_cleanup is called. */ -		for (entry = dev->agp->memory; entry; entry = nexte) { -			nexte = entry->next; -			if (entry->bound) drm_unbind_agp(entry->memory); -			drm_free_agp(entry->memory, entry->pages); -			drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); -		} -		dev->agp->memory = NULL; - -		if (dev->agp->acquired)	_drm_agp_release(); - -		dev->agp->acquired = 0; -		dev->agp->enabled  = 0; -	} -#endif - -				/* Clear vma list (only built for debugging) */ -	if (dev->vmalist) { -		for (vma = dev->vmalist; vma; vma = vma_next) { -			vma_next = vma->next; -			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); -		} -		dev->vmalist = NULL; -	} - -				/* Clear map area and mtrr information */ -	if (dev->maplist) { -		for (i = 0; i < dev->map_count; i++) { -			map = dev->maplist[i]; -			switch (map->type) { -			case _DRM_REGISTERS: -			case _DRM_FRAME_BUFFER: -#ifdef CONFIG_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: -				drm_free_pages((unsigned long)map->handle, -					       drm_order(map->size) -					       - PAGE_SHIFT, -					       DRM_MEM_SAREA); -				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); -		dev->maplist   = NULL; -		dev->map_count = 0; -	} - -	drm_dma_takedown(dev); - -	dev->queue_count     = 0; -	if (dev->lock.hw_lock) { -		dev->lock.hw_lock    = NULL; /* SHM removed */ -		dev->lock.pid	     = 0; -		wake_up_interruptible(&dev->lock.lock_queue); -	} -	up(&dev->struct_sem); - -	return 0; -} - -/* radeon_init is called via init_module at module load time, or via - * linux/init/main.c (this is not currently supported). */ - -static int __init radeon_init(void) -{ -	int		      retcode; -	drm_device_t	      *dev = &radeon_device; - -	DRM_DEBUG("\n"); - -	memset((void *)dev, 0, sizeof(*dev)); -	dev->count_lock	  = SPIN_LOCK_UNLOCKED; -	sema_init(&dev->struct_sem, 1); - -#ifdef MODULE -	drm_parse_options(radeon); -#endif - -	if ((retcode = misc_register(&radeon_misc))) { -		DRM_ERROR("Cannot register \"%s\"\n", RADEON_NAME); -		return retcode; -	} -	dev->device = MKDEV(MISC_MAJOR, radeon_misc.minor); -	dev->name   = RADEON_NAME; - -	drm_mem_init(); -	drm_proc_init(dev); - -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -	dev->agp    = drm_agp_init(); -      	if (dev->agp == NULL) { -	   	DRM_ERROR("Cannot initialize agpgart module.\n"); -	   	drm_proc_cleanup(); -	   	misc_deregister(&radeon_misc); -	   	radeon_takedown(dev); -	   	return -ENOMEM; -	} - -#ifdef CONFIG_MTRR -	dev->agp->agp_mtrr = mtrr_add(dev->agp->agp_info.aper_base, -				      dev->agp->agp_info.aper_size*1024*1024, -				      MTRR_TYPE_WRCOMB, -				      1); -#endif -#endif - -	if((retcode = drm_ctxbitmap_init(dev))) { -		DRM_ERROR("Cannot allocate memory for context bitmap.\n"); -		drm_proc_cleanup(); -		misc_deregister(&radeon_misc); -		radeon_takedown(dev); -		return retcode; -	} - -	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", -		 RADEON_NAME, -		 RADEON_MAJOR, -		 RADEON_MINOR, -		 RADEON_PATCHLEVEL, -		 RADEON_DATE, -		 radeon_misc.minor); - -	return 0; -} - -/* radeon_cleanup is called via cleanup_module at module unload time. */ - -static void __exit radeon_cleanup(void) -{ -	drm_device_t	      *dev = &radeon_device; - -	DRM_DEBUG("\n"); - -	drm_proc_cleanup(); -	if (misc_deregister(&radeon_misc)) { -		DRM_ERROR("Cannot unload module\n"); -	} else { -		DRM_INFO("Module unloaded\n"); -	} -	drm_ctxbitmap_cleanup(dev); -	radeon_takedown(dev); -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -	if (dev->agp) { -		drm_agp_uninit(); -		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); -		dev->agp = NULL; -	} -#endif -} - -module_init(radeon_init); -module_exit(radeon_cleanup); - - -int radeon_version(struct inode *inode, struct file *filp, unsigned int cmd, -		   unsigned long arg) -{ -	drm_version_t version; -	int	      len; - -	if (copy_from_user(&version, -			   (drm_version_t *)arg, -			   sizeof(version))) -		return -EFAULT; - -#define DRM_COPY(name,value)				     \ -	len = strlen(value);				     \ -	if (len > name##_len) len = name##_len;		     \ -	name##_len = strlen(value);			     \ -	if (len && name) {				     \ -		if (copy_to_user(name, value, len))	     \ -			return -EFAULT;			     \ -	} - -	version.version_major	   = RADEON_MAJOR; -	version.version_minor	   = RADEON_MINOR; -	version.version_patchlevel = RADEON_PATCHLEVEL; - -	DRM_COPY(version.name, RADEON_NAME); -	DRM_COPY(version.date, RADEON_DATE); -	DRM_COPY(version.desc, RADEON_DESC); - -	if (copy_to_user((drm_version_t *)arg, -			 &version, -			 sizeof(version))) -		return -EFAULT; -	return 0; -} - -int radeon_open(struct inode *inode, struct file *filp) -{ -	drm_device_t  *dev    = &radeon_device; -	int	      retcode = 0; - -	DRM_DEBUG("open_count = %d\n", dev->open_count); -	if (!(retcode = drm_open_helper(inode, filp, dev))) { -#if LINUX_VERSION_CODE < 0x020333 -		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif -		atomic_inc(&dev->total_open); -		spin_lock(&dev->count_lock); -		if (!dev->open_count++) { -			spin_unlock(&dev->count_lock); -			return radeon_setup(dev); -		} -		spin_unlock(&dev->count_lock); -	} - -	return retcode; -} - -int radeon_release(struct inode *inode, struct file *filp) -{ -	drm_file_t    *priv   = filp->private_data; -	drm_device_t  *dev; -	int	      retcode = 0; - -	lock_kernel(); -	dev = priv->dev; - -	DRM_DEBUG("open_count = %d\n", dev->open_count); - -	/* Force the cleanup of page flipping when required */ -	if ( dev->dev_private ) { -		drm_radeon_private_t *dev_priv = dev->dev_private; -		if ( dev_priv->page_flipping ) { -			radeon_do_cleanup_pageflip( dev ); -		} -	} - -	if (!(retcode = drm_release(inode, filp))) { -#if LINUX_VERSION_CODE < 0x020333 -		MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif -		atomic_inc(&dev->total_close); -		spin_lock(&dev->count_lock); -		if (!--dev->open_count) { -			if (atomic_read(&dev->ioctl_count) || dev->blocked) { -				DRM_ERROR("Device busy: %d %d\n", -					  atomic_read(&dev->ioctl_count), -					  dev->blocked); -				spin_unlock(&dev->count_lock); -				unlock_kernel(); -				return -EBUSY; -			} -			spin_unlock(&dev->count_lock); -			unlock_kernel(); -			return radeon_takedown(dev); -		} -		spin_unlock(&dev->count_lock); -	} - -	unlock_kernel(); -	return retcode; -} - -/* radeon_ioctl is called whenever a process performs an ioctl on /dev/drm. */ - -int radeon_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, -		 unsigned long arg) -{ -	int		 nr	 = DRM_IOCTL_NR(cmd); -	drm_file_t	 *priv	 = filp->private_data; -	drm_device_t	 *dev	 = priv->dev; -	int		 retcode = 0; -	drm_ioctl_desc_t *ioctl; -	drm_ioctl_t	 *func; - -	atomic_inc(&dev->ioctl_count); -	atomic_inc(&dev->total_ioctl); -	++priv->ioctl_count; - -	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", -		  current->pid, cmd, nr, dev->device, priv->authenticated); - -	if (nr >= RADEON_IOCTL_COUNT) { -		retcode = -EINVAL; -	} else { -		ioctl	  = &radeon_ioctls[nr]; -		func	  = ioctl->func; - -		if (!func) { -			DRM_DEBUG("no function\n"); -			retcode = -EINVAL; -		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) -			    || (ioctl->auth_needed && !priv->authenticated)) { -			retcode = -EACCES; -		} else { -			retcode = (func)(inode, filp, cmd, arg); -		} -	} - -	atomic_dec(&dev->ioctl_count); -	return retcode; -} - -int radeon_lock(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; -        DECLARE_WAITQUEUE(entry, current); -        int               ret   = 0; -        drm_lock_t        lock; -#if DRM_DMA_HISTOGRAM -        cycles_t          start; - -        dev->lck_start = start = get_cycles(); -#endif - -        if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) -		return -EFAULT; - -        if (lock.context == DRM_KERNEL_CONTEXT) { -                DRM_ERROR("Process %d using kernel context %d\n", -                          current->pid, lock.context); -                return -EINVAL; -        } - -        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", -                  lock.context, current->pid, dev->lock.hw_lock->lock, -                  lock.flags); - -        if (lock.context < 0 /* || lock.context >= dev->queue_count */) -                return -EINVAL; - -        if (!ret) { -                add_wait_queue(&dev->lock.lock_queue, &entry); -                for (;;) { -                        current->state = TASK_INTERRUPTIBLE; -                        if (!dev->lock.hw_lock) { -                                /* Device has been unregistered */ -                                ret = -EINTR; -                                break; -                        } -                        if (drm_lock_take(&dev->lock.hw_lock->lock, -                                          lock.context)) { -                                dev->lock.pid       = current->pid; -                                dev->lock.lock_time = jiffies; -                                atomic_inc(&dev->total_locks); -                                break;  /* Got lock */ -                        } - -                                /* Contention */ -                        atomic_inc(&dev->total_sleeps); -                        schedule(); -                        if (signal_pending(current)) { -                                ret = -ERESTARTSYS; -                                break; -                        } -                } -                current->state = TASK_RUNNING; -                remove_wait_queue(&dev->lock.lock_queue, &entry); -        } - -        if (!ret) { -		sigemptyset(&dev->sigmask); -		sigaddset(&dev->sigmask, SIGSTOP); -		sigaddset(&dev->sigmask, SIGTSTP); -		sigaddset(&dev->sigmask, SIGTTIN); -		sigaddset(&dev->sigmask, SIGTTOU); -		dev->sigdata.context = lock.context; -		dev->sigdata.lock    = dev->lock.hw_lock; -		block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); -                if (lock.flags & _DRM_LOCK_READY) { -				/* Wait for space in DMA/FIFO */ -		} -                if (lock.flags & _DRM_LOCK_QUIESCENT) { -				/* Make hardware quiescent */ -			DRM_DEBUG("not quiescent!\n");  #if 0 -                        radeon_quiescent(dev); -#endif -		} -        } - -#if LINUX_VERSION_CODE < 0x020400 -	if (lock.context != radeon_res_ctx.handle) { -		current->counter = 5; -		current->priority = DEF_PRIORITY/4; -	} -#endif -        DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); - -#if DRM_DMA_HISTOGRAM -        atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); -#endif - -        return ret; -} - - -int radeon_unlock(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_lock_t	  lock; - -	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) -		return -EFAULT; - -	if (lock.context == DRM_KERNEL_CONTEXT) { -		DRM_ERROR("Process %d using kernel context %d\n", -			  current->pid, lock.context); -		return -EINVAL; -	} - -	DRM_DEBUG("%d frees lock (%d holds)\n", -		  lock.context, -		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); -	atomic_inc(&dev->total_unlocks); -	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) -		atomic_inc(&dev->total_contends); -	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); -				/* FIXME: Try to send data to card here */ -	if (!dev->context_flag) { -		if (drm_lock_free(dev, &dev->lock.hw_lock->lock, -				  DRM_KERNEL_CONTEXT)) { -			DRM_ERROR("\n"); -		} -	} - -#if LINUX_VERSION_CODE < 0x020400 -	if (lock.context != radeon_res_ctx.handle) { -		current->counter = 5; -		current->priority = DEF_PRIORITY; -	} -#endif -	unblock_all_signals(); -	return 0; -} +/* GH: Count data sent to card via ring or vertex/indirect buffers. + */ +#define __HAVE_COUNTERS         3 +#define __HAVE_COUNTER6         _DRM_STAT_IRQ +#define __HAVE_COUNTER7         _DRM_STAT_PRIMARY +#define __HAVE_COUNTER8         _DRM_STAT_SECONDARY +#endif + +#define __HAVE_DMA_QUIESCENT	1 +#define DRIVER_DMA_QUIESCENT() do {					\ +	drm_radeon_private_t *dev_priv = dev->dev_private;		\ +	return radeon_do_cp_idle( dev_priv );				\ +} while (0) + +#define DRIVER_PRERELEASE() do {					\ +	if ( dev->dev_private ) {					\ +		drm_radeon_private_t *dev_priv = dev->dev_private;	\ +		if ( dev_priv->page_flipping ) {			\ +			radeon_do_cleanup_pageflip( dev );		\ +		}							\ +	}								\ +} while (0) + +#define DRIVER_PRETAKEDOWN() do {					\ +	if ( dev->dev_private ) radeon_do_cleanup_cp( dev );		\ +} while (0) + +#include "drm_drv.h" + + +#define DRIVER_BUF_PRIV_T	drm_radeon_buf_priv_t + +#define DRIVER_AGP_BUFFERS_MAP( dev )					\ +	((drm_radeon_private_t *)((dev)->dev_private))->buffers + +#include "drm_bufs.h" + + +#include "drm_agpsupport.h" +#include "drm_auth.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_drawable.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" diff --git a/linux-core/tdfx_drv.c b/linux-core/tdfx_drv.c index b98a2988..9bb7b84a 100644 --- a/linux-core/tdfx_drv.c +++ b/linux-core/tdfx_drv.c @@ -27,670 +27,37 @@   * Authors:   *    Rickard E. (Rik) Faith <faith@valinux.com>   *    Daryll Strauss <daryll@valinux.com> - * + *    Gareth Hughes <gareth@valinux.com>   */  #include <linux/config.h> +#include "tdfx.h"  #include "drmP.h" -#include "tdfx_drv.h" - -#define TDFX_NAME	 "tdfx" -#define TDFX_DESC	 "3dfx Banshee/Voodoo3+" -#define TDFX_DATE	 "20001030" -#define TDFX_MAJOR	 1 -#define TDFX_MINOR	 0 -#define TDFX_PATCHLEVEL  0 - -static drm_device_t	      tdfx_device; -drm_ctx_t	              tdfx_res_ctx; - -static struct file_operations tdfx_fops = { -#if LINUX_VERSION_CODE >= 0x020400 -				/* This started being used during 2.4.0-test */ -	owner:   THIS_MODULE, -#endif -	open:	 tdfx_open, -	flush:	 drm_flush, -	release: tdfx_release, -	ioctl:	 tdfx_ioctl, -	mmap:	 drm_mmap, -	read:	 drm_read, -	fasync:	 drm_fasync, -	poll:	 drm_poll, -}; - -static struct miscdevice      tdfx_misc = { -	minor: MISC_DYNAMIC_MINOR, -	name:  TDFX_NAME, -	fops:  &tdfx_fops, -}; - -static drm_ioctl_desc_t	      tdfx_ioctls[] = { -	[DRM_IOCTL_NR(DRM_IOCTL_VERSION)]    = { tdfx_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_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)]    = { tdfx_addctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)]     = { tdfx_rmctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)]    = { tdfx_modctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)]    = { tdfx_getctx,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { tdfx_switchctx,  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)]    = { tdfx_newctx,	  1, 1 }, -	[DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)]    = { tdfx_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)]	     = { tdfx_lock,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)]     = { tdfx_unlock,	  1, 0 }, -	[DRM_IOCTL_NR(DRM_IOCTL_FINISH)]     = { drm_finish,	  1, 0 }, -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -	[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, 1}, -	[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_unbind,  1, 1}, -	[DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)]    = {drm_agp_bind,    1, 1}, -#endif -}; -#define TDFX_IOCTL_COUNT DRM_ARRAY_SIZE(tdfx_ioctls) - -#ifdef MODULE -static char		      *tdfx = NULL; -#endif - -MODULE_AUTHOR("VA Linux Systems, Inc."); -MODULE_DESCRIPTION("tdfx"); -MODULE_PARM(tdfx, "s"); - -#ifndef MODULE -/* tdfx_options is called by the kernel to parse command-line options - * passed via the boot-loader (e.g., LILO).  It calls the insmod option - * routine, drm_parse_drm. - */ - -static int __init tdfx_options(char *str) -{ -	drm_parse_options(str); -	return 1; -} - -__setup("tdfx=", tdfx_options); -#endif - -static int tdfx_setup(drm_device_t *dev) -{ -	int i; - -	atomic_set(&dev->ioctl_count, 0); -	atomic_set(&dev->vma_count, 0); -	dev->buf_use	  = 0; -	atomic_set(&dev->buf_alloc, 0); - -	atomic_set(&dev->total_open, 0); -	atomic_set(&dev->total_close, 0); -	atomic_set(&dev->total_ioctl, 0); -	atomic_set(&dev->total_irq, 0); -	atomic_set(&dev->total_ctx, 0); -	atomic_set(&dev->total_locks, 0); -	atomic_set(&dev->total_unlocks, 0); -	atomic_set(&dev->total_contends, 0); -	atomic_set(&dev->total_sleeps, 0); - -	for (i = 0; i < DRM_HASH_SIZE; i++) { -		dev->magiclist[i].head = NULL; -		dev->magiclist[i].tail = NULL; -	} -	dev->maplist	    = NULL; -	dev->map_count	    = 0; -	dev->vmalist	    = NULL; -	dev->lock.hw_lock   = NULL; -	init_waitqueue_head(&dev->lock.lock_queue); -	dev->queue_count    = 0; -	dev->queue_reserved = 0; -	dev->queue_slots    = 0; -	dev->queuelist	    = NULL; -	dev->irq	    = 0; -	dev->context_flag   = 0; -	dev->interrupt_flag = 0; -	dev->dma            = 0; -	dev->dma_flag	    = 0; -	dev->last_context   = 0; -	dev->last_switch    = 0; -	dev->last_checked   = 0; -	init_timer(&dev->timer); -	init_waitqueue_head(&dev->context_wait); - -	dev->ctx_start	    = 0; -	dev->lck_start	    = 0; - -	dev->buf_rp	  = dev->buf; -	dev->buf_wp	  = dev->buf; -	dev->buf_end	  = dev->buf + DRM_BSZ; -	dev->buf_async	  = NULL; -	init_waitqueue_head(&dev->buf_readers); -	init_waitqueue_head(&dev->buf_writers); - -	tdfx_res_ctx.handle=-1; - -	DRM_DEBUG("\n"); - -	/* The kernel's context could be created here, but is now created -	   in drm_dma_enqueue.	This is more resource-efficient for -	   hardware that does not do DMA, but may mean that -	   drm_select_queue fails between the time the interrupt is -	   initialized and the time the queues are initialized. */ - -	return 0; -} - - -static int tdfx_takedown(drm_device_t *dev) -{ -	int		  i; -	drm_magic_entry_t *pt, *next; -	drm_map_t	  *map; -	drm_vma_entry_t	  *vma, *vma_next; - -	DRM_DEBUG("\n"); - -	down(&dev->struct_sem); -	del_timer(&dev->timer); - -	if (dev->devname) { -		drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); -		dev->devname = NULL; -	} - -	if (dev->unique) { -		drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); -		dev->unique = NULL; -		dev->unique_len = 0; -	} -				/* Clear pid list */ -	for (i = 0; i < DRM_HASH_SIZE; i++) { -		for (pt = dev->magiclist[i].head; pt; pt = next) { -			next = pt->next; -			drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); -		} -		dev->magiclist[i].head = dev->magiclist[i].tail = NULL; -	} -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -				/* Clear AGP information */ -	if (dev->agp) { -		drm_agp_mem_t *temp; -		drm_agp_mem_t *temp_next; - -		temp = dev->agp->memory; -		while(temp != NULL) { -			temp_next = temp->next; -			drm_free_agp(temp->memory, temp->pages); -			drm_free(temp, sizeof(*temp), DRM_MEM_AGPLISTS); -			temp = temp_next; -		} -		if (dev->agp->acquired) _drm_agp_release(); -	} -#endif -				/* Clear vma list (only built for debugging) */ -	if (dev->vmalist) { -		for (vma = dev->vmalist; vma; vma = vma_next) { -			vma_next = vma->next; -			drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); -		} -		dev->vmalist = NULL; -	} - -				/* Clear map area and mtrr information */ -	if (dev->maplist) { -		for (i = 0; i < dev->map_count; i++) { -			map = dev->maplist[i]; -			switch (map->type) { -			case _DRM_REGISTERS: -			case _DRM_FRAME_BUFFER: -#ifdef CONFIG_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: -				drm_free_pages((unsigned long)map->handle, -					       drm_order(map->size) -					       - PAGE_SHIFT, -					       DRM_MEM_SAREA); -				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); -		dev->maplist   = NULL; -		dev->map_count = 0; -	} - -	if (dev->lock.hw_lock) { -		dev->lock.hw_lock    = NULL; /* SHM removed */ -		dev->lock.pid	     = 0; -		wake_up_interruptible(&dev->lock.lock_queue); -	} -	up(&dev->struct_sem); - -	return 0; -} - -/* tdfx_init is called via init_module at module load time, or via - * linux/init/main.c (this is not currently supported). */ - -static int __init tdfx_init(void) -{ -	int		      retcode; -	drm_device_t	      *dev = &tdfx_device; - -	DRM_DEBUG("\n"); - -	memset((void *)dev, 0, sizeof(*dev)); -	dev->count_lock	  = SPIN_LOCK_UNLOCKED; -	sema_init(&dev->struct_sem, 1); - -#ifdef MODULE -	drm_parse_options(tdfx); -#endif - -	if ((retcode = misc_register(&tdfx_misc))) { -		DRM_ERROR("Cannot register \"%s\"\n", TDFX_NAME); -		return retcode; -	} -	dev->device = MKDEV(MISC_MAJOR, tdfx_misc.minor); -	dev->name   = TDFX_NAME; - -	drm_mem_init(); -	drm_proc_init(dev); -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -	dev->agp    = drm_agp_init(); -#endif -	if((retcode = drm_ctxbitmap_init(dev))) { -		DRM_ERROR("Cannot allocate memory for context bitmap.\n"); -		drm_proc_cleanup(); -		misc_deregister(&tdfx_misc); -		tdfx_takedown(dev); -		return retcode; -	} - -	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", -		 TDFX_NAME, -		 TDFX_MAJOR, -		 TDFX_MINOR, -		 TDFX_PATCHLEVEL, -		 TDFX_DATE, -		 tdfx_misc.minor); - -	return 0; -} - -/* tdfx_cleanup is called via cleanup_module at module unload time. */ - -static void __exit tdfx_cleanup(void) -{ -	drm_device_t	      *dev = &tdfx_device; - -	DRM_DEBUG("\n"); - -	drm_proc_cleanup(); -	if (misc_deregister(&tdfx_misc)) { -		DRM_ERROR("Cannot unload module\n"); -	} else { -		DRM_INFO("Module unloaded\n"); -	} -	drm_ctxbitmap_cleanup(dev); -	tdfx_takedown(dev); -#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) -	if (dev->agp) { -		drm_agp_uninit(); -		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); -		dev->agp = NULL; -	} -#endif -} - -module_init(tdfx_init); -module_exit(tdfx_cleanup); - - -int tdfx_version(struct inode *inode, struct file *filp, unsigned int cmd, -		  unsigned long arg) -{ -	drm_version_t version; -	int	      len; - -	if (copy_from_user(&version, -			   (drm_version_t *)arg, -			   sizeof(version))) -		return -EFAULT; - -#define DRM_COPY(name,value)				     \ -	len = strlen(value);				     \ -	if (len > name##_len) len = name##_len;		     \ -	name##_len = strlen(value);			     \ -	if (len && name) {				     \ -		if (copy_to_user(name, value, len))	     \ -			return -EFAULT;			     \ -	} - -	version.version_major	   = TDFX_MAJOR; -	version.version_minor	   = TDFX_MINOR; -	version.version_patchlevel = TDFX_PATCHLEVEL; - -	DRM_COPY(version.name, TDFX_NAME); -	DRM_COPY(version.date, TDFX_DATE); -	DRM_COPY(version.desc, TDFX_DESC); - -	if (copy_to_user((drm_version_t *)arg, -			 &version, -			 sizeof(version))) -		return -EFAULT; -	return 0; -} - -int tdfx_open(struct inode *inode, struct file *filp) -{ -	drm_device_t  *dev    = &tdfx_device; -	int	      retcode = 0; - -	DRM_DEBUG("open_count = %d\n", dev->open_count); -	if (!(retcode = drm_open_helper(inode, filp, dev))) { -#if LINUX_VERSION_CODE < 0x020333 -		MOD_INC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif -		atomic_inc(&dev->total_open); -		spin_lock(&dev->count_lock); -		if (!dev->open_count++) { -			spin_unlock(&dev->count_lock); -			return tdfx_setup(dev); -		} -		spin_unlock(&dev->count_lock); -	} -	return retcode; -} - -int tdfx_release(struct inode *inode, struct file *filp) -{ -	drm_file_t    *priv   = filp->private_data; -	drm_device_t  *dev; -	int	      retcode = 0; - -	lock_kernel(); -	dev = priv->dev; - -	DRM_DEBUG("open_count = %d\n", dev->open_count); -	if (!(retcode = drm_release(inode, filp))) { -#if LINUX_VERSION_CODE < 0x020333 -		MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ -#endif -		atomic_inc(&dev->total_close); -		spin_lock(&dev->count_lock); -		if (!--dev->open_count) { -			if (atomic_read(&dev->ioctl_count) || dev->blocked) { -				DRM_ERROR("Device busy: %d %d\n", -					  atomic_read(&dev->ioctl_count), -					  dev->blocked); -				spin_unlock(&dev->count_lock); -				unlock_kernel(); -				return -EBUSY; -			} -			spin_unlock(&dev->count_lock); -			unlock_kernel(); -			return tdfx_takedown(dev); -		} -		spin_unlock(&dev->count_lock); -	} - -	unlock_kernel(); -	return retcode; -} - -/* tdfx_ioctl is called whenever a process performs an ioctl on /dev/drm. */ - -int tdfx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, -		unsigned long arg) -{ -	int		 nr	 = DRM_IOCTL_NR(cmd); -	drm_file_t	 *priv	 = filp->private_data; -	drm_device_t	 *dev	 = priv->dev; -	int		 retcode = 0; -	drm_ioctl_desc_t *ioctl; -	drm_ioctl_t	 *func; - -	atomic_inc(&dev->ioctl_count); -	atomic_inc(&dev->total_ioctl); -	++priv->ioctl_count; - -	DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", -		  current->pid, cmd, nr, dev->device, priv->authenticated); - -	if (nr >= TDFX_IOCTL_COUNT) { -		retcode = -EINVAL; -	} else { -		ioctl	  = &tdfx_ioctls[nr]; -		func	  = ioctl->func; - -		if (!func) { -			DRM_DEBUG("no function\n"); -			retcode = -EINVAL; -		} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) -			    || (ioctl->auth_needed && !priv->authenticated)) { -			retcode = -EACCES; -		} else { -			retcode = (func)(inode, filp, cmd, arg); -		} -	} - -	atomic_dec(&dev->ioctl_count); -	return retcode; -} - -int tdfx_lock(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; -        DECLARE_WAITQUEUE(entry, current); -        int               ret   = 0; -        drm_lock_t        lock; -#if DRM_DMA_HISTOGRAM -        cycles_t          start; - -        dev->lck_start = start = get_cycles(); -#endif - -        if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) -		return -EFAULT; - -        if (lock.context == DRM_KERNEL_CONTEXT) { -                DRM_ERROR("Process %d using kernel context %d\n", -                          current->pid, lock.context); -                return -EINVAL; -        } - -        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", -                  lock.context, current->pid, dev->lock.hw_lock->lock, -                  lock.flags); - -#if 0 -				/* dev->queue_count == 0 right now for -                                   tdfx.  FIXME? */ -        if (lock.context < 0 || lock.context >= dev->queue_count) -                return -EINVAL; -#endif - -        if (!ret) { -#if 0 -                if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) -                    != lock.context) { -                        long j = jiffies - dev->lock.lock_time; - -                        if (lock.context == tdfx_res_ctx.handle && -				j >= 0 && j < DRM_LOCK_SLICE) { -                                /* Can't take lock if we just had it and -                                   there is contention. */ -                                DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n", -					lock.context, current->pid, j, -					dev->lock.lock_time, jiffies); -                                current->state = TASK_INTERRUPTIBLE; -				current->policy |= SCHED_YIELD; -                                schedule_timeout(DRM_LOCK_SLICE-j); -				DRM_DEBUG("jiffies=%d\n", jiffies); -                        } -                } -#endif -                add_wait_queue(&dev->lock.lock_queue, &entry); -                for (;;) { -                        current->state = TASK_INTERRUPTIBLE; -                        if (!dev->lock.hw_lock) { -                                /* Device has been unregistered */ -                                ret = -EINTR; -                                break; -                        } -                        if (drm_lock_take(&dev->lock.hw_lock->lock, -                                          lock.context)) { -                                dev->lock.pid       = current->pid; -                                dev->lock.lock_time = jiffies; -                                atomic_inc(&dev->total_locks); -                                break;  /* Got lock */ -                        } - -                                /* Contention */ -                        atomic_inc(&dev->total_sleeps); -#if 1 -			current->policy |= SCHED_YIELD; -#endif -                        schedule(); -                        if (signal_pending(current)) { -                                ret = -ERESTARTSYS; -                                break; -                        } -                } -                current->state = TASK_RUNNING; -                remove_wait_queue(&dev->lock.lock_queue, &entry); -        } - -#if 0 -	if (!ret && dev->last_context != lock.context && -		lock.context != tdfx_res_ctx.handle && -		dev->last_context != tdfx_res_ctx.handle) { -		add_wait_queue(&dev->context_wait, &entry); -	        current->state = TASK_INTERRUPTIBLE; -                /* PRE: dev->last_context != lock.context */ -	        tdfx_context_switch(dev, dev->last_context, lock.context); -		/* POST: we will wait for the context -                   switch and will dispatch on a later call -                   when dev->last_context == lock.context -                   NOTE WE HOLD THE LOCK THROUGHOUT THIS -                   TIME! */ -		current->policy |= SCHED_YIELD; -	        schedule(); -	        current->state = TASK_RUNNING; -	        remove_wait_queue(&dev->context_wait, &entry); -	        if (signal_pending(current)) { -	                ret = -EINTR; -	        } else if (dev->last_context != lock.context) { -			DRM_ERROR("Context mismatch: %d %d\n", -                        	dev->last_context, lock.context); -	        } -	} -#endif - -        if (!ret) { -		sigemptyset(&dev->sigmask); -		sigaddset(&dev->sigmask, SIGSTOP); -		sigaddset(&dev->sigmask, SIGTSTP); -		sigaddset(&dev->sigmask, SIGTTIN); -		sigaddset(&dev->sigmask, SIGTTOU); -		dev->sigdata.context = lock.context; -		dev->sigdata.lock    = dev->lock.hw_lock; -		block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); - -                if (lock.flags & _DRM_LOCK_READY) { -				/* Wait for space in DMA/FIFO */ -		} -                if (lock.flags & _DRM_LOCK_QUIESCENT) { -				/* Make hardware quiescent */ -#if 0 -                        tdfx_quiescent(dev); -#endif -		} -        } - -#if LINUX_VERSION_CODE < 0x020400 -	if (lock.context != tdfx_res_ctx.handle) { -		current->counter = 5; -		current->priority = DEF_PRIORITY/4; -	} -#endif -        DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); - -#if DRM_DMA_HISTOGRAM -        atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); -#endif - -        return ret; -} - - -int tdfx_unlock(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_lock_t	  lock; - -	if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) -		return -EFAULT; - -	if (lock.context == DRM_KERNEL_CONTEXT) { -		DRM_ERROR("Process %d using kernel context %d\n", -			  current->pid, lock.context); -		return -EINVAL; -	} - -	DRM_DEBUG("%d frees lock (%d holds)\n", -		  lock.context, -		  _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); -	atomic_inc(&dev->total_unlocks); -	if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) -		atomic_inc(&dev->total_contends); -	drm_lock_transfer(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); -				/* FIXME: Try to send data to card here */ -	if (!dev->context_flag) { -		if (drm_lock_free(dev, &dev->lock.hw_lock->lock, -				  DRM_KERNEL_CONTEXT)) { -			DRM_ERROR("\n"); -		} -	} - -#if LINUX_VERSION_CODE < 0x020400 -	if (lock.context != tdfx_res_ctx.handle) { -		current->counter = 5; -		current->priority = DEF_PRIORITY; -	} -#endif -	unblock_all_signals(); -	return 0; -} +#define DRIVER_AUTHOR		"VA Linux Systems Inc." + +#define DRIVER_NAME		"tdfx" +#define DRIVER_DESC		"3dfx Banshee/Voodoo3+" +#define DRIVER_DATE		"20010214" + +#define DRIVER_MAJOR		1 +#define DRIVER_MINOR		0 +#define DRIVER_PATCHLEVEL	0 + +#include "drm_drv.h" + + +#include "drm_agpsupport.h" +#include "drm_auth.h" +#include "drm_bufs.h" +#include "drm_context.h" +#include "drm_dma.h" +#include "drm_drawable.h" +#include "drm_fops.h" +#include "drm_init.h" +#include "drm_ioctl.h" +#include "drm_lock.h" +#include "drm_memory.h" +#include "drm_proc.h" +#include "drm_vm.h" +#include "drm_stub.h" | 
