radeon_irq.c revision 112015
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 112015 2003-03-09 02:08:30Z anholt $ 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 59void DRM(dma_service)( 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; 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} 89 90static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv) 91{ 92 u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS ) 93 & (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT); 94 if (tmp) 95 RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp ); 96} 97 98int radeon_emit_irq(drm_device_t *dev) 99{ 100 drm_radeon_private_t *dev_priv = dev->dev_private; 101 unsigned int ret; 102 RING_LOCALS; 103 104 atomic_inc(&dev_priv->swi_emitted); 105 ret = atomic_read(&dev_priv->swi_emitted); 106 107 BEGIN_RING( 4 ); 108 OUT_RING_REG( RADEON_LAST_SWI_REG, ret ); 109 OUT_RING_REG( RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE ); 110 ADVANCE_RING(); 111 COMMIT_RING(); 112 113 return ret; 114} 115 116 117int radeon_wait_irq(drm_device_t *dev, int swi_nr) 118{ 119 drm_radeon_private_t *dev_priv = 120 (drm_radeon_private_t *)dev->dev_private; 121 int ret = 0; 122 123 if (RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr) 124 return 0; 125 126 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; 127 128 /* This is a hack to work around mysterious freezes on certain 129 * systems: 130 */ 131 radeon_acknowledge_irqs( dev_priv ); 132 133 DRM_WAIT_ON( ret, dev_priv->swi_queue, 3 * DRM_HZ, 134 RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr ); 135 136 return ret; 137} 138 139int radeon_emit_and_wait_irq(drm_device_t *dev) 140{ 141 return radeon_wait_irq( dev, radeon_emit_irq(dev) ); 142} 143 144 145int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence) 146{ 147 drm_radeon_private_t *dev_priv = 148 (drm_radeon_private_t *)dev->dev_private; 149 unsigned int cur_vblank; 150 int ret = 0; 151 152 if ( !dev_priv ) { 153 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); 154 return DRM_ERR(EINVAL); 155 } 156 157 radeon_acknowledge_irqs( dev_priv ); 158 159 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; 160 161 /* Assume that the user has missed the current sequence number 162 * by about a day rather than she wants to wait for years 163 * using vertical blanks... 164 */ 165 DRM_WAIT_ON( ret, dev->vbl_queue, 3*DRM_HZ, 166 ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) ) 167 - *sequence ) <= (1<<23) ) ); 168 169 *sequence = cur_vblank; 170 171 return ret; 172} 173 174 175/* Needs the lock as it touches the ring. 176 */ 177int radeon_irq_emit( DRM_IOCTL_ARGS ) 178{ 179 DRM_DEVICE; 180 drm_radeon_private_t *dev_priv = dev->dev_private; 181 drm_radeon_irq_emit_t emit; 182 int result; 183 184 LOCK_TEST_WITH_RETURN( dev ); 185 186 if ( !dev_priv ) { 187 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); 188 return DRM_ERR(EINVAL); 189 } 190 191 DRM_COPY_FROM_USER_IOCTL( emit, (drm_radeon_irq_emit_t *)data, 192 sizeof(emit) ); 193 194 result = radeon_emit_irq( dev ); 195 196 if ( DRM_COPY_TO_USER( emit.irq_seq, &result, sizeof(int) ) ) { 197 DRM_ERROR( "copy_to_user\n" ); 198 return DRM_ERR(EFAULT); 199 } 200 201 return 0; 202} 203 204 205/* Doesn't need the hardware lock. 206 */ 207int radeon_irq_wait( DRM_IOCTL_ARGS ) 208{ 209 DRM_DEVICE; 210 drm_radeon_private_t *dev_priv = dev->dev_private; 211 drm_radeon_irq_wait_t irqwait; 212 213 if ( !dev_priv ) { 214 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); 215 return DRM_ERR(EINVAL); 216 } 217 218 DRM_COPY_FROM_USER_IOCTL( irqwait, (drm_radeon_irq_wait_t *)data, 219 sizeof(irqwait) ); 220 221 return radeon_wait_irq( dev, irqwait.irq_seq ); 222} 223 224 225/* drm_dma.h hooks 226*/ 227void DRM(driver_irq_preinstall)( drm_device_t *dev ) { 228 drm_radeon_private_t *dev_priv = 229 (drm_radeon_private_t *)dev->dev_private; 230 231 /* Disable *all* interrupts */ 232 RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); 233 234 /* Clear bits if they're already high */ 235 radeon_acknowledge_irqs( dev_priv ); 236} 237 238void DRM(driver_irq_postinstall)( drm_device_t *dev ) { 239 drm_radeon_private_t *dev_priv = 240 (drm_radeon_private_t *)dev->dev_private; 241 242 atomic_set(&dev_priv->swi_emitted, 0); 243 DRM_INIT_WAITQUEUE( &dev_priv->swi_queue ); 244 245 /* Turn on SW and VBL ints */ 246 RADEON_WRITE( RADEON_GEN_INT_CNTL, 247 RADEON_CRTC_VBLANK_MASK | 248 RADEON_SW_INT_ENABLE ); 249} 250 251void DRM(driver_irq_uninstall)( drm_device_t *dev ) { 252 drm_radeon_private_t *dev_priv = 253 (drm_radeon_private_t *)dev->dev_private; 254 if ( dev_priv ) { 255 /* Disable *all* interrupts */ 256 RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); 257 } 258} 259