radeon_irq.c revision 139749
1/* radeon_irq.c -- IRQ handling for radeon -*- linux-c -*- */ 2/*- 3 * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. 4 * 5 * The Weather Channel (TM) funded Tungsten Graphics to develop the 6 * initial release of the Radeon 8500 driver under the XFree86 license. 7 * This notice must be preserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the next 17 * paragraph) shall be included in all copies or substantial portions of the 18 * Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 * DEALINGS IN THE SOFTWARE. 27 * 28 * Authors: 29 * Keith Whitwell <keith@tungstengraphics.com> 30 * Michel D�nzer <michel@daenzer.net> 31 * 32 * $FreeBSD: head/sys/dev/drm/radeon_irq.c 139749 2005-01-06 01:43:34Z imp $ 33 */ 34 35#include "dev/drm/radeon.h" 36#include "dev/drm/drmP.h" 37#include "dev/drm/drm.h" 38#include "dev/drm/radeon_drm.h" 39#include "dev/drm/radeon_drv.h" 40 41/* Interrupts - Used for device synchronization and flushing in the 42 * following circumstances: 43 * 44 * - Exclusive FB access with hw idle: 45 * - Wait for GUI Idle (?) interrupt, then do normal flush. 46 * 47 * - Frame throttling, NV_fence: 48 * - Drop marker irq's into command stream ahead of time. 49 * - Wait on irq's with lock *not held* 50 * - Check each for termination condition 51 * 52 * - Internally in cp_getbuffer, etc: 53 * - as above, but wait with lock held??? 54 * 55 * NOTE: These functions are misleadingly named -- the irq's aren't 56 * tied to dma at all, this is just a hangover from dri prehistory. 57 */ 58 59irqreturn_t DRM(irq_handler)( DRM_IRQ_ARGS ) 60{ 61 drm_device_t *dev = (drm_device_t *) arg; 62 drm_radeon_private_t *dev_priv = 63 (drm_radeon_private_t *)dev->dev_private; 64 u32 stat; 65 66 /* Only consider the bits we're interested in - others could be used 67 * outside the DRM 68 */ 69 stat = RADEON_READ(RADEON_GEN_INT_STATUS) 70 & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT); 71 if (!stat) 72 return IRQ_NONE; 73 74 /* SW interrupt */ 75 if (stat & RADEON_SW_INT_TEST) { 76 DRM_WAKEUP( &dev_priv->swi_queue ); 77 } 78 79 /* VBLANK interrupt */ 80 if (stat & RADEON_CRTC_VBLANK_STAT) { 81 atomic_inc(&dev->vbl_received); 82 DRM_WAKEUP(&dev->vbl_queue); 83 DRM(vbl_send_signals)( dev ); 84 } 85 86 /* Acknowledge interrupts we handle */ 87 RADEON_WRITE(RADEON_GEN_INT_STATUS, stat); 88 return IRQ_HANDLED; 89} 90 91static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv) 92{ 93 u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS ) 94 & (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT); 95 if (tmp) 96 RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp ); 97} 98 99int radeon_emit_irq(drm_device_t *dev) 100{ 101 drm_radeon_private_t *dev_priv = dev->dev_private; 102 unsigned int ret; 103 RING_LOCALS; 104 105 atomic_inc(&dev_priv->swi_emitted); 106 ret = atomic_read(&dev_priv->swi_emitted); 107 108 BEGIN_RING( 4 ); 109 OUT_RING_REG( RADEON_LAST_SWI_REG, ret ); 110 OUT_RING_REG( RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE ); 111 ADVANCE_RING(); 112 COMMIT_RING(); 113 114 return ret; 115} 116 117 118int radeon_wait_irq(drm_device_t *dev, int swi_nr) 119{ 120 drm_radeon_private_t *dev_priv = 121 (drm_radeon_private_t *)dev->dev_private; 122 int ret = 0; 123 124 if (RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr) 125 return 0; 126 127 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; 128 129 /* This is a hack to work around mysterious freezes on certain 130 * systems: 131 */ 132 radeon_acknowledge_irqs( dev_priv ); 133 134 DRM_WAIT_ON( ret, dev_priv->swi_queue, 3 * DRM_HZ, 135 RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr ); 136 137 return ret; 138} 139 140int radeon_emit_and_wait_irq(drm_device_t *dev) 141{ 142 return radeon_wait_irq( dev, radeon_emit_irq(dev) ); 143} 144 145 146int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence) 147{ 148 drm_radeon_private_t *dev_priv = 149 (drm_radeon_private_t *)dev->dev_private; 150 unsigned int cur_vblank; 151 int ret = 0; 152 153 if ( !dev_priv ) { 154 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); 155 return DRM_ERR(EINVAL); 156 } 157 158 radeon_acknowledge_irqs( dev_priv ); 159 160 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; 161 162 /* Assume that the user has missed the current sequence number 163 * by about a day rather than she wants to wait for years 164 * using vertical blanks... 165 */ 166 DRM_WAIT_ON( ret, dev->vbl_queue, 3*DRM_HZ, 167 ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) ) 168 - *sequence ) <= (1<<23) ) ); 169 170 *sequence = cur_vblank; 171 172 return ret; 173} 174 175 176/* Needs the lock as it touches the ring. 177 */ 178int radeon_irq_emit( DRM_IOCTL_ARGS ) 179{ 180 DRM_DEVICE; 181 drm_radeon_private_t *dev_priv = dev->dev_private; 182 drm_radeon_irq_emit_t emit; 183 int result; 184 185 LOCK_TEST_WITH_RETURN( dev, filp ); 186 187 if ( !dev_priv ) { 188 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); 189 return DRM_ERR(EINVAL); 190 } 191 192 DRM_COPY_FROM_USER_IOCTL( emit, (drm_radeon_irq_emit_t *)data, 193 sizeof(emit) ); 194 195 result = radeon_emit_irq( dev ); 196 197 if ( DRM_COPY_TO_USER( emit.irq_seq, &result, sizeof(int) ) ) { 198 DRM_ERROR( "copy_to_user\n" ); 199 return DRM_ERR(EFAULT); 200 } 201 202 return 0; 203} 204 205 206/* Doesn't need the hardware lock. 207 */ 208int radeon_irq_wait( DRM_IOCTL_ARGS ) 209{ 210 DRM_DEVICE; 211 drm_radeon_private_t *dev_priv = dev->dev_private; 212 drm_radeon_irq_wait_t irqwait; 213 214 if ( !dev_priv ) { 215 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); 216 return DRM_ERR(EINVAL); 217 } 218 219 DRM_COPY_FROM_USER_IOCTL( irqwait, (drm_radeon_irq_wait_t *)data, 220 sizeof(irqwait) ); 221 222 return radeon_wait_irq( dev, irqwait.irq_seq ); 223} 224 225 226/* drm_dma.h hooks 227*/ 228void DRM(driver_irq_preinstall)( drm_device_t *dev ) { 229 drm_radeon_private_t *dev_priv = 230 (drm_radeon_private_t *)dev->dev_private; 231 232 /* Disable *all* interrupts */ 233 RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); 234 235 /* Clear bits if they're already high */ 236 radeon_acknowledge_irqs( dev_priv ); 237} 238 239void DRM(driver_irq_postinstall)( drm_device_t *dev ) { 240 drm_radeon_private_t *dev_priv = 241 (drm_radeon_private_t *)dev->dev_private; 242 243 atomic_set(&dev_priv->swi_emitted, 0); 244 DRM_INIT_WAITQUEUE( &dev_priv->swi_queue ); 245 246 /* Turn on SW and VBL ints */ 247 RADEON_WRITE( RADEON_GEN_INT_CNTL, 248 RADEON_CRTC_VBLANK_MASK | 249 RADEON_SW_INT_ENABLE ); 250} 251 252void DRM(driver_irq_uninstall)( drm_device_t *dev ) { 253 drm_radeon_private_t *dev_priv = 254 (drm_radeon_private_t *)dev->dev_private; 255 if (!dev_priv) 256 return; 257 258 /* Disable *all* interrupts */ 259 RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); 260} 261