diff options
author | Michel Daenzer <michel@daenzer.net> | 2002-09-25 17:18:19 +0000 |
---|---|---|
committer | Michel Daenzer <michel@daenzer.net> | 2002-09-25 17:18:19 +0000 |
commit | 55acd0d5a64a2ee6b0cecc75872fbf8c4bb42a0c (patch) | |
tree | 35851b96a577b91c5a41de9d4b390d038f558fce /shared/radeon_irq.c | |
parent | f1c8fe95578e15d5eece6ad52540ce2c7c671f70 (diff) |
common ioctl to wait for vertical blank IRQs
Diffstat (limited to 'shared/radeon_irq.c')
-rw-r--r-- | shared/radeon_irq.c | 102 |
1 files changed, 70 insertions, 32 deletions
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 ); + } +} |