Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.13 245 lines 6.8 kB view raw
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�zer <michel@daenzer.net> 31 */ 32 33#include "drmP.h" 34#include "drm.h" 35#include "radeon_drm.h" 36#include "radeon_drv.h" 37 38static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 mask) 39{ 40 u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask; 41 if (irqs) 42 RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs); 43 return irqs; 44} 45 46/* Interrupts - Used for device synchronization and flushing in the 47 * following circumstances: 48 * 49 * - Exclusive FB access with hw idle: 50 * - Wait for GUI Idle (?) interrupt, then do normal flush. 51 * 52 * - Frame throttling, NV_fence: 53 * - Drop marker irq's into command stream ahead of time. 54 * - Wait on irq's with lock *not held* 55 * - Check each for termination condition 56 * 57 * - Internally in cp_getbuffer, etc: 58 * - as above, but wait with lock held??? 59 * 60 * NOTE: These functions are misleadingly named -- the irq's aren't 61 * tied to dma at all, this is just a hangover from dri prehistory. 62 */ 63 64irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS ) 65{ 66 drm_device_t *dev = (drm_device_t *) arg; 67 drm_radeon_private_t *dev_priv = 68 (drm_radeon_private_t *)dev->dev_private; 69 u32 stat; 70 71 /* Only consider the bits we're interested in - others could be used 72 * outside the DRM 73 */ 74 stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | 75 RADEON_CRTC_VBLANK_STAT)); 76 if (!stat) 77 return IRQ_NONE; 78 79 /* SW interrupt */ 80 if (stat & RADEON_SW_INT_TEST) { 81 DRM_WAKEUP( &dev_priv->swi_queue ); 82 } 83 84 /* VBLANK interrupt */ 85 if (stat & RADEON_CRTC_VBLANK_STAT) { 86 atomic_inc(&dev->vbl_received); 87 DRM_WAKEUP(&dev->vbl_queue); 88 drm_vbl_send_signals( dev ); 89 } 90 91 return IRQ_HANDLED; 92} 93 94static int radeon_emit_irq(drm_device_t *dev) 95{ 96 drm_radeon_private_t *dev_priv = dev->dev_private; 97 unsigned int ret; 98 RING_LOCALS; 99 100 atomic_inc(&dev_priv->swi_emitted); 101 ret = atomic_read(&dev_priv->swi_emitted); 102 103 BEGIN_RING( 4 ); 104 OUT_RING_REG( RADEON_LAST_SWI_REG, ret ); 105 OUT_RING_REG( RADEON_GEN_INT_STATUS, RADEON_SW_INT_FIRE ); 106 ADVANCE_RING(); 107 COMMIT_RING(); 108 109 return ret; 110} 111 112 113static int radeon_wait_irq(drm_device_t *dev, int swi_nr) 114{ 115 drm_radeon_private_t *dev_priv = 116 (drm_radeon_private_t *)dev->dev_private; 117 int ret = 0; 118 119 if (RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr) 120 return 0; 121 122 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; 123 124 DRM_WAIT_ON( ret, dev_priv->swi_queue, 3 * DRM_HZ, 125 RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr ); 126 127 return ret; 128} 129 130int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) 131{ 132 drm_radeon_private_t *dev_priv = 133 (drm_radeon_private_t *)dev->dev_private; 134 unsigned int cur_vblank; 135 int ret = 0; 136 137 if ( !dev_priv ) { 138 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); 139 return DRM_ERR(EINVAL); 140 } 141 142 radeon_acknowledge_irqs(dev_priv, RADEON_CRTC_VBLANK_STAT); 143 144 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; 145 146 /* Assume that the user has missed the current sequence number 147 * by about a day rather than she wants to wait for years 148 * using vertical blanks... 149 */ 150 DRM_WAIT_ON( ret, dev->vbl_queue, 3*DRM_HZ, 151 ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) ) 152 - *sequence ) <= (1<<23) ) ); 153 154 *sequence = cur_vblank; 155 156 return ret; 157} 158 159 160/* Needs the lock as it touches the ring. 161 */ 162int radeon_irq_emit( DRM_IOCTL_ARGS ) 163{ 164 DRM_DEVICE; 165 drm_radeon_private_t *dev_priv = dev->dev_private; 166 drm_radeon_irq_emit_t emit; 167 int result; 168 169 LOCK_TEST_WITH_RETURN( dev, filp ); 170 171 if ( !dev_priv ) { 172 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); 173 return DRM_ERR(EINVAL); 174 } 175 176 DRM_COPY_FROM_USER_IOCTL( emit, (drm_radeon_irq_emit_t __user *)data, 177 sizeof(emit) ); 178 179 result = radeon_emit_irq( dev ); 180 181 if ( DRM_COPY_TO_USER( emit.irq_seq, &result, sizeof(int) ) ) { 182 DRM_ERROR( "copy_to_user\n" ); 183 return DRM_ERR(EFAULT); 184 } 185 186 return 0; 187} 188 189 190/* Doesn't need the hardware lock. 191 */ 192int radeon_irq_wait( DRM_IOCTL_ARGS ) 193{ 194 DRM_DEVICE; 195 drm_radeon_private_t *dev_priv = dev->dev_private; 196 drm_radeon_irq_wait_t irqwait; 197 198 if ( !dev_priv ) { 199 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); 200 return DRM_ERR(EINVAL); 201 } 202 203 DRM_COPY_FROM_USER_IOCTL( irqwait, (drm_radeon_irq_wait_t __user*)data, 204 sizeof(irqwait) ); 205 206 return radeon_wait_irq( dev, irqwait.irq_seq ); 207} 208 209 210/* drm_dma.h hooks 211*/ 212void radeon_driver_irq_preinstall( drm_device_t *dev ) { 213 drm_radeon_private_t *dev_priv = 214 (drm_radeon_private_t *)dev->dev_private; 215 216 /* Disable *all* interrupts */ 217 RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); 218 219 /* Clear bits if they're already high */ 220 radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK | 221 RADEON_CRTC_VBLANK_STAT)); 222} 223 224void radeon_driver_irq_postinstall( drm_device_t *dev ) { 225 drm_radeon_private_t *dev_priv = 226 (drm_radeon_private_t *)dev->dev_private; 227 228 atomic_set(&dev_priv->swi_emitted, 0); 229 DRM_INIT_WAITQUEUE( &dev_priv->swi_queue ); 230 231 /* Turn on SW and VBL ints */ 232 RADEON_WRITE( RADEON_GEN_INT_CNTL, 233 RADEON_CRTC_VBLANK_MASK | 234 RADEON_SW_INT_ENABLE ); 235} 236 237void radeon_driver_irq_uninstall( drm_device_t *dev ) { 238 drm_radeon_private_t *dev_priv = 239 (drm_radeon_private_t *)dev->dev_private; 240 if (!dev_priv) 241 return; 242 243 /* Disable *all* interrupts */ 244 RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); 245}