diff options
Diffstat (limited to 'linux')
| -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 | 
4 files changed, 110 insertions, 3 deletions
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  };  | 
