diff options
Diffstat (limited to 'linux-core')
| -rw-r--r-- | linux-core/Makefile.kernel | 18 | ||||
| -rw-r--r-- | linux-core/drmP.h | 127 | ||||
| -rw-r--r-- | linux-core/i810_dma.c | 1228 | ||||
| -rw-r--r-- | linux-core/i810_drm.h | 93 | ||||
| -rw-r--r-- | linux-core/i810_drv.c | 141 | ||||
| -rw-r--r-- | linux-core/i810_drv.h | 132 | ||||
| -rw-r--r-- | linux-core/mga_drv.c | 34 | ||||
| -rw-r--r-- | linux-core/tdfx_drv.c | 44 | 
8 files changed, 1255 insertions, 562 deletions
| diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 44d75c48..2ea6c721 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -14,7 +14,8 @@  L_TARGET        := libdrm.a  L_OBJS		:= init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ -			lists.o lock.o ioctl.o fops.o vm.o dma.o +			lists.o lock.o ioctl.o fops.o vm.o dma.o ctxbitmap.o \ +			agpsupport.o  M_OBJS		:=  @@ -26,6 +27,14 @@ ifdef CONFIG_DRM_TDFX  M_OBJS          += tdfx.o  endif +ifdef CONFIG_DRM_MGA +M_OBJS		+= mga.o +endif + +ifdef CONFIG_DRM_R128 +M_OBJS		+= r128.o +endif +  include $(TOPDIR)/Rules.make  gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) @@ -33,3 +42,10 @@ gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET)  tdfx.o: tdfx_drv.o tdfx_context.o $(L_TARGET)  	$(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o -L. -ldrm + +i810.o: i810_drv.o i810_context.o $(L_TARGET) +	$(LD) $(LD_RFLAG) -r -o $@ i810_drv.o i810_bufs.o i810_dma.o i810_context.o -L. -ldrm + +mga.o: mga_drv.o mga_context.o mga_dma.o mga_bufs.o $(L_TARGET) +	$(LD) $(LD_RFLAG) -r -o $@ mga_drv.o mga_bufs.o mga_dma.o mga_context.o mga_state.o -L. -ldrm + diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 312fba36..f8e78eab 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -48,8 +48,12 @@  #ifdef CONFIG_MTRR  #include <asm/mtrr.h>  #endif +#ifdef DRM_AGP +#include <linux/types.h> +#include <linux/agp_backend.h> +#endif  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include <asm/spinlock.h> +#include <linux/tqueue.h>  #include <linux/poll.h>  #endif  #include "drm.h" @@ -69,21 +73,27 @@  #define DRM_FLAG_DEBUG	  0x01  #define DRM_FLAG_NOCTX	  0x02 -#define DRM_MEM_DMA	  0 -#define DRM_MEM_SAREA	  1 -#define DRM_MEM_DRIVER	  2 -#define DRM_MEM_MAGIC	  3 -#define DRM_MEM_IOCTLS	  4 -#define DRM_MEM_MAPS	  5 -#define DRM_MEM_VMAS	  6 -#define DRM_MEM_BUFS	  7 -#define DRM_MEM_SEGS	  8 -#define DRM_MEM_PAGES	  9 -#define DRM_MEM_FILES	 10 -#define DRM_MEM_QUEUES	 11 -#define DRM_MEM_CMDS	 12 -#define DRM_MEM_MAPPINGS 13 -#define DRM_MEM_BUFLISTS 14 +#define DRM_MEM_DMA	   0 +#define DRM_MEM_SAREA	   1 +#define DRM_MEM_DRIVER	   2 +#define DRM_MEM_MAGIC	   3 +#define DRM_MEM_IOCTLS	   4 +#define DRM_MEM_MAPS	   5 +#define DRM_MEM_VMAS	   6 +#define DRM_MEM_BUFS	   7 +#define DRM_MEM_SEGS	   8 +#define DRM_MEM_PAGES	   9 +#define DRM_MEM_FILES	  10 +#define DRM_MEM_QUEUES	  11 +#define DRM_MEM_CMDS	  12 +#define DRM_MEM_MAPPINGS  13 +#define DRM_MEM_BUFLISTS  14 +#define DRM_MEM_AGPLISTS  15 +#define DRM_MEM_TOTALAGP  16 +#define DRM_MEM_BOUNDAGP  17 +#define DRM_MEM_CTXBITMAP 18 + +#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)  				/* Backward compatibility section */  				/* _PAGE_WT changed to _PAGE_PWT in 2.2.6 */ @@ -235,6 +245,7 @@ typedef struct drm_buf {  	int		  used;	       /* Amount of buffer in use (for DMA)  */  	unsigned long	  offset;      /* Byte offset (used internally)	     */  	void		  *address;    /* Address of buffer		     */ +	unsigned long	  bus_address; /* Bus address of buffer		     */  	struct drm_buf	  *next;       /* Kernel-only: used for free list    */  	__volatile__ int  waiting;     /* On kernel DMA queue		     */  	__volatile__ int  pending;     /* On hardware DMA queue		     */ @@ -250,6 +261,11 @@ typedef struct drm_buf {  		DRM_LIST_PRIO	 = 4,  		DRM_LIST_RECLAIM = 5  	}		  list;	       /* Which list we're on		     */ + + +	void *dev_private; +	int dev_priv_size; +  #if DRM_DMA_HISTOGRAM  	cycles_t	  time_queued;	   /* Queued to kernel DMA queue     */  	cycles_t	  time_dispatched; /* Dispatched to hardware	     */ @@ -376,6 +392,9 @@ typedef struct drm_device_dma {  	int		  page_count;  	unsigned long	  *pagelist;  	unsigned long	  byte_count; +	enum { +	   _DRM_DMA_USE_AGP = 0x01 +	} flags;  				/* DMA support */  	drm_buf_t	  *this_buffer;	/* Buffer being sent		   */ @@ -384,6 +403,41 @@ typedef struct drm_device_dma {  	wait_queue_head_t waiting;	/* Processes waiting on free bufs  */  } drm_device_dma_t; +#ifdef DRM_AGP +typedef struct drm_agp_mem { +	unsigned long      handle; +	agp_memory         *memory; +	unsigned long      bound; /* address */ +	int                pages; +	struct drm_agp_mem *prev; +	struct drm_agp_mem *next; +} drm_agp_mem_t; + +typedef struct drm_agp_head { +	agp_kern_info      agp_info; +	const char         *chipset; +	drm_agp_mem_t      *memory; +	unsigned long      mode; +	int                enabled; +	int                acquired; +	unsigned long      base; +   	int 		   agp_mtrr; +} drm_agp_head_t; + +typedef struct { +	void       (*free_memory)(agp_memory *); +	agp_memory *(*allocate_memory)(size_t, u32); +	int        (*bind_memory)(agp_memory *, off_t); +	int        (*unbind_memory)(agp_memory *); +	void       (*enable)(u32); +	int        (*acquire)(void); +	void       (*release)(void); +	void       (*copy_info)(agp_kern_info *); +} drm_agp_func_t; + +extern drm_agp_func_t drm_agp; +#endif +  typedef struct drm_device {  	const char	  *name;	/* Simple driver name		   */  	char		  *unique;	/* Unique identifier: e.g., busid  */ @@ -462,6 +516,12 @@ typedef struct drm_device {  	struct fasync_struct *buf_async;/* Processes waiting for SIGIO	   */  	wait_queue_head_t buf_readers;	/* Processes waiting to read	   */  	wait_queue_head_t buf_writers;	/* Processes waiting to ctx switch */ +	 +#ifdef DRM_AGP +	drm_agp_head_t    *agp; +#endif +	unsigned long     *ctx_bitmap; +	void		  *dev_private;  } drm_device_t; @@ -533,6 +593,14 @@ extern void	     drm_free_pages(unsigned long address, int order,  extern void	     *drm_ioremap(unsigned long offset, unsigned long size);  extern void	     drm_ioremapfree(void *pt, unsigned long size); +#ifdef DRM_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, @@ -642,5 +710,32 @@ 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); + +				/* 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); + +#ifdef DRM_AGP +				/* AGP/GART support (agpsupport.c) */ +extern drm_agp_head_t *drm_agp_init(void); +extern int            drm_agp_acquire(struct inode *inode, struct file *filp, +				      unsigned int cmd, unsigned long arg); +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_info(struct inode *inode, struct file *filp, +				   unsigned int cmd, unsigned long arg); +extern int            drm_agp_alloc(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, +				     unsigned int cmd, unsigned long arg); +extern int            drm_agp_bind(struct inode *inode, struct file *filp, +				   unsigned int cmd, unsigned long arg); +#endif  #endif  #endif diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 09959b65..30fda5b8 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -25,8 +25,9 @@   *   * Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com>   *	    Jeff Hartmann <jhartmann@precisioninsight.com> + *          Keith Whitwell <keithw@precisioninsight.com>   * - * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_dma.c,v 1.1 2000/02/11 17:26:04 dawes Exp $ + * $XFree86$   *   */ @@ -36,6 +37,9 @@  #include <linux/interrupt.h>	/* For task queue support */ +#define I810_BUF_FREE		1 +#define I810_BUF_USED		0 +  #define I810_REG(reg)		2  #define I810_BASE(reg)		((unsigned long) \  				dev->maplist[I810_REG(reg)]->handle) @@ -43,544 +47,457 @@  #define I810_DEREF(reg)		*(__volatile__ int *)I810_ADDR(reg)  #define I810_READ(reg)		I810_DEREF(reg)  #define I810_WRITE(reg,val) 	do { I810_DEREF(reg) = val; } while (0) - -void i810_dma_init(drm_device_t *dev) +#define I810_DEREF16(reg)	*(__volatile__ u16 *)I810_ADDR(reg) +#define I810_READ16(reg)	I810_DEREF16(reg) +#define I810_WRITE16(reg,val)	do { I810_DEREF16(reg) = val; } while (0) + +#define RING_LOCALS	unsigned int outring, ringmask; volatile char *virt; + +#define BEGIN_LP_RING(n) do {				\ +	if (I810_VERBOSE)				\ +		DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",	\ +			  n, __FUNCTION__);		\ +	if (dev_priv->ring.space < n*4) 		\ +		i810_wait_ring(dev, n*4);		\ +	dev_priv->ring.space -= n*4;			\ +	outring = dev_priv->ring.tail;			\ +	ringmask = dev_priv->ring.tail_mask;		\ +	virt = dev_priv->ring.virtual_start;		\ +} while (0) + +#define ADVANCE_LP_RING() do {					\ +	if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n");	\ +	dev_priv->ring.tail = outring;				\ +	I810_WRITE(LP_RING + RING_TAIL, outring);		\ +} while(0) + +#define OUT_RING(n) do {						\ +	if (I810_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));	\ +	*(volatile unsigned int *)(virt + outring) = n;			\ +	outring += 4;							\ +	outring &= ringmask;						\ +} while (0); + +static inline void i810_print_status_page(drm_device_t *dev)  { -        printk(KERN_INFO "i810_dma_init\n"); +   	drm_device_dma_t *dma = dev->dma; +      	drm_i810_private_t *dev_priv = dev->dev_private; +	u32 *temp = (u32 *)dev_priv->hw_status_page; +   	int i; + +   	DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]); +   	DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]); +   	DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]); +      	DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]); +   	DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]); +   	for(i = 6; i < dma->buf_count + 6; i++) { +	   	DRM_DEBUG(  "buffer status idx : %d used: %d\n", i - 6, temp[i]); +	}  } -void i810_dma_cleanup(drm_device_t *dev) +static drm_buf_t *i810_freelist_get(drm_device_t *dev)  { -   printk(KERN_INFO "i810_dma_cleanup\n"); +   	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,  +			       I810_BUF_USED); +	   	if(used == I810_BUF_FREE) { +			return buf; +		} +	} +   	return NULL;  } -static inline void i810_dma_dispatch(drm_device_t *dev, unsigned long address, -				    unsigned long length) +/* This should only be called if the buffer is not sent to the hardware + * yet, the hardware updates in use for us once its on the ring buffer. + */ + +static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)  { -   printk(KERN_INFO "i810_dma_dispatch\n"); +   	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_USED, I810_BUF_FREE); +   	if(used != I810_BUF_USED) { +	   	DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); +	   	return -EINVAL; +	} +    +   	return 0;  } -static inline void i810_dma_quiescent(drm_device_t *dev) +static int i810_dma_get_buffers(drm_device_t *dev, drm_dma_t *d)  { +	int		  i; +	drm_buf_t	  *buf; + +	for (i = d->granted_count; i < d->request_count; i++) { +		buf = i810_freelist_get(dev); +		if (!buf) break; +		buf->pid     = current->pid; +		copy_to_user_ret(&d->request_indices[i], +				 &buf->idx, +				 sizeof(buf->idx), +				 -EFAULT); +		copy_to_user_ret(&d->request_sizes[i], +				 &buf->total, +				 sizeof(buf->total), +				 -EFAULT); +		++d->granted_count; +	} +	return 0;  } -static inline void i810_dma_ready(drm_device_t *dev) +static unsigned long i810_alloc_page(drm_device_t *dev)  { -   i810_dma_quiescent(dev); -   printk(KERN_INFO "i810_dma_ready\n"); +	unsigned long address; +    +	address = __get_free_page(GFP_KERNEL); +	if(address == 0UL)  +		return 0; +	 +	atomic_inc(&mem_map[MAP_NR((void *) address)].count); +	set_bit(PG_locked, &mem_map[MAP_NR((void *) address)].flags); +    +	return address;  } -static inline int i810_dma_is_ready(drm_device_t *dev) +static void i810_free_page(drm_device_t *dev, unsigned long page)  { - -   i810_dma_quiescent(dev); - -   printk(KERN_INFO "i810_dma_is_ready\n"); -   return 1; +	if(page == 0UL)  +		return; +	 +	atomic_dec(&mem_map[MAP_NR((void *) page)].count); +	clear_bit(PG_locked, &mem_map[MAP_NR((void *) page)].flags); +	wake_up(&mem_map[MAP_NR((void *) page)].wait); +	free_page(page); +	return;  } - -static void i810_dma_service(int irq, void *device, struct pt_regs *regs) +static int i810_dma_cleanup(drm_device_t *dev)  { -	drm_device_t	 *dev = (drm_device_t *)device; -	drm_device_dma_t *dma = dev->dma; -	 -	atomic_inc(&dev->total_irq); -	if (i810_dma_is_ready(dev)) { -				/* Free previous buffer */ -		if (test_and_set_bit(0, &dev->dma_flag)) { -			atomic_inc(&dma->total_missed_free); -			return; +	if(dev->dev_private) { +	   	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);  		} -		if (dma->this_buffer) { -			drm_free_buffer(dev, dma->this_buffer); -			dma->this_buffer = NULL; +	   	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);  		} -		clear_bit(0, &dev->dma_flag); - -				/* Dispatch new buffer */ -		queue_task(&dev->tq, &tq_immediate); -		mark_bh(IMMEDIATE_BH); +	   	drm_free(dev->dev_private, sizeof(drm_i810_private_t),  +			 DRM_MEM_DRIVER); +	   	dev->dev_private = NULL;  	} +   	return 0;  } -/* Only called by i810_dma_schedule. */ -static int i810_do_dma(drm_device_t *dev, int locked) +static int i810_wait_ring(drm_device_t *dev, int n)  { -	unsigned long	 address; -	unsigned long	 length; -	drm_buf_t	 *buf; -	int		 retcode = 0; -	drm_device_dma_t *dma = dev->dma; -#if DRM_DMA_HISTOGRAM -	cycles_t	 dma_start, dma_stop; -#endif - -	if (test_and_set_bit(0, &dev->dma_flag)) { -		atomic_inc(&dma->total_missed_dma); -		return -EBUSY; -	} -	 -#if DRM_DMA_HISTOGRAM -	dma_start = get_cycles(); -#endif - -	if (!dma->next_buffer) { -		DRM_ERROR("No next_buffer\n"); -		clear_bit(0, &dev->dma_flag); -		return -EINVAL; -	} - -	buf	= dma->next_buffer; -	address = (unsigned long)buf->bus_address; -	length	= buf->used; +   	drm_i810_private_t *dev_priv = dev->dev_private; +   	drm_i810_ring_buffer_t *ring = &(dev_priv->ring); +   	int iters = 0; +   	unsigned long end; + +	end = jiffies + (HZ*3); +   	while (ring->space < n) { +	   	int i; - -	DRM_DEBUG("context %d, buffer %d (%ld bytes)\n", -		  buf->context, buf->idx, length); - -	if (buf->list == DRM_LIST_RECLAIM) { -		drm_clear_next_buffer(dev); -		drm_free_buffer(dev, buf); -		clear_bit(0, &dev->dma_flag); -		return -EINVAL; -	} - -	if (!length) { -		DRM_ERROR("0 length buffer\n"); -		drm_clear_next_buffer(dev); -		drm_free_buffer(dev, buf); -		clear_bit(0, &dev->dma_flag); -		return 0; -	} -	 -	if (!i810_dma_is_ready(dev)) { -		clear_bit(0, &dev->dma_flag); -		return -EBUSY; -	} - -	if (buf->while_locked) { -		if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { -			DRM_ERROR("Dispatching buffer %d from pid %d" -				  " \"while locked\", but no lock held\n", -				  buf->idx, buf->pid); -		} -	} else { -		if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock, -					      DRM_KERNEL_CONTEXT)) { -			atomic_inc(&dma->total_missed_lock); -			clear_bit(0, &dev->dma_flag); -			return -EBUSY; +	   	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; +	    +	   	iters++; +		if((signed)(end - jiffies) <= 0) { +		   	DRM_ERROR("space: %d wanted %d\n", ring->space, n); +		   	DRM_ERROR("lockup\n"); +		   	goto out_wait_ring;  		} -	} - -	if (dev->last_context != buf->context -	    && !(dev->queuelist[buf->context]->flags -		 & _DRM_CONTEXT_PRESERVED)) { -				/* PRE: dev->last_context != buf->context */ -		if (drm_context_switch(dev, dev->last_context, buf->context)) { -			drm_clear_next_buffer(dev); -			drm_free_buffer(dev, buf); -		} -		retcode = -EBUSY; -		goto cleanup; -			 -				/* POST: we will wait for the context -				   switch and will dispatch on a later call -				   when dev->last_context == buf->context. -				   NOTE WE HOLD THE LOCK THROUGHOUT THIS -				   TIME! */ -	} - -	drm_clear_next_buffer(dev); -	buf->pending	 = 1; -	buf->waiting	 = 0; -	buf->list	 = DRM_LIST_PEND; -#if DRM_DMA_HISTOGRAM -	buf->time_dispatched = get_cycles(); -#endif -	i810_dma_dispatch(dev, address, length); -	drm_free_buffer(dev, dma->this_buffer); -	dma->this_buffer = buf; - -	atomic_add(length, &dma->total_bytes); -	atomic_inc(&dma->total_dmas); - -	if (!buf->while_locked && !dev->context_flag && !locked) { -		if (drm_lock_free(dev, &dev->lock.hw_lock->lock, -				  DRM_KERNEL_CONTEXT)) { -			DRM_ERROR("\n"); -		} +	   	for (i = 0 ; i < 2000 ; i++) ;  	} -cleanup: - -	clear_bit(0, &dev->dma_flag); -#if DRM_DMA_HISTOGRAM -	dma_stop = get_cycles(); -	atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]); -#endif - -	return retcode; -} - -static void i810_dma_schedule_timer_wrapper(unsigned long dev) -{ -	i810_dma_schedule((drm_device_t *)dev, 0); +out_wait_ring:    +   	return iters;  } -static void i810_dma_schedule_tq_wrapper(void *dev) +static void i810_kernel_lost_context(drm_device_t *dev)  { -	i810_dma_schedule(dev, 0); +      	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); +     	if (ring->space < 0) ring->space += ring->Size;  } -int i810_dma_schedule(drm_device_t *dev, int locked) +static int i810_freelist_init(drm_device_t *dev)  { -	int		 next; -	drm_queue_t	 *q; -	drm_buf_t	 *buf; -	int		 retcode   = 0; -	int		 processed = 0; -	int		 missed; -	int		 expire	   = 20; -	drm_device_dma_t *dma	   = dev->dma; -#if DRM_DMA_HISTOGRAM -	cycles_t	 schedule_start; -#endif - -	if (test_and_set_bit(0, &dev->interrupt_flag)) { -				/* Not reentrant */ -		atomic_inc(&dma->total_missed_sched); -		return -EBUSY; -	} -	missed = atomic_read(&dma->total_missed_sched); - -#if DRM_DMA_HISTOGRAM -	schedule_start = get_cycles(); -#endif - -again: -	if (dev->context_flag) { -		clear_bit(0, &dev->interrupt_flag); -		return -EBUSY; -	} -	if (dma->next_buffer) { -				/* Unsent buffer that was previously -				   selected, but that couldn't be sent -				   because the lock could not be obtained -				   or the DMA engine wasn't ready.  Try -				   again. */ -		atomic_inc(&dma->total_tried); -		if (!(retcode = i810_do_dma(dev, locked))) { -			atomic_inc(&dma->total_hit); -			++processed; -		} -	} else { -		do { -			next = drm_select_queue(dev, -					     i810_dma_schedule_timer_wrapper); -			if (next >= 0) { -				q   = dev->queuelist[next]; -				buf = drm_waitlist_get(&q->waitlist); -				dma->next_buffer = buf; -				dma->next_queue	 = q; -				if (buf && buf->list == DRM_LIST_RECLAIM) { -					drm_clear_next_buffer(dev); -					drm_free_buffer(dev, buf); -				} -			} -		} while (next >= 0 && !dma->next_buffer); -		if (dma->next_buffer) { -			if (!(retcode = i810_do_dma(dev, locked))) { -				++processed; -			} -		} +      	drm_device_dma_t *dma = dev->dma; +   	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; +   	u8 *hw_status = (u8 *)dev_priv->hw_status_page; +   	int i; +   	int my_idx = 24; +    +   	if(dma->buf_count > 1019) { +	   	/* Not enough space in the status page for the freelist */ +	   	return -EINVAL;  	} -	if (--expire) { -		if (missed != atomic_read(&dma->total_missed_sched)) { -			atomic_inc(&dma->total_lost); -			if (i810_dma_is_ready(dev)) goto again; -		} -		if (processed && i810_dma_is_ready(dev)) { -			atomic_inc(&dma->total_lost); -			processed = 0; -			goto again; -		} +   	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 + my_idx; +	   	DRM_DEBUG("buf_priv->in_use : %p\n", buf_priv->in_use); +	   	*buf_priv->in_use = I810_BUF_FREE; +	   	buf_priv->my_use_idx = my_idx; +	   	my_idx += 4;  	} -	 -	clear_bit(0, &dev->interrupt_flag); -	 -#if DRM_DMA_HISTOGRAM -	atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles() -							   - schedule_start)]); -#endif -	return retcode; +	return 0;  } -static int i810_dma_priority(drm_device_t *dev, drm_dma_t *d) +static int i810_dma_initialize(drm_device_t *dev,  +			       drm_i810_private_t *dev_priv, +			       drm_i810_init_t *init)  { -	unsigned long	  address; -	unsigned long	  length; -	int		  must_free = 0; -	int		  retcode   = 0; -	int		  i; -	int		  idx; -	drm_buf_t	  *buf; -	drm_buf_t	  *last_buf = NULL; -	drm_device_dma_t  *dma	    = dev->dma; -	DECLARE_WAITQUEUE(entry, current); - -				/* Turn off interrupt handling */ -	while (test_and_set_bit(0, &dev->interrupt_flag)) { -		schedule(); -		if (signal_pending(current)) return -EINTR; -	} -	if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) { -		while (!drm_lock_take(&dev->lock.hw_lock->lock, -				      DRM_KERNEL_CONTEXT)) { -			schedule(); -			if (signal_pending(current)) { -				clear_bit(0, &dev->interrupt_flag); -				return -EINTR; -			} -		} -		++must_free; -	} -	atomic_inc(&dma->total_prio); - -	for (i = 0; i < d->send_count; i++) { -		idx = d->send_indices[i]; -		if (idx < 0 || idx >= dma->buf_count) { -			DRM_ERROR("Index %d (of %d max)\n", -				  d->send_indices[i], dma->buf_count - 1); -			continue; -		} -		buf = dma->buflist[ idx ]; -		if (buf->pid != current->pid) { -			DRM_ERROR("Process %d using buffer owned by %d\n", -				  current->pid, buf->pid); -			retcode = -EINVAL; -			goto cleanup; -		} -		if (buf->list != DRM_LIST_NONE) { -			DRM_ERROR("Process %d using %d's buffer on list %d\n", -				  current->pid, buf->pid, buf->list); -			retcode = -EINVAL; -			goto cleanup; -		} -				/* This isn't a race condition on -				   buf->list, since our concern is the -				   buffer reclaim during the time the -				   process closes the /dev/drm? handle, so -				   it can't also be doing DMA. */ -		buf->list	  = DRM_LIST_PRIO; -		buf->used	  = d->send_sizes[i]; -		buf->context	  = d->context; -		buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED; -		address		  = (unsigned long)buf->address; -		length		  = buf->used; -		if (!length) { -			DRM_ERROR("0 length buffer\n"); -		} -		if (buf->pending) { -			DRM_ERROR("Sending pending buffer:" -				  " buffer %d, offset %d\n", -				  d->send_indices[i], i); -			retcode = -EINVAL; -			goto cleanup; -		} -		if (buf->waiting) { -			DRM_ERROR("Sending waiting buffer:" -				  " buffer %d, offset %d\n", -				  d->send_indices[i], i); -			retcode = -EINVAL; -			goto cleanup; -		} -		buf->pending = 1; -		 -		if (dev->last_context != buf->context -		    && !(dev->queuelist[buf->context]->flags -			 & _DRM_CONTEXT_PRESERVED)) { -			add_wait_queue(&dev->context_wait, &entry); -			current->state = TASK_INTERRUPTIBLE; -				/* PRE: dev->last_context != buf->context */ -			drm_context_switch(dev, dev->last_context, -					   buf->context); -				/* POST: we will wait for the context -				   switch and will dispatch on a later call -				   when dev->last_context == buf->context. -				   NOTE WE HOLD THE LOCK THROUGHOUT THIS -				   TIME! */ -			schedule(); -			current->state = TASK_RUNNING; -			remove_wait_queue(&dev->context_wait, &entry); -			if (signal_pending(current)) { -				retcode = -EINTR; -				goto cleanup; -			} -			if (dev->last_context != buf->context) { -				DRM_ERROR("Context mismatch: %d %d\n", -					  dev->last_context, -					  buf->context); -			} -		} - -#if DRM_DMA_HISTOGRAM -		buf->time_queued     = get_cycles(); -		buf->time_dispatched = buf->time_queued; -#endif -		i810_dma_dispatch(dev, address, length); -	        if (drm_lock_free(dev, &dev->lock.hw_lock->lock, -				  DRM_KERNEL_CONTEXT)) { -		   DRM_ERROR("\n"); -		} - -		atomic_add(length, &dma->total_bytes); -		atomic_inc(&dma->total_dmas); -		 -		if (last_buf) { -			drm_free_buffer(dev, last_buf); -		} -		last_buf = buf; -	} +	drm_map_t *sarea_map; +   	dev->dev_private = (void *) dev_priv; +   	memset(dev_priv, 0, sizeof(drm_i810_private_t)); -cleanup: -	if (last_buf) { -		i810_dma_ready(dev); -		drm_free_buffer(dev, last_buf); +   	if (init->ring_map_idx >= dev->map_count || +	    init->buffer_map_idx >= dev->map_count) { +	   	i810_dma_cleanup(dev); +	   	DRM_ERROR("ring_map or buffer_map are invalid\n"); +	   	return -EINVAL;  	} -	 -	if (must_free && !dev->context_flag) { -		if (drm_lock_free(dev, &dev->lock.hw_lock->lock, -				  DRM_KERNEL_CONTEXT)) { -			DRM_ERROR("\n"); -		} +    +   	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 +  +		 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.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" +			  " ring buffer\n"); +	   	return -ENOMEM;  	} -	clear_bit(0, &dev->interrupt_flag); -	return retcode; +    +   	/* Program Hardware Status Page */ +   	dev_priv->hw_status_page = i810_alloc_page(dev); +   	memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE); +   	if(dev_priv->hw_status_page == 0UL) { +		i810_dma_cleanup(dev); +		DRM_ERROR("Can not allocate hardware status page\n"); +		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); +	   	DRM_ERROR("Not enough space in the status page for" +			  " the freelist\n"); +	   	return -ENOMEM; +	} +   	return 0;  } -static int i810_dma_send_buffers(drm_device_t *dev, drm_dma_t *d) +int i810_dma_init(struct inode *inode, struct file *filp, +		  unsigned int cmd, unsigned long arg)  { -	DECLARE_WAITQUEUE(entry, current); -	drm_buf_t	  *last_buf = NULL; -	int		  retcode   = 0; -	drm_device_dma_t  *dma	    = dev->dma; - -	if (d->flags & _DRM_DMA_BLOCK) { -		last_buf = dma->buflist[d->send_indices[d->send_count-1]]; -		add_wait_queue(&last_buf->dma_wait, &entry); -	} +   	drm_file_t *priv = filp->private_data; +   	drm_device_t *dev = priv->dev; +   	drm_i810_private_t *dev_priv; +   	drm_i810_init_t init; +   	int retcode = 0; -	if ((retcode = drm_dma_enqueue(dev, d))) { -		if (d->flags & _DRM_DMA_BLOCK) -			remove_wait_queue(&last_buf->dma_wait, &entry); -		return retcode; -	} -	 -	i810_dma_schedule(dev, 0); +   	copy_from_user_ret(&init, (drm_i810_init_t *)arg,  +			   sizeof(init), -EFAULT); -	if (d->flags & _DRM_DMA_BLOCK) { -		DRM_DEBUG("%d waiting\n", current->pid); -		current->state = TASK_INTERRUPTIBLE; -		for (;;) { -			if (!last_buf->waiting -			    && !last_buf->pending) -				break; /* finished */ -			schedule(); -			if (signal_pending(current)) { -				retcode = -EINTR; /* Can't restart */ -				break; -			} -		} -		current->state = TASK_RUNNING; -		DRM_DEBUG("%d running\n", current->pid); -		remove_wait_queue(&last_buf->dma_wait, &entry); -		if (!retcode -		    || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) { -			if (!waitqueue_active(&last_buf->dma_wait)) { -				drm_free_buffer(dev, last_buf); -			} -		} -		if (retcode) { -			DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n", -				  d->context, -				  last_buf->waiting, -				  last_buf->pending, -				  DRM_WAITCOUNT(dev, d->context), -				  last_buf->idx, -				  last_buf->list, -				  last_buf->pid, -				  current->pid); -		} +   	switch(init.func) { +	 	case I810_INIT_DMA: +	   		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); +	   	break; +	 	case I810_CLEANUP_DMA: +	   		retcode = i810_dma_cleanup(dev); +	   	break; +	 	default: +	   		retcode = -EINVAL; +	   	break;  	} -	return retcode; +    +   	return retcode;  } -int i810_dma(struct inode *inode, struct file *filp, unsigned int cmd, -	      unsigned long arg) +static void i810_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf, +				      int used )  { -	drm_file_t	  *priv	    = filp->private_data; -	drm_device_t	  *dev	    = priv->dev; -	drm_device_dma_t  *dma	    = dev->dma; -	int		  retcode   = 0; -	drm_dma_t	  d; - -        printk("i810_dma start\n"); -   	copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); -	DRM_DEBUG("%d %d: %d send, %d req\n", -		  current->pid, d.context, d.send_count, d.request_count); +      	drm_i810_private_t *dev_priv = dev->dev_private; +   	drm_i810_buf_priv_t *buf_priv = buf->dev_private; +	unsigned long address = (unsigned long)buf->bus_address; +	unsigned long start = address - dev->agp->base; +   	RING_LOCALS; + +   	dev_priv->counter++; +   	DRM_DEBUG(  "dispatch counter : %ld\n", dev_priv->counter); +   	DRM_DEBUG(  "i810_dma_dispatch\n"); +   	DRM_DEBUG(  "start : 0x%lx\n", start); +	DRM_DEBUG(  "used : 0x%x\n", used); +   	DRM_DEBUG(  "start + used - 4 : 0x%lx\n", start + used - 4); +   	i810_kernel_lost_context(dev); + +   	BEGIN_LP_RING(10); +   	OUT_RING( CMD_OP_BATCH_BUFFER ); +   	OUT_RING( start | BB1_PROTECTED ); +   	OUT_RING( start + used - 4 ); +      	OUT_RING( CMD_STORE_DWORD_IDX ); +   	OUT_RING( 20 ); +   	OUT_RING( dev_priv->counter ); +   	OUT_RING( CMD_STORE_DWORD_IDX ); +   	OUT_RING( buf_priv->my_use_idx ); +   	OUT_RING( I810_BUF_FREE );    +      	OUT_RING( CMD_REPORT_HEAD ); +      	ADVANCE_LP_RING(); +} -	if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) { -		DRM_ERROR("Process %d using context %d\n", -			  current->pid, d.context); -		return -EINVAL; -	} +static void i810_dma_dispatch_vertex(drm_device_t *dev,  +				     drm_buf_t *buf, +				     int discard, +				     int used) +{ +   	drm_i810_private_t *dev_priv = dev->dev_private; +	drm_i810_buf_priv_t *buf_priv = buf->dev_private; +   	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; +   	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;      +	int i = 0; +   	RING_LOCALS; -	if (d.send_count < 0 || d.send_count > dma->buf_count) { -		DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n", -			  current->pid, d.send_count, dma->buf_count); -		return -EINVAL; -	} -	if (d.request_count < 0 || d.request_count > dma->buf_count) { -		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", -			  current->pid, d.request_count, dma->buf_count); -		return -EINVAL; +    +   	if (nbox > I810_NR_SAREA_CLIPRECTS)  +		nbox = I810_NR_SAREA_CLIPRECTS; +    +   	DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",  +		  address, used, nbox); + +   	dev_priv->counter++; +   	DRM_DEBUG(  "dispatch counter : %ld\n", dev_priv->counter); +   	DRM_DEBUG(  "i810_dma_dispatch\n"); +   	DRM_DEBUG(  "start : %lx\n", start); +	DRM_DEBUG(  "used : %d\n", used); +   	DRM_DEBUG(  "start + used - 4 : %ld\n", start + used - 4); +   	i810_kernel_lost_context(dev); + +	if (used) { +		do { +			if (i < nbox) { +				BEGIN_LP_RING(4); +				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);  	} -	if (d.send_count) { -#if 0 -		if (d.flags & _DRM_DMA_PRIORITY) -			retcode = i810_dma_priority(dev, &d); -		else  -			retcode = i810_dma_send_buffers(dev, &d); -#endif -	   printk("i810_dma priority\n"); +	BEGIN_LP_RING(10); +	OUT_RING( CMD_STORE_DWORD_IDX ); +	OUT_RING( 20 ); +	OUT_RING( dev_priv->counter ); +	OUT_RING( 0 ); -	   retcode = i810_dma_priority(dev, &d); +	if (discard) { +		OUT_RING( CMD_STORE_DWORD_IDX ); +		OUT_RING( buf_priv->my_use_idx ); +		OUT_RING( I810_BUF_FREE ); +		OUT_RING( 0 );  	} -	d.granted_count = 0; +      	OUT_RING( CMD_REPORT_HEAD ); +	OUT_RING( 0 ); +   	ADVANCE_LP_RING(); +} -	if (!retcode && d.request_count) { -		retcode = drm_dma_get_buffers(dev, &d); -	} -	DRM_DEBUG("%d returning, granted = %d\n", -		  current->pid, d.granted_count); -	copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT); +/* Interrupts are only for flushing */ +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); +      	temp = I810_READ16(I810REG_INT_IDENTITY_R); +   	temp = temp & ~(0x6000); +   	if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,  +				   temp); /* Clear all interrupts */ +    +   	queue_task(&dev->tq, &tq_immediate); +   	mark_bh(IMMEDIATE_BH); +} -   	printk("i810_dma end (granted)\n"); -	return retcode; +static void i810_dma_task_queue(void *device) +{ +	drm_device_t *dev = (drm_device_t *) device; +      	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; + +   	atomic_set(&dev_priv->flush_done, 1); +   	wake_up_interruptible(&dev_priv->flush_queue);  }  int i810_irq_install(drm_device_t *dev, int irq)  {  	int retcode; - +	u16 temp; +     	if (!irq)     return -EINVAL;  	down(&dev->struct_sem); @@ -591,6 +508,7 @@ 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; @@ -603,12 +521,21 @@ int i810_irq_install(drm_device_t *dev, int irq)  	dev->tq.next	      = NULL;  	dev->tq.sync	      = 0; -	dev->tq.routine	      = i810_dma_schedule_tq_wrapper; +	dev->tq.routine	      = i810_dma_task_queue;  	dev->tq.data	      = dev; -  				/* Before installing handler */ -	/* TODO */	 +   	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 */ +   	temp = I810_READ16(I810REG_INT_ENABLE_R); +   	temp = temp & 0x6000; +      	I810_WRITE16(I810REG_INT_ENABLE_R, temp); /* Disable all interrupts */ +  				/* Install handler */  	if ((retcode = request_irq(dev->irq,  				   i810_dma_service, @@ -620,15 +547,18 @@ int i810_irq_install(drm_device_t *dev, int irq)  		up(&dev->struct_sem);  		return retcode;  	} - -				/* After installing handler */ -	/* TODO */ +   	temp = I810_READ16(I810REG_INT_ENABLE_R); +   	temp = temp & 0x6000; +   	temp = temp | 0x0003; +   	I810_WRITE16(I810REG_INT_ENABLE_R,  +		     temp); /* Enable bp & user interrupts */  	return 0;  }  int i810_irq_uninstall(drm_device_t *dev)  {  	int irq; +   	u16 temp;  	down(&dev->struct_sem);  	irq	 = dev->irq; @@ -636,16 +566,25 @@ int i810_irq_uninstall(drm_device_t *dev)  	up(&dev->struct_sem);  	if (!irq) return -EINVAL; -	 + +   	DRM_DEBUG(  "Interrupt UnInstall: %d\n", irq);	  	DRM_DEBUG("%d\n", irq); -	 -	/* TODO : Disable interrupts */ +    +   	temp = I810_READ16(I810REG_INT_IDENTITY_R); +   	temp = temp & ~(0x6000); +   	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,  +		     temp);                     /* Disable all interrupts */ +     	free_irq(irq, dev);  	return 0;  } -  int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,  		  unsigned long arg)  { @@ -654,8 +593,7 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,  	drm_control_t	ctl;  	int		retcode; -   	printk(KERN_INFO "i810_control\n"); -   	i810_dma_init(dev); +   	DRM_DEBUG(  "i810_control\n");  	copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); @@ -674,20 +612,134 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,  	return 0;  } +static inline void i810_dma_emit_flush(drm_device_t *dev) +{ +   	drm_i810_private_t *dev_priv = dev->dev_private; +   	RING_LOCALS; + +   	i810_kernel_lost_context(dev); +   	BEGIN_LP_RING(2); +      	OUT_RING( CMD_REPORT_HEAD ); +   	OUT_RING( GFX_OP_USER_INTERRUPT ); +      	ADVANCE_LP_RING(); +} + +static inline void i810_dma_quiescent_emit(drm_device_t *dev) +{ +      	drm_i810_private_t *dev_priv = dev->dev_private; +   	RING_LOCALS; + +  	i810_kernel_lost_context(dev); +   	BEGIN_LP_RING(4); + +   	OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); +   	OUT_RING( CMD_REPORT_HEAD ); +   	OUT_RING( GFX_OP_USER_INTERRUPT ); +   	OUT_RING( 0 ); +   	ADVANCE_LP_RING(); +} + +static 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;       + +   	if(dev_priv == NULL) { +	   	return; +	} +      	atomic_set(&dev_priv->flush_done, 0); +   	current->state = TASK_INTERRUPTIBLE; +   	add_wait_queue(&dev_priv->flush_queue, &entry); +   	end = jiffies + (HZ*3); +    +   	for (;;) { +	      	i810_dma_quiescent_emit(dev); +	   	if (atomic_read(&dev_priv->flush_done) == 1) break; +		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; +} + +static int i810_flush_queue(drm_device_t *dev) +{ +   	DECLARE_WAITQUEUE(entry, current); +  	drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; +	unsigned long end; +   	int ret = 0;       + +   	if(dev_priv == NULL) { +	   	return 0; +	} +      	atomic_set(&dev_priv->flush_done, 0); +   	current->state = TASK_INTERRUPTIBLE; +   	add_wait_queue(&dev_priv->flush_queue, &entry); +   	end = jiffies + (HZ*3); +   	for (;;) { +	      	i810_dma_emit_flush(dev); +	   	if (atomic_read(&dev_priv->flush_done) == 1) break; +		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); +    +   	return ret; +} + +/* Must be called with the lock held */ +void i810_reclaim_buffers(drm_device_t *dev, pid_t pid) +{ +	drm_device_dma_t *dma = dev->dma; +	int		 i; + +	if (!dma) return; +      	if(dev->dev_private == NULL) return; + +        i810_flush_queue(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; + +		if (buf->pid == pid) { +		   	/* Only buffers that need to get reclaimed ever  +			 * get set to free */ +		   	if(buf_priv == NULL) return; +		   	cmpxchg(buf_priv->in_use,  +				I810_BUF_USED, I810_BUF_FREE); +		} +	} +} +  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; -	drm_queue_t	  *q; -#if DRM_DMA_HISTOGRAM -	cycles_t	  start; - -	dev->lck_start = start = get_cycles(); -#endif  	copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); @@ -696,16 +748,20 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,  			  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) { +	if (lock.context < 0) {  		return -EINVAL;  	} -	q = dev->queuelist[lock.context]; -	 -	ret = drm_flush_block_and_flush(dev, lock.context, lock.flags); +	/* Only one queue: +	 */  	if (!ret) { -		if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) +#if 0 +	   	if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)  		    != lock.context) {  			long j = jiffies - dev->lock.lock_time; @@ -716,6 +772,7 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,  				schedule_timeout(j);  			}  		} +#endif  		add_wait_queue(&dev->lock.lock_queue, &entry);  		for (;;) {  			if (!dev->lock.hw_lock) { @@ -728,13 +785,13 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,  				dev->lock.pid	    = current->pid;  				dev->lock.lock_time = jiffies;  				atomic_inc(&dev->total_locks); -				atomic_inc(&q->total_locks);  				break;	/* Got lock */  			}  				/* Contention */  			atomic_inc(&dev->total_sleeps);  			current->state = TASK_INTERRUPTIBLE; +		   	DRM_DEBUG("Calling lock schedule\n");  			schedule();  			if (signal_pending(current)) {  				ret = -ERESTARTSYS; @@ -744,19 +801,184 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,  		current->state = TASK_RUNNING;  		remove_wait_queue(&dev->lock.lock_queue, &entry);  	} - -	drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */  	if (!ret) { -		if (lock.flags & _DRM_LOCK_READY) -			i810_dma_ready(dev); -		if (lock.flags & _DRM_LOCK_QUIESCENT) -			i810_dma_quiescent(dev); +		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; +} -#if DRM_DMA_HISTOGRAM -	atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); -#endif +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"); +		return -EINVAL; +	} + +   	i810_flush_queue(dev); +   	return 0; +} + +static int i810DmaGeneral(drm_device_t *dev, drm_i810_general_t *args) +{ +	drm_device_dma_t *dma = dev->dma; +   	drm_buf_t *buf = dma->buflist[ args->idx ]; +   	 +	if (!args->used) { +	   	i810_freelist_put(dev, buf); +	} else {   +		i810_dma_dispatch_general( dev, buf, args->used ); +		atomic_add(args->used, &dma->total_bytes); +		atomic_inc(&dma->total_dmas); +	} +	return 0;  +} + +static int i810DmaVertex(drm_device_t *dev, drm_i810_vertex_t *args) +{ +	drm_device_dma_t *dma = dev->dma; +	drm_buf_t *buf = dma->buflist[ args->idx ]; +   	i810_dma_dispatch_vertex( dev, buf, args->discard, args->used ); +   	atomic_add(args->used, &dma->total_bytes); +	atomic_inc(&dma->total_dmas); +   	return 0; +} + +int i810_dma_general(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_i810_general_t general; +      	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;  + +	int retcode = 0; -	return ret; +	copy_from_user_ret(&general, (drm_i810_general_t *)arg, sizeof(general), +			   -EFAULT); + +	DRM_DEBUG("i810 dma general idx %d used %d\n", +		  general.idx, general.used); +    +   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { +		DRM_ERROR("i810_dma_general called without lock held\n"); +		return -EINVAL; +	} + +	retcode = i810DmaGeneral(dev, &general); +	sarea_priv->last_enqueue = dev_priv->counter-1; +   	sarea_priv->last_dispatch = (int) hw_status[5]; +    +	return retcode; +} + +int i810_dma_vertex(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_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_vertex_t vertex; +	int retcode = 0; + +	copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex), +			   -EFAULT); +   	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { +		DRM_ERROR("i810_dma_vertex called without lock held\n"); +		return -EINVAL; +	} + +	DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", +		  vertex.idx, vertex.used, vertex.discard); + +	retcode = i810DmaVertex(dev, &vertex); +	sarea_priv->last_enqueue = dev_priv->counter-1; +   	sarea_priv->last_dispatch = (int) hw_status[5]; +    +	return retcode; + +} + +int i810_getage(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_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;  + +      	sarea_priv->last_dispatch = (int) hw_status[5]; +	return 0; +} + +int i810_dma(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; +	drm_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;  + + +   	copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); +	DRM_DEBUG("%d %d: %d send, %d req\n", +		  current->pid, d.context, d.send_count, d.request_count); +    +	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { +		DRM_ERROR("i810_dma called without lock held\n"); +		return -EINVAL; +	} + +	/* Please don't send us buffers. +	 */ +	if (d.send_count != 0) { +		DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", +			  current->pid, d.send_count); +		return -EINVAL; +	} +	 +	/* We'll send you buffers. +	 */ +	if (d.request_count < 0 || d.request_count > dma->buf_count) { +		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", +			  current->pid, d.request_count, dma->buf_count); +		return -EINVAL; +	} +	 +	d.granted_count = 0; + +	if (!retcode && d.request_count) { +		retcode = i810_dma_get_buffers(dev, &d); +	} + +	DRM_DEBUG("i810_dma: %d returning, granted = %d\n", +		  current->pid, d.granted_count); + +	copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);    +   	sarea_priv->last_dispatch = (int) hw_status[5]; + +	return retcode;  } diff --git a/linux-core/i810_drm.h b/linux-core/i810_drm.h new file mode 100644 index 00000000..0754874c --- /dev/null +++ b/linux-core/i810_drm.h @@ -0,0 +1,93 @@ +#ifndef _I810_DRM_H_ +#define _I810_DRM_H_ + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +/* Might one day want to support the client-side ringbuffer code again. + */ +#ifndef _I810_DEFINES_ +#define _I810_DEFINES_ + +#define I810_USE_BATCH			1 +#define I810_DMA_BUF_ORDER		12 +#define I810_DMA_BUF_SZ 		(1<<I810_DMA_BUF_ORDER) +#define I810_DMA_BUF_NR 		256 +#define I810_NR_SAREA_CLIPRECTS 	2 + +/* Each region is a minimum of 64k, and there are at most 64 of them. + */ + +#define I810_NR_TEX_REGIONS 64 +#define I810_LOG_MIN_TEX_REGION_SIZE 16 +#endif + +typedef struct _drm_i810_init { +   	enum { +	   	I810_INIT_DMA = 0x01, +	   	I810_CLEANUP_DMA = 0x02 +	} func; +   	int ring_map_idx; +      	int buffer_map_idx; +	int sarea_priv_offset; +   	unsigned long ring_start; +   	unsigned long ring_end; +   	unsigned long ring_size; +} drm_i810_init_t; + +/* Warning: If you change the SAREA structure you must change the Xserver + * structure as well */ + +typedef struct _drm_i810_tex_region { +	unsigned char next, prev; /* indices to form a circular LRU  */ +	unsigned char in_use;	/* owned by a client, or free? */ +	int age;		/* tracked by clients to update local LRU's */ +} drm_i810_tex_region_t; + +typedef struct _drm_i810_sarea { +	unsigned int nbox; +	drm_clip_rect_t boxes[I810_NR_SAREA_CLIPRECTS]; + +	/* Maintain an LRU of contiguous regions of texture space.  If +	 * you think you own a region of texture memory, and it has an +	 * age different to the one you set, then you are mistaken and +	 * it has been stolen by another client.  If global texAge +	 * hasn't changed, there is no need to walk the list. +	 * +	 * These regions can be used as a proxy for the fine-grained +	 * texture information of other clients - by maintaining them +	 * in the same lru which is used to age their own textures, +	 * clients have an approximate lru for the whole of global +	 * texture space, and can make informed decisions as to which +	 * areas to kick out.  There is no need to choose whether to +	 * kick out your own texture or someone else's - simply eject +	 * them all in LRU order.   +	 */ +    +	drm_i810_tex_region_t texList[I810_NR_TEX_REGIONS+1];  +				/* Last elt is sentinal */ +        int texAge;		/* last time texture was uploaded */ +        int last_enqueue;	/* last time a buffer was enqueued */ +	int last_dispatch;	/* age of the most recently dispatched buffer */ +	int last_quiescent;     /*  */ +	int ctxOwner;		/* last context to upload state */ +} drm_i810_sarea_t; + +typedef struct _drm_i810_general { +   	int idx; +	int used; +} drm_i810_general_t; + +/* These may be placeholders if we have more cliprects than + * I810_NR_SAREA_CLIPRECTS.  In that case, the client sets discard to + * false, indicating that the buffer will be dispatched again with a + * new set of cliprects. + */ +typedef struct _drm_i810_vertex { +   	int idx;		/* buffer index */ +	int used;		/* nr bytes in use */ +	int discard;		/* client is finished with the buffer? */ +} drm_i810_vertex_t; + +#endif /* _I810_DRM_H_ */ diff --git a/linux-core/i810_drv.c b/linux-core/i810_drv.c index f33153a3..d3b35c49 100644 --- a/linux-core/i810_drv.c +++ b/linux-core/i810_drv.c @@ -33,11 +33,13 @@  #define EXPORT_SYMTAB  #include "drmP.h"  #include "i810_drv.h" + +  EXPORT_SYMBOL(i810_init);  EXPORT_SYMBOL(i810_cleanup);  #define I810_NAME	 "i810" -#define I810_DESC	 "Matrox g200/g400" +#define I810_DESC	 "Intel I810"  #define I810_DATE	 "19991213"  #define I810_MAJOR	 0  #define I810_MINOR	 0 @@ -54,6 +56,7 @@ static struct file_operations i810_fops = {  	mmap:	 drm_mmap,  	read:	 drm_read,  	fasync:	 drm_fasync, +      	poll:	 drm_poll,  };  static struct miscdevice      i810_misc = { @@ -80,13 +83,13 @@ static drm_ioctl_desc_t	      i810_ioctls[] = {  	[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)]    = { i810_mapbufs,	  1, 0 },  	[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)]   = { i810_freebufs,  1, 0 }, -	[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_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 }, @@ -104,6 +107,11 @@ static drm_ioctl_desc_t	      i810_ioctls[] = {  	[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_DMA)]    = { i810_dma_general,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 },  };  #define I810_IOCTL_COUNT DRM_ARRAY_SIZE(i810_ioctls) @@ -121,7 +129,7 @@ MODULE_PARM(i810, "s");  int init_module(void)  { -	printk("doing i810_init()\n"); +	DRM_DEBUG("doing i810_init()\n");  	return i810_init();  } @@ -364,7 +372,7 @@ int i810_init(void)  #ifdef MODULE  	drm_parse_options(i810);  #endif -	printk("doing misc_register\n"); +	DRM_DEBUG("doing misc_register\n");  	if ((retcode = misc_register(&i810_misc))) {  		DRM_ERROR("Cannot register \"%s\"\n", I810_NAME);  		return retcode; @@ -372,13 +380,22 @@ int i810_init(void)  	dev->device = MKDEV(MISC_MAJOR, i810_misc.minor);  	dev->name   = I810_NAME; -   	printk("doing mem init\n"); +   	DRM_DEBUG("doing mem init\n");  	drm_mem_init(); -	printk("doing proc init\n"); +	DRM_DEBUG("doing proc init\n");  	drm_proc_init(dev); -	printk("doing agp init\n"); +	DRM_DEBUG("doing agp init\n");  	dev->agp    = drm_agp_init(); -	printk("doing ctxbitmap init\n"); +   	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(); @@ -386,10 +403,6 @@ int i810_init(void)  		i810_takedown(dev);  		return retcode;  	} -#if 0 -	printk("doing i810_dma_init\n"); -	i810_dma_init(dev); -#endif  	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",  		 I810_NAME, @@ -417,7 +430,6 @@ void i810_cleanup(void)  		DRM_INFO("Module unloaded\n");  	}  	drm_ctxbitmap_cleanup(dev); -	i810_dma_cleanup(dev);  	i810_takedown(dev);  	if (dev->agp) {  		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); @@ -484,24 +496,82 @@ int i810_release(struct inode *inode, struct file *filp)  	drm_device_t  *dev    = priv->dev;  	int	      retcode = 0; -	DRM_DEBUG("open_count = %d\n", dev->open_count); -	if (!(retcode = drm_release(inode, filp))) { -		MOD_DEC_USE_COUNT; -		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); -				return -EBUSY; +	DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", +		  current->pid, dev->device, dev->open_count); + +	if (_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 { +	   	/* The lock is required to reclaim buffers */ +	   	DECLARE_WAITQUEUE(entry, current); +	   	add_wait_queue(&dev->lock.lock_queue, &entry); +		for (;;) { +			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); +			current->state = TASK_INTERRUPTIBLE; +			schedule(); +			if (signal_pending(current)) { +				retcode = -ERESTARTSYS; +				break;  			} -			spin_unlock(&dev->count_lock); -			return i810_takedown(dev);  		} -		spin_unlock(&dev->count_lock); +		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); +   	MOD_DEC_USE_COUNT; +   	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); +		   	return -EBUSY; +		} +	   	spin_unlock(&dev->count_lock); +	   	return i810_takedown(dev);  	} +   	spin_unlock(&dev->count_lock);  	return retcode;  } @@ -566,8 +636,7 @@ int i810_unlock(struct inode *inode, struct file *filp, unsigned int cmd,  	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); -	i810_dma_schedule(dev, 1); +   	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)) { diff --git a/linux-core/i810_drv.h b/linux-core/i810_drv.h index 0f5f42bb..1badd36b 100644 --- a/linux-core/i810_drv.h +++ b/linux-core/i810_drv.h @@ -32,6 +32,31 @@  #ifndef _I810_DRV_H_  #define _I810_DRV_H_ +typedef struct _drm_i810_ring_buffer{ +	int tail_mask; +	unsigned long Start; +	unsigned long End; +	unsigned long Size; +	u8 *virtual_start; +	int head; +	int tail; +	int space; +} drm_i810_ring_buffer_t; + +typedef struct drm_i810_private { +   	int ring_map_idx; +   	int buffer_map_idx; + +   	drm_i810_ring_buffer_t ring; +	drm_i810_sarea_t *sarea_priv; + +      	unsigned long hw_status_page; +   	unsigned long counter; + +   	atomic_t flush_done; +   	wait_queue_head_t flush_queue;	/* Processes waiting until flush    */ +} drm_i810_private_t; +  				/* i810_drv.c */  extern int  i810_init(void);  extern void i810_cleanup(void); @@ -54,8 +79,13 @@ extern int  i810_control(struct inode *inode, struct file *filp,  			  unsigned int cmd, unsigned long arg);  extern int  i810_lock(struct inode *inode, struct file *filp,  		       unsigned int cmd, unsigned long arg); -extern void i810_dma_init(drm_device_t *dev); -extern void i810_dma_cleanup(drm_device_t *dev); +extern int  i810_dma_init(struct inode *inode, struct file *filp, +			  unsigned int cmd, unsigned long arg); +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);  				/* i810_bufs.c */ @@ -72,5 +102,103 @@ extern int  i810_mapbufs(struct inode *inode, struct file *filp,  extern int  i810_addmap(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); + + + + +/* Copy the outstanding cliprects for every I810_DMA_VERTEX buffer. + * This can be fixed by emitting directly to the ringbuffer in the + * 'vertex_dma' ioctl.   +*/ +typedef struct { +   	u32 *in_use; +   	int my_use_idx; +} drm_i810_buf_priv_t; + + +#define I810_DMA_GENERAL 0 +#define I810_DMA_VERTEX  1 +#define I810_DMA_DISCARD 2	/* not used */ + +#define I810_VERBOSE 0 + + +int i810_dma_vertex(struct inode *inode, struct file *filp, +		    unsigned int cmd, unsigned long arg); + +int i810_dma_general(struct inode *inode, struct file *filp, +		     unsigned int cmd, unsigned long arg); + + +#define GFX_OP_USER_INTERRUPT 		((0<<29)|(2<<23)) +#define GFX_OP_BREAKPOINT_INTERRUPT	((0<<29)|(1<<23)) +#define CMD_REPORT_HEAD			(7<<23) +#define CMD_STORE_DWORD_IDX		((0x21<<23) | 0x1) +#define CMD_OP_BATCH_BUFFER  ((0x0<<29)|(0x30<<23)|0x1) + +#define INST_PARSER_CLIENT   0x00000000 +#define INST_OP_FLUSH        0x02000000 +#define INST_FLUSH_MAP_CACHE 0x00000001 + + +#define BB1_START_ADDR_MASK   (~0x7) +#define BB1_PROTECTED         (1<<0) +#define BB1_UNPROTECTED       (0<<0) +#define BB2_END_ADDR_MASK     (~0x7) + +#define I810REG_HWSTAM		0x02098 +#define I810REG_INT_IDENTITY_R	0x020a4 +#define I810REG_INT_MASK_R 	0x020a8 +#define I810REG_INT_ENABLE_R	0x020a0 + +#define LP_RING     		0x2030 +#define HP_RING     		0x2040 +#define RING_TAIL      		0x00 +#define TAIL_ADDR		0x000FFFF8 +#define RING_HEAD      		0x04 +#define HEAD_WRAP_COUNT     	0xFFE00000 +#define HEAD_WRAP_ONE       	0x00200000 +#define HEAD_ADDR           	0x001FFFFC +#define RING_START     		0x08 +#define START_ADDR          	0x00FFFFF8 +#define RING_LEN       		0x0C +#define RING_NR_PAGES       	0x000FF000  +#define RING_REPORT_MASK    	0x00000006 +#define RING_REPORT_64K     	0x00000002 +#define RING_REPORT_128K    	0x00000004 +#define RING_NO_REPORT      	0x00000000 +#define RING_VALID_MASK     	0x00000001 +#define RING_VALID          	0x00000001 +#define RING_INVALID        	0x00000000 + +#define GFX_OP_SCISSOR         ((0x3<<29)|(0x1c<<24)|(0x10<<19)) +#define SC_UPDATE_SCISSOR       (0x1<<1) +#define SC_ENABLE_MASK          (0x1<<0) +#define SC_ENABLE               (0x1<<0) + +#define GFX_OP_SCISSOR_INFO    ((0x3<<29)|(0x1d<<24)|(0x81<<16)|(0x1)) +#define SCI_YMIN_MASK      (0xffff<<16) +#define SCI_XMIN_MASK      (0xffff<<0) +#define SCI_YMAX_MASK      (0xffff<<16) +#define SCI_XMAX_MASK      (0xffff<<0)  #endif + diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index 8bc25617..48041354 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -54,6 +54,7 @@ static struct file_operations mga_fops = {  	mmap:	 drm_mmap,  	read:	 drm_read,  	fasync:	 drm_fasync, +   	poll:	 drm_poll,  };  static struct miscdevice      mga_misc = { @@ -105,9 +106,11 @@ static drm_ioctl_desc_t	      mga_ioctls[] = {  	[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_clear_bufs,  1, 1 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_CLEAR)]   = { mga_swap_bufs,   1, 1 }, -   	[DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)]   = { mga_iload,       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 },  };  #define MGA_IOCTL_COUNT DRM_ARRAY_SIZE(mga_ioctls) @@ -380,6 +383,21 @@ int mga_init(void)  	drm_proc_init(dev);  	DRM_DEBUG("doing agp init\n");  	dev->agp    = drm_agp_init(); +      	if(dev->agp == NULL) { +	   	DRM_DEBUG("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  	DRM_DEBUG("doing ctxbitmap init\n");  	if((retcode = drm_ctxbitmap_init(dev))) {  		DRM_ERROR("Cannot allocate memory for context bitmap.\n"); @@ -416,6 +434,16 @@ void mga_cleanup(void)  	}  	drm_ctxbitmap_cleanup(dev);  	mga_dma_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_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); diff --git a/linux-core/tdfx_drv.c b/linux-core/tdfx_drv.c index 57c1c719..fb7a997b 100644 --- a/linux-core/tdfx_drv.c +++ b/linux-core/tdfx_drv.c @@ -85,6 +85,16 @@ static drm_ioctl_desc_t	      tdfx_ioctls[] = {  	[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 }, +#ifdef DRM_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, 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) @@ -228,7 +238,24 @@ static int tdfx_takedown(drm_device_t *dev)  		}  		dev->magiclist[i].head = dev->magiclist[i].tail = NULL;  	} -	 +#ifdef DRM_AGP +				/* 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)(); +		drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); +		dev->agp = NULL; +	} +#endif  				/* Clear vma list (only built for debugging) */  	if (dev->vmalist) {  		for (vma = dev->vmalist; vma; vma = vma_next) { @@ -262,6 +289,10 @@ static int tdfx_takedown(drm_device_t *dev)  					       - 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);  		} @@ -309,6 +340,16 @@ int tdfx_init(void)  	drm_mem_init();  	drm_proc_init(dev); +#ifdef DRM_AGP +	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, @@ -335,6 +376,7 @@ void tdfx_cleanup(void)  	} else {  		DRM_INFO("Module unloaded\n");  	} +	drm_ctxbitmap_cleanup(dev);  	tdfx_takedown(dev);  } | 
