common ioctl to wait for vertical blank IRQs
parent
f1c8fe9557
commit
55acd0d5a6
|
@ -1105,6 +1105,17 @@ int drmScatterGatherFree(int fd, unsigned long handle)
|
||||||
return 0;
|
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)
|
int drmError(int err, const char *label)
|
||||||
{
|
{
|
||||||
switch (err) {
|
switch (err) {
|
||||||
|
|
|
@ -577,6 +577,10 @@ typedef struct drm_device {
|
||||||
int last_context; /* Last current context */
|
int last_context; /* Last current context */
|
||||||
unsigned long last_switch; /* jiffies at last context switch */
|
unsigned long last_switch; /* jiffies at last context switch */
|
||||||
struct tq_struct tq;
|
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 ctx_start;
|
||||||
cycles_t lck_start;
|
cycles_t lck_start;
|
||||||
#if __HAVE_DMA_HISTOGRAM
|
#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 int DRM(irq_uninstall)( drm_device_t *dev );
|
||||||
extern void DRM(dma_service)( int irq, void *device,
|
extern void DRM(dma_service)( int irq, void *device,
|
||||||
struct pt_regs *regs );
|
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
|
#if __HAVE_DMA_IRQ_BH
|
||||||
extern void DRM(dma_immediate_bh)( void *dev );
|
extern void DRM(dma_immediate_bh)( void *dev );
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -538,8 +538,12 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
|
||||||
dev->tq.data = dev;
|
dev->tq.data = dev;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __HAVE_VBL_IRQ
|
||||||
|
init_waitqueue_head(&dev->vbl_queue);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Before installing handler */
|
/* Before installing handler */
|
||||||
DRIVER_PREINSTALL();
|
DRM(driver_irq_preinstall)(dev);
|
||||||
|
|
||||||
/* Install handler */
|
/* Install handler */
|
||||||
ret = request_irq( dev->irq, DRM(dma_service),
|
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 */
|
/* After installing handler */
|
||||||
DRIVER_POSTINSTALL();
|
DRM(driver_irq_postinstall)(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -571,7 +575,7 @@ int DRM(irq_uninstall)( drm_device_t *dev )
|
||||||
|
|
||||||
DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
|
DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
|
||||||
|
|
||||||
DRIVER_UNINSTALL();
|
DRM(driver_irq_uninstall)( dev );
|
||||||
|
|
||||||
free_irq( irq, 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
|
#else
|
||||||
|
|
||||||
int DRM(control)( struct inode *inode, struct file *filp,
|
int DRM(control)( struct inode *inode, struct file *filp,
|
||||||
|
|
|
@ -222,6 +222,10 @@ static drm_ioctl_desc_t DRM(ioctls)[] = {
|
||||||
[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 },
|
[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __HAVE_VBL_IRQ
|
||||||
|
[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { DRM(wait_vblank), 0, 0 },
|
||||||
|
#endif
|
||||||
|
|
||||||
DRIVER_IOCTLS
|
DRIVER_IOCTLS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
15
linux/drm.h
15
linux/drm.h
|
@ -345,6 +345,19 @@ typedef struct drm_irq_busid {
|
||||||
int funcnum;
|
int funcnum;
|
||||||
} drm_irq_busid_t;
|
} 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 {
|
typedef struct drm_agp_mode {
|
||||||
unsigned long mode;
|
unsigned long mode;
|
||||||
} drm_agp_mode_t;
|
} 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_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t)
|
||||||
#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, 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
|
/* Device specfic ioctls should only be in their respective headers
|
||||||
* The device specific ioctl range is 0x40 to 0x79. */
|
* The device specific ioctl range is 0x40 to 0x79. */
|
||||||
#define DRM_COMMAND_BASE 0x40
|
#define DRM_COMMAND_BASE 0x40
|
||||||
|
|
12
linux/drmP.h
12
linux/drmP.h
|
@ -577,6 +577,10 @@ typedef struct drm_device {
|
||||||
int last_context; /* Last current context */
|
int last_context; /* Last current context */
|
||||||
unsigned long last_switch; /* jiffies at last context switch */
|
unsigned long last_switch; /* jiffies at last context switch */
|
||||||
struct tq_struct tq;
|
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 ctx_start;
|
||||||
cycles_t lck_start;
|
cycles_t lck_start;
|
||||||
#if __HAVE_DMA_HISTOGRAM
|
#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 int DRM(irq_uninstall)( drm_device_t *dev );
|
||||||
extern void DRM(dma_service)( int irq, void *device,
|
extern void DRM(dma_service)( int irq, void *device,
|
||||||
struct pt_regs *regs );
|
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
|
#if __HAVE_DMA_IRQ_BH
|
||||||
extern void DRM(dma_immediate_bh)( void *dev );
|
extern void DRM(dma_immediate_bh)( void *dev );
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -538,8 +538,12 @@ int DRM(irq_install)( drm_device_t *dev, int irq )
|
||||||
dev->tq.data = dev;
|
dev->tq.data = dev;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __HAVE_VBL_IRQ
|
||||||
|
init_waitqueue_head(&dev->vbl_queue);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Before installing handler */
|
/* Before installing handler */
|
||||||
DRIVER_PREINSTALL();
|
DRM(driver_irq_preinstall)(dev);
|
||||||
|
|
||||||
/* Install handler */
|
/* Install handler */
|
||||||
ret = request_irq( dev->irq, DRM(dma_service),
|
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 */
|
/* After installing handler */
|
||||||
DRIVER_POSTINSTALL();
|
DRM(driver_irq_postinstall)(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -571,7 +575,7 @@ int DRM(irq_uninstall)( drm_device_t *dev )
|
||||||
|
|
||||||
DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
|
DRM_DEBUG( "%s: irq=%d\n", __FUNCTION__, irq );
|
||||||
|
|
||||||
DRIVER_UNINSTALL();
|
DRM(driver_irq_uninstall)( dev );
|
||||||
|
|
||||||
free_irq( irq, 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
|
#else
|
||||||
|
|
||||||
int DRM(control)( struct inode *inode, struct file *filp,
|
int DRM(control)( struct inode *inode, struct file *filp,
|
||||||
|
|
|
@ -222,6 +222,10 @@ static drm_ioctl_desc_t DRM(ioctls)[] = {
|
||||||
[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 },
|
[DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __HAVE_VBL_IRQ
|
||||||
|
[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = { DRM(wait_vblank), 0, 0 },
|
||||||
|
#endif
|
||||||
|
|
||||||
DRIVER_IOCTLS
|
DRIVER_IOCTLS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -345,6 +345,19 @@ typedef struct drm_irq_busid {
|
||||||
int funcnum;
|
int funcnum;
|
||||||
} drm_irq_busid_t;
|
} 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 {
|
typedef struct drm_agp_mode {
|
||||||
unsigned long mode;
|
unsigned long mode;
|
||||||
} drm_agp_mode_t;
|
} 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_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t)
|
||||||
#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, 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
|
/* Device specfic ioctls should only be in their respective headers
|
||||||
* The device specific ioctl range is 0x40 to 0x79. */
|
* The device specific ioctl range is 0x40 to 0x79. */
|
||||||
#define DRM_COMMAND_BASE 0x40
|
#define DRM_COMMAND_BASE 0x40
|
||||||
|
|
|
@ -139,9 +139,10 @@ typedef struct drm_radeon_private {
|
||||||
struct mem_block *agp_heap;
|
struct mem_block *agp_heap;
|
||||||
struct mem_block *fb_heap;
|
struct mem_block *fb_heap;
|
||||||
|
|
||||||
wait_queue_head_t irq_queue;
|
/* SW interrupt */
|
||||||
atomic_t irq_received;
|
wait_queue_head_t swi_queue;
|
||||||
atomic_t irq_emitted;
|
atomic_t swi_received;
|
||||||
|
atomic_t swi_emitted;
|
||||||
|
|
||||||
} drm_radeon_private_t;
|
} 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_takedown( struct mem_block **heap );
|
||||||
extern void radeon_mem_release( 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_emit( DRM_IOCTL_ARGS );
|
||||||
extern int radeon_irq_wait( 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_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_emit_irq(drm_device_t *dev);
|
||||||
|
extern int radeon_vblank_wait(drm_device_t *dev, unsigned int *vbl_seq);
|
||||||
|
|
||||||
|
|
||||||
/* Flags for stats.boxes
|
/* 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_GEN_INT_CNTL 0x0040
|
||||||
|
# define RADEON_CRTC_VBLANK_MASK (1 << 0)
|
||||||
# define RADEON_GUI_IDLE_INT_ENABLE (1 << 19)
|
# define RADEON_GUI_IDLE_INT_ENABLE (1 << 19)
|
||||||
# define RADEON_SW_INT_ENABLE (1 << 25)
|
# define RADEON_SW_INT_ENABLE (1 << 25)
|
||||||
|
|
||||||
#define RADEON_GEN_INT_STATUS 0x0044
|
#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_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_TEST_ACK (1 << 25)
|
||||||
# define RADEON_SW_INT_FIRE (1 << 26)
|
# define RADEON_SW_INT_FIRE (1 << 26)
|
||||||
|
|
||||||
|
|
|
@ -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.
|
* 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_device_t *dev = (drm_device_t *) arg;
|
||||||
drm_radeon_private_t *dev_priv =
|
drm_radeon_private_t *dev_priv =
|
||||||
(drm_radeon_private_t *)dev->dev_private;
|
(drm_radeon_private_t *)dev->dev_private;
|
||||||
u32 temp;
|
u32 stat, ack = 0;
|
||||||
|
|
||||||
/* Need to wait for fifo to drain?
|
/* Need to wait for fifo to drain?
|
||||||
*/
|
*/
|
||||||
temp = RADEON_READ(RADEON_GEN_INT_STATUS);
|
stat = RADEON_READ(RADEON_GEN_INT_STATUS);
|
||||||
temp = temp & RADEON_SW_INT_TEST_ACK;
|
|
||||||
if (temp == 0) return;
|
|
||||||
RADEON_WRITE(RADEON_GEN_INT_STATUS, temp);
|
|
||||||
|
|
||||||
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__
|
#ifdef __linux__
|
||||||
queue_task(&dev->tq, &tq_immediate);
|
wake_up_interruptible(&dev_priv->swi_queue);
|
||||||
mark_bh(IMMEDIATE_BH);
|
|
||||||
#endif /* __linux__ */
|
|
||||||
#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;
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
wake_up_interruptible(&dev_priv->irq_queue);
|
|
||||||
#endif /* __linux__ */
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
wakeup( &dev_priv->irq_queue );
|
|
||||||
#endif
|
#endif
|
||||||
}
|
#ifdef __FreeBSD__
|
||||||
|
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->vbl_queue);
|
||||||
|
#endif
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
wakeup(&dev->vbl_queue);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ack)
|
||||||
|
RADEON_WRITE(RADEON_GEN_INT_STATUS, ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int radeon_emit_irq(drm_device_t *dev)
|
int radeon_emit_irq(drm_device_t *dev)
|
||||||
{
|
{
|
||||||
drm_radeon_private_t *dev_priv = dev->dev_private;
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
RING_LOCALS;
|
RING_LOCALS;
|
||||||
|
|
||||||
atomic_inc(&dev_priv->irq_emitted);
|
atomic_inc(&dev_priv->swi_emitted);
|
||||||
|
|
||||||
BEGIN_RING(2);
|
BEGIN_RING(2);
|
||||||
OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) );
|
OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) );
|
||||||
|
@ -105,11 +106,11 @@ int radeon_emit_irq(drm_device_t *dev)
|
||||||
ADVANCE_RING();
|
ADVANCE_RING();
|
||||||
COMMIT_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_priv =
|
||||||
(drm_radeon_private_t *)dev->dev_private;
|
(drm_radeon_private_t *)dev->dev_private;
|
||||||
|
@ -119,17 +120,17 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)
|
||||||
#endif /* __linux__ */
|
#endif /* __linux__ */
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
|
if (atomic_read(&dev_priv->swi_received) >= swi_nr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
|
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
add_wait_queue(&dev_priv->irq_queue, &entry);
|
add_wait_queue(&dev_priv->swi_queue, &entry);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
current->state = TASK_INTERRUPTIBLE;
|
current->state = TASK_INTERRUPTIBLE;
|
||||||
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
|
if (atomic_read(&dev_priv->swi_received) >= swi_nr)
|
||||||
break;
|
break;
|
||||||
if((signed)(end - jiffies) <= 0) {
|
if((signed)(end - jiffies) <= 0) {
|
||||||
ret = -EBUSY; /* Lockup? Missed irq? */
|
ret = -EBUSY; /* Lockup? Missed irq? */
|
||||||
|
@ -143,12 +144,12 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)
|
||||||
}
|
}
|
||||||
|
|
||||||
current->state = TASK_RUNNING;
|
current->state = TASK_RUNNING;
|
||||||
remove_wait_queue(&dev_priv->irq_queue, &entry);
|
remove_wait_queue(&dev_priv->swi_queue, &entry);
|
||||||
return ret;
|
return ret;
|
||||||
#endif /* __linux__ */
|
#endif /* __linux__ */
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
ret = tsleep( &dev_priv->irq_queue, PZERO | PCATCH, \
|
ret = tsleep( &dev_priv->swi_queue, PZERO | PCATCH, \
|
||||||
"rdnirq", 3*hz );
|
"rdnirq", 3*hz );
|
||||||
if ( (ret == EWOULDBLOCK) || (ret == EINTR) )
|
if ( (ret == EWOULDBLOCK) || (ret == EINTR) )
|
||||||
return DRM_ERR(EBUSY);
|
return DRM_ERR(EBUSY);
|
||||||
|
@ -156,7 +157,6 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)
|
||||||
#endif /* __FreeBSD__ */
|
#endif /* __FreeBSD__ */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int radeon_emit_and_wait_irq(drm_device_t *dev)
|
int radeon_emit_and_wait_irq(drm_device_t *dev)
|
||||||
{
|
{
|
||||||
return radeon_wait_irq( dev, radeon_emit_irq(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 );
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
shared/drm.h
15
shared/drm.h
|
@ -345,6 +345,19 @@ typedef struct drm_irq_busid {
|
||||||
int funcnum;
|
int funcnum;
|
||||||
} drm_irq_busid_t;
|
} 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 {
|
typedef struct drm_agp_mode {
|
||||||
unsigned long mode;
|
unsigned long mode;
|
||||||
} drm_agp_mode_t;
|
} 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_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t)
|
||||||
#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, 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
|
/* Device specfic ioctls should only be in their respective headers
|
||||||
* The device specific ioctl range is 0x40 to 0x79. */
|
* The device specific ioctl range is 0x40 to 0x79. */
|
||||||
#define DRM_COMMAND_BASE 0x40
|
#define DRM_COMMAND_BASE 0x40
|
||||||
|
|
|
@ -132,53 +132,10 @@
|
||||||
*/
|
*/
|
||||||
#define __HAVE_DMA 1
|
#define __HAVE_DMA 1
|
||||||
|
|
||||||
|
|
||||||
#define __HAVE_DMA_IRQ 1
|
#define __HAVE_DMA_IRQ 1
|
||||||
#define __HAVE_DMA_IRQ_BH 1
|
#define __HAVE_VBL_IRQ 1
|
||||||
#define __HAVE_SHARED_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:
|
/* Buffer customization:
|
||||||
*/
|
*/
|
||||||
#define DRIVER_BUF_PRIV_T drm_radeon_buf_priv_t
|
#define DRIVER_BUF_PRIV_T drm_radeon_buf_priv_t
|
||||||
|
|
|
@ -139,9 +139,10 @@ typedef struct drm_radeon_private {
|
||||||
struct mem_block *agp_heap;
|
struct mem_block *agp_heap;
|
||||||
struct mem_block *fb_heap;
|
struct mem_block *fb_heap;
|
||||||
|
|
||||||
wait_queue_head_t irq_queue;
|
/* SW interrupt */
|
||||||
atomic_t irq_received;
|
wait_queue_head_t swi_queue;
|
||||||
atomic_t irq_emitted;
|
atomic_t swi_received;
|
||||||
|
atomic_t swi_emitted;
|
||||||
|
|
||||||
} drm_radeon_private_t;
|
} 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_takedown( struct mem_block **heap );
|
||||||
extern void radeon_mem_release( 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_emit( DRM_IOCTL_ARGS );
|
||||||
extern int radeon_irq_wait( 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_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_emit_irq(drm_device_t *dev);
|
||||||
|
extern int radeon_vblank_wait(drm_device_t *dev, unsigned int *vbl_seq);
|
||||||
|
|
||||||
|
|
||||||
/* Flags for stats.boxes
|
/* 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_GEN_INT_CNTL 0x0040
|
||||||
|
# define RADEON_CRTC_VBLANK_MASK (1 << 0)
|
||||||
# define RADEON_GUI_IDLE_INT_ENABLE (1 << 19)
|
# define RADEON_GUI_IDLE_INT_ENABLE (1 << 19)
|
||||||
# define RADEON_SW_INT_ENABLE (1 << 25)
|
# define RADEON_SW_INT_ENABLE (1 << 25)
|
||||||
|
|
||||||
#define RADEON_GEN_INT_STATUS 0x0044
|
#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_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_TEST_ACK (1 << 25)
|
||||||
# define RADEON_SW_INT_FIRE (1 << 26)
|
# define RADEON_SW_INT_FIRE (1 << 26)
|
||||||
|
|
||||||
|
|
|
@ -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.
|
* 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_device_t *dev = (drm_device_t *) arg;
|
||||||
drm_radeon_private_t *dev_priv =
|
drm_radeon_private_t *dev_priv =
|
||||||
(drm_radeon_private_t *)dev->dev_private;
|
(drm_radeon_private_t *)dev->dev_private;
|
||||||
u32 temp;
|
u32 stat, ack = 0;
|
||||||
|
|
||||||
/* Need to wait for fifo to drain?
|
/* Need to wait for fifo to drain?
|
||||||
*/
|
*/
|
||||||
temp = RADEON_READ(RADEON_GEN_INT_STATUS);
|
stat = RADEON_READ(RADEON_GEN_INT_STATUS);
|
||||||
temp = temp & RADEON_SW_INT_TEST_ACK;
|
|
||||||
if (temp == 0) return;
|
|
||||||
RADEON_WRITE(RADEON_GEN_INT_STATUS, temp);
|
|
||||||
|
|
||||||
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__
|
#ifdef __linux__
|
||||||
queue_task(&dev->tq, &tq_immediate);
|
wake_up_interruptible(&dev_priv->swi_queue);
|
||||||
mark_bh(IMMEDIATE_BH);
|
|
||||||
#endif /* __linux__ */
|
|
||||||
#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;
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
wake_up_interruptible(&dev_priv->irq_queue);
|
|
||||||
#endif /* __linux__ */
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
wakeup( &dev_priv->irq_queue );
|
|
||||||
#endif
|
#endif
|
||||||
}
|
#ifdef __FreeBSD__
|
||||||
|
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->vbl_queue);
|
||||||
|
#endif
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
wakeup(&dev->vbl_queue);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ack)
|
||||||
|
RADEON_WRITE(RADEON_GEN_INT_STATUS, ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int radeon_emit_irq(drm_device_t *dev)
|
int radeon_emit_irq(drm_device_t *dev)
|
||||||
{
|
{
|
||||||
drm_radeon_private_t *dev_priv = dev->dev_private;
|
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||||
RING_LOCALS;
|
RING_LOCALS;
|
||||||
|
|
||||||
atomic_inc(&dev_priv->irq_emitted);
|
atomic_inc(&dev_priv->swi_emitted);
|
||||||
|
|
||||||
BEGIN_RING(2);
|
BEGIN_RING(2);
|
||||||
OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) );
|
OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) );
|
||||||
|
@ -105,11 +106,11 @@ int radeon_emit_irq(drm_device_t *dev)
|
||||||
ADVANCE_RING();
|
ADVANCE_RING();
|
||||||
COMMIT_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_priv =
|
||||||
(drm_radeon_private_t *)dev->dev_private;
|
(drm_radeon_private_t *)dev->dev_private;
|
||||||
|
@ -119,17 +120,17 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)
|
||||||
#endif /* __linux__ */
|
#endif /* __linux__ */
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
|
if (atomic_read(&dev_priv->swi_received) >= swi_nr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
|
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
add_wait_queue(&dev_priv->irq_queue, &entry);
|
add_wait_queue(&dev_priv->swi_queue, &entry);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
current->state = TASK_INTERRUPTIBLE;
|
current->state = TASK_INTERRUPTIBLE;
|
||||||
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
|
if (atomic_read(&dev_priv->swi_received) >= swi_nr)
|
||||||
break;
|
break;
|
||||||
if((signed)(end - jiffies) <= 0) {
|
if((signed)(end - jiffies) <= 0) {
|
||||||
ret = -EBUSY; /* Lockup? Missed irq? */
|
ret = -EBUSY; /* Lockup? Missed irq? */
|
||||||
|
@ -143,12 +144,12 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)
|
||||||
}
|
}
|
||||||
|
|
||||||
current->state = TASK_RUNNING;
|
current->state = TASK_RUNNING;
|
||||||
remove_wait_queue(&dev_priv->irq_queue, &entry);
|
remove_wait_queue(&dev_priv->swi_queue, &entry);
|
||||||
return ret;
|
return ret;
|
||||||
#endif /* __linux__ */
|
#endif /* __linux__ */
|
||||||
|
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
ret = tsleep( &dev_priv->irq_queue, PZERO | PCATCH, \
|
ret = tsleep( &dev_priv->swi_queue, PZERO | PCATCH, \
|
||||||
"rdnirq", 3*hz );
|
"rdnirq", 3*hz );
|
||||||
if ( (ret == EWOULDBLOCK) || (ret == EINTR) )
|
if ( (ret == EWOULDBLOCK) || (ret == EINTR) )
|
||||||
return DRM_ERR(EBUSY);
|
return DRM_ERR(EBUSY);
|
||||||
|
@ -156,7 +157,6 @@ int radeon_wait_irq(drm_device_t *dev, int irq_nr)
|
||||||
#endif /* __FreeBSD__ */
|
#endif /* __FreeBSD__ */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int radeon_emit_and_wait_irq(drm_device_t *dev)
|
int radeon_emit_and_wait_irq(drm_device_t *dev)
|
||||||
{
|
{
|
||||||
return radeon_wait_irq( dev, radeon_emit_irq(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 );
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue