diff options
| -rw-r--r-- | libdrm/xf86drm.c | 11 | ||||
| -rw-r--r-- | linux-core/drmP.h | 12 | ||||
| -rw-r--r-- | linux-core/drm_dma.c | 82 | ||||
| -rw-r--r-- | linux-core/drm_drv.c | 4 | ||||
| -rw-r--r-- | linux/drm.h | 15 | ||||
| -rw-r--r-- | linux/drmP.h | 12 | ||||
| -rw-r--r-- | linux/drm_dma.h | 82 | ||||
| -rw-r--r-- | linux/drm_drv.h | 4 | ||||
| -rw-r--r-- | shared-core/drm.h | 15 | ||||
| -rw-r--r-- | shared-core/radeon_drv.h | 15 | ||||
| -rw-r--r-- | shared-core/radeon_irq.c | 102 | ||||
| -rw-r--r-- | shared/drm.h | 15 | ||||
| -rw-r--r-- | shared/radeon.h | 45 | ||||
| -rw-r--r-- | shared/radeon_drv.h | 15 | ||||
| -rw-r--r-- | shared/radeon_irq.c | 102 | 
15 files changed, 409 insertions, 122 deletions
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index d2ce5e1e..8d3a20d1 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -1105,6 +1105,17 @@ int drmScatterGatherFree(int fd, unsigned long handle)      return 0;  } +int drmWaitVBlank(int fd, drmVBlankPtr vbl) +{ +    int ret; + +    do { +       ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); +    } while (ret && errno == EINTR); + +    return ret; +} +  int drmError(int err, const char *label)  {      switch (err) { diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 7d82fce3..6f6f91c4 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -577,6 +577,10 @@ typedef struct drm_device {  	int		  last_context;	/* Last current context		   */  	unsigned long	  last_switch;	/* jiffies at last context switch  */  	struct tq_struct  tq; +#if __HAVE_VBL_IRQ +   	wait_queue_head_t vbl_queue; +   	atomic_t          vbl_received; +#endif  	cycles_t	  ctx_start;  	cycles_t	  lck_start;  #if __HAVE_DMA_HISTOGRAM @@ -809,6 +813,14 @@ extern int           DRM(irq_install)( drm_device_t *dev, int irq );  extern int           DRM(irq_uninstall)( drm_device_t *dev );  extern void          DRM(dma_service)( int irq, void *device,  				       struct pt_regs *regs ); +extern void          DRM(driver_irq_preinstall)( drm_device_t *dev ); +extern void          DRM(driver_irq_postinstall)( drm_device_t *dev ); +extern void          DRM(driver_irq_uninstall)( drm_device_t *dev ); +#if __HAVE_VBL_IRQ +extern int           DRM(wait_vblank)(struct inode *inode, struct file *filp, +				      unsigned int cmd, unsigned long arg); +extern int           DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); +#endif  #if __HAVE_DMA_IRQ_BH  extern void          DRM(dma_immediate_bh)( void *dev );  #endif diff --git a/linux-core/drm_dma.c b/linux-core/drm_dma.c index dce376f6..2938c77a 100644 --- a/linux-core/drm_dma.c +++ b/linux-core/drm_dma.c @@ -538,8 +538,12 @@ int DRM(irq_install)( drm_device_t *dev, int irq )  	dev->tq.data = dev;  #endif +#if __HAVE_VBL_IRQ +	init_waitqueue_head(&dev->vbl_queue); +#endif +  				/* Before installing handler */ -	DRIVER_PREINSTALL(); +	DRM(driver_irq_preinstall)(dev);  				/* Install handler */  	ret = request_irq( dev->irq, DRM(dma_service), @@ -552,7 +556,7 @@ int DRM(irq_install)( drm_device_t *dev, int irq )  	}  				/* After installing handler */ -	DRIVER_POSTINSTALL(); +	DRM(driver_irq_postinstall)(dev);  	return 0;  } @@ -571,7 +575,7 @@ int DRM(irq_uninstall)( drm_device_t *dev )  	DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); -	DRIVER_UNINSTALL(); +	DRM(driver_irq_uninstall)( dev );  	free_irq( irq, dev ); @@ -598,6 +602,78 @@ int DRM(control)( struct inode *inode, struct file *filp,  	}  } +#if __HAVE_VBL_IRQ + +int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence) +{ +  	drm_radeon_private_t *dev_priv =  +	   (drm_radeon_private_t *)dev->dev_private; +	unsigned int cur_vblank; +	int ret = 0; + +	if ( !dev_priv ) { +		DRM_ERROR( "%s called with no initialization\n", __func__ ); +		return DRM_ERR(EINVAL); +	} + +	/* Assume that the user has missed the current sequence number by about +	 * a day rather than she wants to wait for years using vertical blanks :) +	 */ +	while ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) ) +		+ ~*sequence + 1 ) > (1<<23) ) { +		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; +#ifdef __linux__ +		interruptible_sleep_on( &dev->vbl_queue ); + +		if (signal_pending(current)) { +			ret = -EINTR; +			break; +		} +#endif /* __linux__ */ +#ifdef __FreeBSD__ +		ret = tsleep( &dev_priv->vbl_queue, 3*hz, "rdnvbl", PZERO | PCATCH); +		if (ret) +			break; +#endif /* __FreeBSD__ */ +	} + +	*sequence = cur_vblank; + +	return ret; +} + +int DRM(wait_vblank)( DRM_IOCTL_ARGS ) +{ +	drm_file_t *priv = filp->private_data; +	drm_device_t *dev = priv->dev; +	drm_wait_vblank_t vblwait; +	struct timeval now; +	int ret; + +	if (!dev->irq) +		return -EINVAL; + +	DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data, +				  sizeof(vblwait) ); + +	if ( vblwait.type == _DRM_VBLANK_RELATIVE ) { +		vblwait.sequence += atomic_read( &dev->vbl_received ); +	} + +	ret = DRM(vblank_wait)( dev, &vblwait.sequence ); + +	do_gettimeofday( &now ); +	vblwait.tval_sec = now.tv_sec; +	vblwait.tval_usec = now.tv_usec; + +	DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait, +				sizeof(vblwait) ); + +	return ret; +} + +#endif	/* __HAVE_VBL_IRQ */ +  #else  int DRM(control)( struct inode *inode, struct file *filp, diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 7e2cfd8c..3ebe7811 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -222,6 +222,10 @@ static drm_ioctl_desc_t		  DRM(ioctls)[] = {  	[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)]       = { DRM(sg_free),     1, 1 },  #endif +#if __HAVE_VBL_IRQ +	[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)]   = { DRM(wait_vblank), 0, 0 }, +#endif +  	DRIVER_IOCTLS  }; diff --git a/linux/drm.h b/linux/drm.h index 376568e0..f26d4442 100644 --- a/linux/drm.h +++ b/linux/drm.h @@ -345,6 +345,19 @@ typedef struct drm_irq_busid {  	int funcnum;  } drm_irq_busid_t; +typedef enum { +    _DRM_VBLANK_ABSOLUTE = 0x0,	/* Wait for specific vblank sequence number */ +    _DRM_VBLANK_RELATIVE = 0x1	/* Wait for given number of vblanks */ +} drm_vblank_seq_type_t; + +typedef struct drm_radeon_vbl_wait { +	drm_vblank_seq_type_t type; +	unsigned int sequence; +	long tval_sec; +	long tval_usec; +} drm_wait_vblank_t; + +  typedef struct drm_agp_mode {  	unsigned long mode;  } drm_agp_mode_t; @@ -439,6 +452,8 @@ typedef struct drm_scatter_gather {  #define DRM_IOCTL_SG_ALLOC		DRM_IOW( 0x38, drm_scatter_gather_t)  #define DRM_IOCTL_SG_FREE		DRM_IOW( 0x39, drm_scatter_gather_t) +#define DRM_IOCTL_WAIT_VBLANK		DRM_IOWR(0x3a, drm_wait_vblank_t) +  /* Device specfic ioctls should only be in their respective headers   * The device specific ioctl range is 0x40 to 0x79.                  */  #define DRM_COMMAND_BASE                0x40 diff --git a/linux/drmP.h b/linux/drmP.h index 7d82fce3..6f6f91c4 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -577,6 +577,10 @@ typedef struct drm_device {  	int		  last_context;	/* Last current context		   */  	unsigned long	  last_switch;	/* jiffies at last context switch  */  	struct tq_struct  tq; +#if __HAVE_VBL_IRQ +   	wait_queue_head_t vbl_queue; +   	atomic_t          vbl_received; +#endif  	cycles_t	  ctx_start;  	cycles_t	  lck_start;  #if __HAVE_DMA_HISTOGRAM @@ -809,6 +813,14 @@ extern int           DRM(irq_install)( drm_device_t *dev, int irq );  extern int           DRM(irq_uninstall)( drm_device_t *dev );  extern void          DRM(dma_service)( int irq, void *device,  				       struct pt_regs *regs ); +extern void          DRM(driver_irq_preinstall)( drm_device_t *dev ); +extern void          DRM(driver_irq_postinstall)( drm_device_t *dev ); +extern void          DRM(driver_irq_uninstall)( drm_device_t *dev ); +#if __HAVE_VBL_IRQ +extern int           DRM(wait_vblank)(struct inode *inode, struct file *filp, +				      unsigned int cmd, unsigned long arg); +extern int           DRM(vblank_wait)(drm_device_t *dev, unsigned int *vbl_seq); +#endif  #if __HAVE_DMA_IRQ_BH  extern void          DRM(dma_immediate_bh)( void *dev );  #endif diff --git a/linux/drm_dma.h b/linux/drm_dma.h index dce376f6..2938c77a 100644 --- a/linux/drm_dma.h +++ b/linux/drm_dma.h @@ -538,8 +538,12 @@ int DRM(irq_install)( drm_device_t *dev, int irq )  	dev->tq.data = dev;  #endif +#if __HAVE_VBL_IRQ +	init_waitqueue_head(&dev->vbl_queue); +#endif +  				/* Before installing handler */ -	DRIVER_PREINSTALL(); +	DRM(driver_irq_preinstall)(dev);  				/* Install handler */  	ret = request_irq( dev->irq, DRM(dma_service), @@ -552,7 +556,7 @@ int DRM(irq_install)( drm_device_t *dev, int irq )  	}  				/* After installing handler */ -	DRIVER_POSTINSTALL(); +	DRM(driver_irq_postinstall)(dev);  	return 0;  } @@ -571,7 +575,7 @@ int DRM(irq_uninstall)( drm_device_t *dev )  	DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq ); -	DRIVER_UNINSTALL(); +	DRM(driver_irq_uninstall)( dev );  	free_irq( irq, dev ); @@ -598,6 +602,78 @@ int DRM(control)( struct inode *inode, struct file *filp,  	}  } +#if __HAVE_VBL_IRQ + +int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence) +{ +  	drm_radeon_private_t *dev_priv =  +	   (drm_radeon_private_t *)dev->dev_private; +	unsigned int cur_vblank; +	int ret = 0; + +	if ( !dev_priv ) { +		DRM_ERROR( "%s called with no initialization\n", __func__ ); +		return DRM_ERR(EINVAL); +	} + +	/* Assume that the user has missed the current sequence number by about +	 * a day rather than she wants to wait for years using vertical blanks :) +	 */ +	while ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) ) +		+ ~*sequence + 1 ) > (1<<23) ) { +		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; +#ifdef __linux__ +		interruptible_sleep_on( &dev->vbl_queue ); + +		if (signal_pending(current)) { +			ret = -EINTR; +			break; +		} +#endif /* __linux__ */ +#ifdef __FreeBSD__ +		ret = tsleep( &dev_priv->vbl_queue, 3*hz, "rdnvbl", PZERO | PCATCH); +		if (ret) +			break; +#endif /* __FreeBSD__ */ +	} + +	*sequence = cur_vblank; + +	return ret; +} + +int DRM(wait_vblank)( DRM_IOCTL_ARGS ) +{ +	drm_file_t *priv = filp->private_data; +	drm_device_t *dev = priv->dev; +	drm_wait_vblank_t vblwait; +	struct timeval now; +	int ret; + +	if (!dev->irq) +		return -EINVAL; + +	DRM_COPY_FROM_USER_IOCTL( vblwait, (drm_wait_vblank_t *)data, +				  sizeof(vblwait) ); + +	if ( vblwait.type == _DRM_VBLANK_RELATIVE ) { +		vblwait.sequence += atomic_read( &dev->vbl_received ); +	} + +	ret = DRM(vblank_wait)( dev, &vblwait.sequence ); + +	do_gettimeofday( &now ); +	vblwait.tval_sec = now.tv_sec; +	vblwait.tval_usec = now.tv_usec; + +	DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait, +				sizeof(vblwait) ); + +	return ret; +} + +#endif	/* __HAVE_VBL_IRQ */ +  #else  int DRM(control)( struct inode *inode, struct file *filp, diff --git a/linux/drm_drv.h b/linux/drm_drv.h index 7e2cfd8c..3ebe7811 100644 --- a/linux/drm_drv.h +++ b/linux/drm_drv.h @@ -222,6 +222,10 @@ static drm_ioctl_desc_t		  DRM(ioctls)[] = {  	[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)]       = { DRM(sg_free),     1, 1 },  #endif +#if __HAVE_VBL_IRQ +	[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)]   = { DRM(wait_vblank), 0, 0 }, +#endif +  	DRIVER_IOCTLS  }; diff --git a/shared-core/drm.h b/shared-core/drm.h index 376568e0..f26d4442 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -345,6 +345,19 @@ typedef struct drm_irq_busid {  	int funcnum;  } drm_irq_busid_t; +typedef enum { +    _DRM_VBLANK_ABSOLUTE = 0x0,	/* Wait for specific vblank sequence number */ +    _DRM_VBLANK_RELATIVE = 0x1	/* Wait for given number of vblanks */ +} drm_vblank_seq_type_t; + +typedef struct drm_radeon_vbl_wait { +	drm_vblank_seq_type_t type; +	unsigned int sequence; +	long tval_sec; +	long tval_usec; +} drm_wait_vblank_t; + +  typedef struct drm_agp_mode {  	unsigned long mode;  } drm_agp_mode_t; @@ -439,6 +452,8 @@ typedef struct drm_scatter_gather {  #define DRM_IOCTL_SG_ALLOC		DRM_IOW( 0x38, drm_scatter_gather_t)  #define DRM_IOCTL_SG_FREE		DRM_IOW( 0x39, drm_scatter_gather_t) +#define DRM_IOCTL_WAIT_VBLANK		DRM_IOWR(0x3a, drm_wait_vblank_t) +  /* Device specfic ioctls should only be in their respective headers   * The device specific ioctl range is 0x40 to 0x79.                  */  #define DRM_COMMAND_BASE                0x40 diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index efe3020c..5c43ebc6 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -139,9 +139,10 @@ typedef struct drm_radeon_private {  	struct mem_block *agp_heap;  	struct mem_block *fb_heap; -   	wait_queue_head_t irq_queue; -   	atomic_t irq_received; -   	atomic_t irq_emitted; +	/* SW interrupt */ +   	wait_queue_head_t swi_queue; +   	atomic_t swi_received; +   	atomic_t swi_emitted;  } drm_radeon_private_t; @@ -187,12 +188,14 @@ extern int radeon_mem_init_heap( DRM_IOCTL_ARGS );  extern void radeon_mem_takedown( struct mem_block **heap );  extern void radeon_mem_release( struct mem_block *heap ); +				/* radeon_irq.c */  extern int radeon_irq_emit( DRM_IOCTL_ARGS );  extern int radeon_irq_wait( DRM_IOCTL_ARGS );  extern int radeon_emit_and_wait_irq(drm_device_t *dev); -extern int radeon_wait_irq(drm_device_t *dev, int irq_nr); +extern int radeon_wait_irq(drm_device_t *dev, int swi_nr);  extern int radeon_emit_irq(drm_device_t *dev); +extern int radeon_vblank_wait(drm_device_t *dev, unsigned int *vbl_seq);  /* Flags for stats.boxes @@ -271,11 +274,15 @@ extern int radeon_emit_irq(drm_device_t *dev);  #define RADEON_GEN_INT_CNTL		0x0040 +#	define RADEON_CRTC_VBLANK_MASK		(1 << 0)  #	define RADEON_GUI_IDLE_INT_ENABLE	(1 << 19)  #	define RADEON_SW_INT_ENABLE		(1 << 25)  #define RADEON_GEN_INT_STATUS		0x0044 +#	define RADEON_CRTC_VBLANK_STAT		(1 << 0) +#	define RADEON_CRTC_VBLANK_STAT_ACK   	(1 << 0)  #	define RADEON_GUI_IDLE_INT_TEST_ACK     (1 << 19) +#	define RADEON_SW_INT_TEST		(1 << 25)  #	define RADEON_SW_INT_TEST_ACK   	(1 << 25)  #	define RADEON_SW_INT_FIRE		(1 << 26) diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c index 11609393..7b170389 100644 --- a/shared-core/radeon_irq.c +++ b/shared-core/radeon_irq.c @@ -1,4 +1,4 @@ -/* radeon_mem.c -- Simple agp/fb memory manager for radeon -*- linux-c -*- +/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*-   *   * Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.   *  @@ -58,46 +58,47 @@ void DRM(dma_service)( DRM_IRQ_ARGS )  	drm_device_t *dev = (drm_device_t *) arg;  	drm_radeon_private_t *dev_priv =   	   (drm_radeon_private_t *)dev->dev_private; -   	u32 temp; +   	u32 stat, ack = 0;  	/* Need to wait for fifo to drain?  	 */ -	temp = RADEON_READ(RADEON_GEN_INT_STATUS);   -	temp = temp & RADEON_SW_INT_TEST_ACK;   -	if (temp == 0) return;   -	RADEON_WRITE(RADEON_GEN_INT_STATUS, temp);   +	stat = RADEON_READ(RADEON_GEN_INT_STATUS); -	atomic_inc(&dev_priv->irq_received); +	/* SW interrupt */ +	if (stat & RADEON_SW_INT_TEST) { +		ack |= RADEON_SW_INT_TEST_ACK; +		atomic_inc(&dev_priv->swi_received);  #ifdef __linux__ -	queue_task(&dev->tq, &tq_immediate);   -	mark_bh(IMMEDIATE_BH);   -#endif /* __linux__ */ +		wake_up_interruptible(&dev_priv->swi_queue); +#endif  #ifdef __FreeBSD__ -	taskqueue_enqueue(taskqueue_swi, &dev->task); -#endif /* __FreeBSD__ */ -} - -void DRM(dma_immediate_bh)( DRM_TASKQUEUE_ARGS ) -{ -	drm_device_t *dev = (drm_device_t *) arg; -	drm_radeon_private_t *dev_priv =  -	   (drm_radeon_private_t *)dev->dev_private; +		wakeup(&dev->vbl_queue); +#endif +	} +	/* VBLANK interrupt */ +	if (stat & RADEON_CRTC_VBLANK_STAT) { +		ack |= RADEON_CRTC_VBLANK_STAT_ACK; +		atomic_inc(&dev->vbl_received);  #ifdef __linux__ -	wake_up_interruptible(&dev_priv->irq_queue);  -#endif /* __linux__ */ +		wake_up_interruptible(&dev->vbl_queue); +#endif  #ifdef __FreeBSD__ -	wakeup( &dev_priv->irq_queue ); +		wakeup(&dev->vbl_queue);  #endif -} +	} +	if (ack) +		RADEON_WRITE(RADEON_GEN_INT_STATUS, ack); +} +   int radeon_emit_irq(drm_device_t *dev)  {  	drm_radeon_private_t *dev_priv = dev->dev_private;  	RING_LOCALS; -	atomic_inc(&dev_priv->irq_emitted); +	atomic_inc(&dev_priv->swi_emitted);  	BEGIN_RING(2);   	OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) ); @@ -105,11 +106,11 @@ int radeon_emit_irq(drm_device_t *dev)  	ADVANCE_RING();    	COMMIT_RING(); -	return atomic_read(&dev_priv->irq_emitted); +	return atomic_read(&dev_priv->swi_emitted);  } -int radeon_wait_irq(drm_device_t *dev, int irq_nr) +int radeon_wait_irq(drm_device_t *dev, int swi_nr)  {    	drm_radeon_private_t *dev_priv =   	   (drm_radeon_private_t *)dev->dev_private; @@ -119,17 +120,17 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)  #endif /* __linux__ */  	int ret = 0; - 	if (atomic_read(&dev_priv->irq_received) >= irq_nr)   + 	if (atomic_read(&dev_priv->swi_received) >= swi_nr)     		return 0;   	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;  #ifdef __linux__ -	add_wait_queue(&dev_priv->irq_queue, &entry); +	add_wait_queue(&dev_priv->swi_queue, &entry);  	for (;;) {  		current->state = TASK_INTERRUPTIBLE; -	   	if (atomic_read(&dev_priv->irq_received) >= irq_nr)  +	   	if (atomic_read(&dev_priv->swi_received) >= swi_nr)   		   break;  		if((signed)(end - jiffies) <= 0) {  		   	ret = -EBUSY;	/* Lockup?  Missed irq? */ @@ -143,12 +144,12 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)  	}  	current->state = TASK_RUNNING; -	remove_wait_queue(&dev_priv->irq_queue, &entry); +	remove_wait_queue(&dev_priv->swi_queue, &entry);  	return ret;  #endif /* __linux__ */  #ifdef __FreeBSD__ -	ret = tsleep( &dev_priv->irq_queue, PZERO | PCATCH, \ +	ret = tsleep( &dev_priv->swi_queue, PZERO | PCATCH, \  		"rdnirq", 3*hz );  	if ( (ret == EWOULDBLOCK) || (ret == EINTR) )  		return DRM_ERR(EBUSY); @@ -156,7 +157,6 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)  #endif /* __FreeBSD__ */  } -  int radeon_emit_and_wait_irq(drm_device_t *dev)  {  	return radeon_wait_irq( dev, radeon_emit_irq(dev) ); @@ -212,3 +212,41 @@ int radeon_irq_wait( DRM_IOCTL_ARGS )  	return radeon_wait_irq( dev, irqwait.irq_seq );  } +  +void DRM(driver_irq_preinstall)( drm_device_t *dev ) { +	drm_radeon_private_t *dev_priv = +		(drm_radeon_private_t *)dev->dev_private; +	u32 tmp; + + 	/* Disable *all* interrupts */ +      	RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); + +	/* Clear bits if they're already high */ +   	tmp = RADEON_READ( RADEON_GEN_INT_STATUS ); +   	RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp ); +} + +void DRM(driver_irq_postinstall)( drm_device_t *dev ) { +	drm_radeon_private_t *dev_priv = +		(drm_radeon_private_t *)dev->dev_private; + +   	atomic_set(&dev_priv->swi_received, 0); +   	atomic_set(&dev_priv->swi_emitted, 0); +#ifdef __linux__ +	init_waitqueue_head(&dev_priv->swi_queue); +#endif + +	/* Turn on SW and VBL ints */ +   	RADEON_WRITE( RADEON_GEN_INT_CNTL, +		      RADEON_CRTC_VBLANK_MASK |	 +		      RADEON_SW_INT_ENABLE ); +} + +void DRM(driver_irq_uninstall)( drm_device_t *dev ) { +	drm_radeon_private_t *dev_priv = +		(drm_radeon_private_t *)dev->dev_private; +	if ( dev_priv ) { +		/* Disable *all* interrupts */ +		RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); +	} +} diff --git a/shared/drm.h b/shared/drm.h index 376568e0..f26d4442 100644 --- a/shared/drm.h +++ b/shared/drm.h @@ -345,6 +345,19 @@ typedef struct drm_irq_busid {  	int funcnum;  } drm_irq_busid_t; +typedef enum { +    _DRM_VBLANK_ABSOLUTE = 0x0,	/* Wait for specific vblank sequence number */ +    _DRM_VBLANK_RELATIVE = 0x1	/* Wait for given number of vblanks */ +} drm_vblank_seq_type_t; + +typedef struct drm_radeon_vbl_wait { +	drm_vblank_seq_type_t type; +	unsigned int sequence; +	long tval_sec; +	long tval_usec; +} drm_wait_vblank_t; + +  typedef struct drm_agp_mode {  	unsigned long mode;  } drm_agp_mode_t; @@ -439,6 +452,8 @@ typedef struct drm_scatter_gather {  #define DRM_IOCTL_SG_ALLOC		DRM_IOW( 0x38, drm_scatter_gather_t)  #define DRM_IOCTL_SG_FREE		DRM_IOW( 0x39, drm_scatter_gather_t) +#define DRM_IOCTL_WAIT_VBLANK		DRM_IOWR(0x3a, drm_wait_vblank_t) +  /* Device specfic ioctls should only be in their respective headers   * The device specific ioctl range is 0x40 to 0x79.                  */  #define DRM_COMMAND_BASE                0x40 diff --git a/shared/radeon.h b/shared/radeon.h index 4cb00986..aa613c40 100644 --- a/shared/radeon.h +++ b/shared/radeon.h @@ -132,53 +132,10 @@   */  #define __HAVE_DMA		1 -  #define __HAVE_DMA_IRQ		1 -#define __HAVE_DMA_IRQ_BH	1  +#define __HAVE_VBL_IRQ		1  #define __HAVE_SHARED_IRQ       1 -#define DRIVER_PREINSTALL() do {				\ -	drm_radeon_private_t *dev_priv =			\ -		(drm_radeon_private_t *)dev->dev_private;	\ -	u32 tmp;						\ -								\ -	/* Clear bit if it's already high: */			\ -   	tmp = RADEON_READ( RADEON_GEN_INT_STATUS );		\ -   	tmp = tmp & RADEON_SW_INT_TEST_ACK;			\ -   	RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );		\ -								\ - 	/* Disable *all* interrupts */				\ -      	RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );			\ -} while (0) - -#ifdef __linux__  -#define IWH(x) init_waitqueue_head(x)  -#else  -#define IWH(x)  -#endif  - -#define DRIVER_POSTINSTALL() do {				\ -	drm_radeon_private_t *dev_priv =			\ -		(drm_radeon_private_t *)dev->dev_private;	\ -								\ -   	atomic_set(&dev_priv->irq_received, 0);			\ -   	atomic_set(&dev_priv->irq_emitted, 0);			\ -	IWH(&dev_priv->irq_queue);		\ -								\ -	/* Turn on SW_INT only */				\ -   	RADEON_WRITE( RADEON_GEN_INT_CNTL,			\ -		      RADEON_SW_INT_ENABLE );			\ -} while (0) - -#define DRIVER_UNINSTALL() do {					\ -	drm_radeon_private_t *dev_priv =			\ -		(drm_radeon_private_t *)dev->dev_private;	\ -	if ( dev_priv ) {					\ -		/* Disable *all* interrupts */			\ -		RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );		\ -	}							\ -} while (0) -  /* Buffer customization:   */  #define DRIVER_BUF_PRIV_T	drm_radeon_buf_priv_t diff --git a/shared/radeon_drv.h b/shared/radeon_drv.h index efe3020c..5c43ebc6 100644 --- a/shared/radeon_drv.h +++ b/shared/radeon_drv.h @@ -139,9 +139,10 @@ typedef struct drm_radeon_private {  	struct mem_block *agp_heap;  	struct mem_block *fb_heap; -   	wait_queue_head_t irq_queue; -   	atomic_t irq_received; -   	atomic_t irq_emitted; +	/* SW interrupt */ +   	wait_queue_head_t swi_queue; +   	atomic_t swi_received; +   	atomic_t swi_emitted;  } drm_radeon_private_t; @@ -187,12 +188,14 @@ extern int radeon_mem_init_heap( DRM_IOCTL_ARGS );  extern void radeon_mem_takedown( struct mem_block **heap );  extern void radeon_mem_release( struct mem_block *heap ); +				/* radeon_irq.c */  extern int radeon_irq_emit( DRM_IOCTL_ARGS );  extern int radeon_irq_wait( DRM_IOCTL_ARGS );  extern int radeon_emit_and_wait_irq(drm_device_t *dev); -extern int radeon_wait_irq(drm_device_t *dev, int irq_nr); +extern int radeon_wait_irq(drm_device_t *dev, int swi_nr);  extern int radeon_emit_irq(drm_device_t *dev); +extern int radeon_vblank_wait(drm_device_t *dev, unsigned int *vbl_seq);  /* Flags for stats.boxes @@ -271,11 +274,15 @@ extern int radeon_emit_irq(drm_device_t *dev);  #define RADEON_GEN_INT_CNTL		0x0040 +#	define RADEON_CRTC_VBLANK_MASK		(1 << 0)  #	define RADEON_GUI_IDLE_INT_ENABLE	(1 << 19)  #	define RADEON_SW_INT_ENABLE		(1 << 25)  #define RADEON_GEN_INT_STATUS		0x0044 +#	define RADEON_CRTC_VBLANK_STAT		(1 << 0) +#	define RADEON_CRTC_VBLANK_STAT_ACK   	(1 << 0)  #	define RADEON_GUI_IDLE_INT_TEST_ACK     (1 << 19) +#	define RADEON_SW_INT_TEST		(1 << 25)  #	define RADEON_SW_INT_TEST_ACK   	(1 << 25)  #	define RADEON_SW_INT_FIRE		(1 << 26) diff --git a/shared/radeon_irq.c b/shared/radeon_irq.c index 11609393..7b170389 100644 --- a/shared/radeon_irq.c +++ b/shared/radeon_irq.c @@ -1,4 +1,4 @@ -/* radeon_mem.c -- Simple agp/fb memory manager for radeon -*- linux-c -*- +/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*-   *   * Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.   *  @@ -58,46 +58,47 @@ void DRM(dma_service)( DRM_IRQ_ARGS )  	drm_device_t *dev = (drm_device_t *) arg;  	drm_radeon_private_t *dev_priv =   	   (drm_radeon_private_t *)dev->dev_private; -   	u32 temp; +   	u32 stat, ack = 0;  	/* Need to wait for fifo to drain?  	 */ -	temp = RADEON_READ(RADEON_GEN_INT_STATUS);   -	temp = temp & RADEON_SW_INT_TEST_ACK;   -	if (temp == 0) return;   -	RADEON_WRITE(RADEON_GEN_INT_STATUS, temp);   +	stat = RADEON_READ(RADEON_GEN_INT_STATUS); -	atomic_inc(&dev_priv->irq_received); +	/* SW interrupt */ +	if (stat & RADEON_SW_INT_TEST) { +		ack |= RADEON_SW_INT_TEST_ACK; +		atomic_inc(&dev_priv->swi_received);  #ifdef __linux__ -	queue_task(&dev->tq, &tq_immediate);   -	mark_bh(IMMEDIATE_BH);   -#endif /* __linux__ */ +		wake_up_interruptible(&dev_priv->swi_queue); +#endif  #ifdef __FreeBSD__ -	taskqueue_enqueue(taskqueue_swi, &dev->task); -#endif /* __FreeBSD__ */ -} - -void DRM(dma_immediate_bh)( DRM_TASKQUEUE_ARGS ) -{ -	drm_device_t *dev = (drm_device_t *) arg; -	drm_radeon_private_t *dev_priv =  -	   (drm_radeon_private_t *)dev->dev_private; +		wakeup(&dev->vbl_queue); +#endif +	} +	/* VBLANK interrupt */ +	if (stat & RADEON_CRTC_VBLANK_STAT) { +		ack |= RADEON_CRTC_VBLANK_STAT_ACK; +		atomic_inc(&dev->vbl_received);  #ifdef __linux__ -	wake_up_interruptible(&dev_priv->irq_queue);  -#endif /* __linux__ */ +		wake_up_interruptible(&dev->vbl_queue); +#endif  #ifdef __FreeBSD__ -	wakeup( &dev_priv->irq_queue ); +		wakeup(&dev->vbl_queue);  #endif -} +	} +	if (ack) +		RADEON_WRITE(RADEON_GEN_INT_STATUS, ack); +} +   int radeon_emit_irq(drm_device_t *dev)  {  	drm_radeon_private_t *dev_priv = dev->dev_private;  	RING_LOCALS; -	atomic_inc(&dev_priv->irq_emitted); +	atomic_inc(&dev_priv->swi_emitted);  	BEGIN_RING(2);   	OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) ); @@ -105,11 +106,11 @@ int radeon_emit_irq(drm_device_t *dev)  	ADVANCE_RING();    	COMMIT_RING(); -	return atomic_read(&dev_priv->irq_emitted); +	return atomic_read(&dev_priv->swi_emitted);  } -int radeon_wait_irq(drm_device_t *dev, int irq_nr) +int radeon_wait_irq(drm_device_t *dev, int swi_nr)  {    	drm_radeon_private_t *dev_priv =   	   (drm_radeon_private_t *)dev->dev_private; @@ -119,17 +120,17 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)  #endif /* __linux__ */  	int ret = 0; - 	if (atomic_read(&dev_priv->irq_received) >= irq_nr)   + 	if (atomic_read(&dev_priv->swi_received) >= swi_nr)     		return 0;   	dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;  #ifdef __linux__ -	add_wait_queue(&dev_priv->irq_queue, &entry); +	add_wait_queue(&dev_priv->swi_queue, &entry);  	for (;;) {  		current->state = TASK_INTERRUPTIBLE; -	   	if (atomic_read(&dev_priv->irq_received) >= irq_nr)  +	   	if (atomic_read(&dev_priv->swi_received) >= swi_nr)   		   break;  		if((signed)(end - jiffies) <= 0) {  		   	ret = -EBUSY;	/* Lockup?  Missed irq? */ @@ -143,12 +144,12 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)  	}  	current->state = TASK_RUNNING; -	remove_wait_queue(&dev_priv->irq_queue, &entry); +	remove_wait_queue(&dev_priv->swi_queue, &entry);  	return ret;  #endif /* __linux__ */  #ifdef __FreeBSD__ -	ret = tsleep( &dev_priv->irq_queue, PZERO | PCATCH, \ +	ret = tsleep( &dev_priv->swi_queue, PZERO | PCATCH, \  		"rdnirq", 3*hz );  	if ( (ret == EWOULDBLOCK) || (ret == EINTR) )  		return DRM_ERR(EBUSY); @@ -156,7 +157,6 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)  #endif /* __FreeBSD__ */  } -  int radeon_emit_and_wait_irq(drm_device_t *dev)  {  	return radeon_wait_irq( dev, radeon_emit_irq(dev) ); @@ -212,3 +212,41 @@ int radeon_irq_wait( DRM_IOCTL_ARGS )  	return radeon_wait_irq( dev, irqwait.irq_seq );  } +  +void DRM(driver_irq_preinstall)( drm_device_t *dev ) { +	drm_radeon_private_t *dev_priv = +		(drm_radeon_private_t *)dev->dev_private; +	u32 tmp; + + 	/* Disable *all* interrupts */ +      	RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); + +	/* Clear bits if they're already high */ +   	tmp = RADEON_READ( RADEON_GEN_INT_STATUS ); +   	RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp ); +} + +void DRM(driver_irq_postinstall)( drm_device_t *dev ) { +	drm_radeon_private_t *dev_priv = +		(drm_radeon_private_t *)dev->dev_private; + +   	atomic_set(&dev_priv->swi_received, 0); +   	atomic_set(&dev_priv->swi_emitted, 0); +#ifdef __linux__ +	init_waitqueue_head(&dev_priv->swi_queue); +#endif + +	/* Turn on SW and VBL ints */ +   	RADEON_WRITE( RADEON_GEN_INT_CNTL, +		      RADEON_CRTC_VBLANK_MASK |	 +		      RADEON_SW_INT_ENABLE ); +} + +void DRM(driver_irq_uninstall)( drm_device_t *dev ) { +	drm_radeon_private_t *dev_priv = +		(drm_radeon_private_t *)dev->dev_private; +	if ( dev_priv ) { +		/* Disable *all* interrupts */ +		RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); +	} +}  | 
