make SW interrupts more robust: write sequence number to scratch register,

acknowledge any lost interrupts before waiting
main
Michel Daenzer 2002-09-27 21:47:52 +00:00
parent cc9a169d08
commit a33d42e2ba
4 changed files with 52 additions and 34 deletions

View File

@ -141,7 +141,6 @@ typedef struct drm_radeon_private {
/* SW interrupt */ /* SW interrupt */
wait_queue_head_t swi_queue; wait_queue_head_t swi_queue;
atomic_t swi_received;
atomic_t swi_emitted; atomic_t swi_emitted;
} drm_radeon_private_t; } drm_radeon_private_t;
@ -638,6 +637,7 @@ extern int radeon_emit_irq(drm_device_t *dev);
#define RADEON_LAST_FRAME_REG RADEON_SCRATCH_REG0 #define RADEON_LAST_FRAME_REG RADEON_SCRATCH_REG0
#define RADEON_LAST_DISPATCH_REG RADEON_SCRATCH_REG1 #define RADEON_LAST_DISPATCH_REG RADEON_SCRATCH_REG1
#define RADEON_LAST_CLEAR_REG RADEON_SCRATCH_REG2 #define RADEON_LAST_CLEAR_REG RADEON_SCRATCH_REG2
#define RADEON_LAST_SWI_REG RADEON_SCRATCH_REG3
#define RADEON_LAST_DISPATCH 1 #define RADEON_LAST_DISPATCH 1
#define RADEON_MAX_VB_AGE 0x7fffffff #define RADEON_MAX_VB_AGE 0x7fffffff

View File

@ -27,6 +27,7 @@
* *
* Authors: * Authors:
* Keith Whitwell <keith@tungstengraphics.com> * Keith Whitwell <keith@tungstengraphics.com>
* Michel Dänzer <michel@daenzer.net>
*/ */
#include "radeon.h" #include "radeon.h"
@ -67,7 +68,6 @@ void DRM(dma_service)( DRM_IRQ_ARGS )
/* SW interrupt */ /* SW interrupt */
if (stat & RADEON_SW_INT_TEST) { if (stat & RADEON_SW_INT_TEST) {
ack |= RADEON_SW_INT_TEST_ACK; ack |= RADEON_SW_INT_TEST_ACK;
atomic_inc(&dev_priv->swi_received);
#ifdef __linux__ #ifdef __linux__
wake_up_interruptible(&dev_priv->swi_queue); wake_up_interruptible(&dev_priv->swi_queue);
#endif #endif
@ -91,22 +91,28 @@ void DRM(dma_service)( DRM_IRQ_ARGS )
if (ack) if (ack)
RADEON_WRITE(RADEON_GEN_INT_STATUS, ack); RADEON_WRITE(RADEON_GEN_INT_STATUS, ack);
} }
static inline void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv)
{
RADEON_WRITE( RADEON_GEN_INT_STATUS, RADEON_READ( RADEON_GEN_INT_STATUS ) );
}
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;
unsigned int ret;
RING_LOCALS; RING_LOCALS;
atomic_inc(&dev_priv->swi_emitted); atomic_inc(&dev_priv->swi_emitted);
ret = atomic_read(&dev_priv->swi_emitted);
BEGIN_RING(2); BEGIN_RING( 4 );
OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) ); OUT_RING_REG( RADEON_LAST_SWI_REG, ret );
OUT_RING( RADEON_SW_INT_FIRE ); OUT_RING_REG( RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE );
ADVANCE_RING(); ADVANCE_RING();
COMMIT_RING(); COMMIT_RING();
return atomic_read(&dev_priv->swi_emitted); return ret;
} }
@ -120,23 +126,24 @@ int radeon_wait_irq(drm_device_t *dev, int swi_nr)
#endif /* __linux__ */ #endif /* __linux__ */
int ret = 0; int ret = 0;
if (atomic_read(&dev_priv->swi_received) >= swi_nr) if (RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr)
return 0; return 0;
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
radeon_acknowledge_irqs( dev_priv );
#ifdef __linux__ #ifdef __linux__
add_wait_queue(&dev_priv->swi_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->swi_received) >= swi_nr) if (RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr)
break; break;
if((signed)(end - jiffies) <= 0) { if((signed)(end - jiffies) <= 0) {
ret = -EBUSY; /* Lockup? Missed irq? */ ret = -EBUSY; /* Lockup? Missed irq? */
break; break;
} }
schedule_timeout(HZ*3); schedule_timeout(max(HZ/100,1));
if (signal_pending(current)) { if (signal_pending(current)) {
ret = -EINTR; ret = -EINTR;
break; break;
@ -171,7 +178,7 @@ int radeon_vblank_wait(drm_device_t *dev, unsigned int *sequence)
int ret = 0; int ret = 0;
if ( !dev_priv ) { if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __func__ ); DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
return DRM_ERR(EINVAL); return DRM_ERR(EINVAL);
} }
@ -181,6 +188,9 @@ int radeon_vblank_wait(drm_device_t *dev, unsigned int *sequence)
while ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) ) while ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) )
+ ~*sequence + 1 ) > (1<<23) ) { + ~*sequence + 1 ) > (1<<23) ) {
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
radeon_acknowledge_irqs( dev_priv );
#ifdef __linux__ #ifdef __linux__
interruptible_sleep_on( &dev->vbl_queue ); interruptible_sleep_on( &dev->vbl_queue );
@ -251,25 +261,24 @@ int radeon_irq_wait( DRM_IOCTL_ARGS )
return radeon_wait_irq( dev, irqwait.irq_seq ); return radeon_wait_irq( dev, irqwait.irq_seq );
} }
/* drm_dma.h hooks
*/
void DRM(driver_irq_preinstall)( drm_device_t *dev ) { void DRM(driver_irq_preinstall)( drm_device_t *dev ) {
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 tmp;
/* Disable *all* interrupts */ /* Disable *all* interrupts */
RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
/* Clear bits if they're already high */ /* Clear bits if they're already high */
tmp = RADEON_READ( RADEON_GEN_INT_STATUS ); radeon_acknowledge_irqs( dev_priv );
RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );
} }
void DRM(driver_irq_postinstall)( drm_device_t *dev ) { void DRM(driver_irq_postinstall)( drm_device_t *dev ) {
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;
atomic_set(&dev_priv->swi_received, 0);
atomic_set(&dev_priv->swi_emitted, 0); atomic_set(&dev_priv->swi_emitted, 0);
#ifdef __linux__ #ifdef __linux__
init_waitqueue_head(&dev_priv->swi_queue); init_waitqueue_head(&dev_priv->swi_queue);

View File

@ -141,7 +141,6 @@ typedef struct drm_radeon_private {
/* SW interrupt */ /* SW interrupt */
wait_queue_head_t swi_queue; wait_queue_head_t swi_queue;
atomic_t swi_received;
atomic_t swi_emitted; atomic_t swi_emitted;
} drm_radeon_private_t; } drm_radeon_private_t;
@ -638,6 +637,7 @@ extern int radeon_emit_irq(drm_device_t *dev);
#define RADEON_LAST_FRAME_REG RADEON_SCRATCH_REG0 #define RADEON_LAST_FRAME_REG RADEON_SCRATCH_REG0
#define RADEON_LAST_DISPATCH_REG RADEON_SCRATCH_REG1 #define RADEON_LAST_DISPATCH_REG RADEON_SCRATCH_REG1
#define RADEON_LAST_CLEAR_REG RADEON_SCRATCH_REG2 #define RADEON_LAST_CLEAR_REG RADEON_SCRATCH_REG2
#define RADEON_LAST_SWI_REG RADEON_SCRATCH_REG3
#define RADEON_LAST_DISPATCH 1 #define RADEON_LAST_DISPATCH 1
#define RADEON_MAX_VB_AGE 0x7fffffff #define RADEON_MAX_VB_AGE 0x7fffffff

View File

@ -27,6 +27,7 @@
* *
* Authors: * Authors:
* Keith Whitwell <keith@tungstengraphics.com> * Keith Whitwell <keith@tungstengraphics.com>
* Michel Dänzer <michel@daenzer.net>
*/ */
#include "radeon.h" #include "radeon.h"
@ -67,7 +68,6 @@ void DRM(dma_service)( DRM_IRQ_ARGS )
/* SW interrupt */ /* SW interrupt */
if (stat & RADEON_SW_INT_TEST) { if (stat & RADEON_SW_INT_TEST) {
ack |= RADEON_SW_INT_TEST_ACK; ack |= RADEON_SW_INT_TEST_ACK;
atomic_inc(&dev_priv->swi_received);
#ifdef __linux__ #ifdef __linux__
wake_up_interruptible(&dev_priv->swi_queue); wake_up_interruptible(&dev_priv->swi_queue);
#endif #endif
@ -91,22 +91,28 @@ void DRM(dma_service)( DRM_IRQ_ARGS )
if (ack) if (ack)
RADEON_WRITE(RADEON_GEN_INT_STATUS, ack); RADEON_WRITE(RADEON_GEN_INT_STATUS, ack);
} }
static inline void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv)
{
RADEON_WRITE( RADEON_GEN_INT_STATUS, RADEON_READ( RADEON_GEN_INT_STATUS ) );
}
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;
unsigned int ret;
RING_LOCALS; RING_LOCALS;
atomic_inc(&dev_priv->swi_emitted); atomic_inc(&dev_priv->swi_emitted);
ret = atomic_read(&dev_priv->swi_emitted);
BEGIN_RING(2); BEGIN_RING( 4 );
OUT_RING( CP_PACKET0( RADEON_GEN_INT_STATUS, 0 ) ); OUT_RING_REG( RADEON_LAST_SWI_REG, ret );
OUT_RING( RADEON_SW_INT_FIRE ); OUT_RING_REG( RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE );
ADVANCE_RING(); ADVANCE_RING();
COMMIT_RING(); COMMIT_RING();
return atomic_read(&dev_priv->swi_emitted); return ret;
} }
@ -120,23 +126,24 @@ int radeon_wait_irq(drm_device_t *dev, int swi_nr)
#endif /* __linux__ */ #endif /* __linux__ */
int ret = 0; int ret = 0;
if (atomic_read(&dev_priv->swi_received) >= swi_nr) if (RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr)
return 0; return 0;
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
radeon_acknowledge_irqs( dev_priv );
#ifdef __linux__ #ifdef __linux__
add_wait_queue(&dev_priv->swi_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->swi_received) >= swi_nr) if (RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr)
break; break;
if((signed)(end - jiffies) <= 0) { if((signed)(end - jiffies) <= 0) {
ret = -EBUSY; /* Lockup? Missed irq? */ ret = -EBUSY; /* Lockup? Missed irq? */
break; break;
} }
schedule_timeout(HZ*3); schedule_timeout(max(HZ/100,1));
if (signal_pending(current)) { if (signal_pending(current)) {
ret = -EINTR; ret = -EINTR;
break; break;
@ -171,7 +178,7 @@ int radeon_vblank_wait(drm_device_t *dev, unsigned int *sequence)
int ret = 0; int ret = 0;
if ( !dev_priv ) { if ( !dev_priv ) {
DRM_ERROR( "%s called with no initialization\n", __func__ ); DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
return DRM_ERR(EINVAL); return DRM_ERR(EINVAL);
} }
@ -181,6 +188,9 @@ int radeon_vblank_wait(drm_device_t *dev, unsigned int *sequence)
while ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) ) while ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) )
+ ~*sequence + 1 ) > (1<<23) ) { + ~*sequence + 1 ) > (1<<23) ) {
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
radeon_acknowledge_irqs( dev_priv );
#ifdef __linux__ #ifdef __linux__
interruptible_sleep_on( &dev->vbl_queue ); interruptible_sleep_on( &dev->vbl_queue );
@ -251,25 +261,24 @@ int radeon_irq_wait( DRM_IOCTL_ARGS )
return radeon_wait_irq( dev, irqwait.irq_seq ); return radeon_wait_irq( dev, irqwait.irq_seq );
} }
/* drm_dma.h hooks
*/
void DRM(driver_irq_preinstall)( drm_device_t *dev ) { void DRM(driver_irq_preinstall)( drm_device_t *dev ) {
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 tmp;
/* Disable *all* interrupts */ /* Disable *all* interrupts */
RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
/* Clear bits if they're already high */ /* Clear bits if they're already high */
tmp = RADEON_READ( RADEON_GEN_INT_STATUS ); radeon_acknowledge_irqs( dev_priv );
RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );
} }
void DRM(driver_irq_postinstall)( drm_device_t *dev ) { void DRM(driver_irq_postinstall)( drm_device_t *dev ) {
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;
atomic_set(&dev_priv->swi_received, 0);
atomic_set(&dev_priv->swi_emitted, 0); atomic_set(&dev_priv->swi_emitted, 0);
#ifdef __linux__ #ifdef __linux__
init_waitqueue_head(&dev_priv->swi_queue); init_waitqueue_head(&dev_priv->swi_queue);