make SW interrupts more robust: write sequence number to scratch register,
acknowledge any lost interrupts before waitingmain
parent
cc9a169d08
commit
a33d42e2ba
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -92,21 +92,27 @@ void DRM(dma_service)( DRM_IRQ_ARGS )
|
||||||
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 );
|
||||||
|
|
||||||
|
@ -252,24 +262,23 @@ int radeon_irq_wait( DRM_IOCTL_ARGS )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -92,21 +92,27 @@ void DRM(dma_service)( DRM_IRQ_ARGS )
|
||||||
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 );
|
||||||
|
|
||||||
|
@ -252,24 +262,23 @@ int radeon_irq_wait( DRM_IOCTL_ARGS )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
Loading…
Reference in New Issue