diff options
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" |