1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* BEGIN CSTYLED */ 7 8 /* i915_irq.c -- IRQ support for the I915 -*- linux-c -*- 9 */ 10 /************************************************************************** 11 * 12 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 13 * All Rights Reserved. 14 * 15 * Permission is hereby granted, free of charge, to any person obtaining a 16 * copy of this software and associated documentation files (the 17 * "Software"), to deal in the Software without restriction, including 18 * without limitation the rights to use, copy, modify, merge, publish, 19 * distribute, sub license, and/or sell copies of the Software, and to 20 * permit persons to whom the Software is furnished to do so, subject to 21 * the following conditions: 22 * 23 * The above copyright notice and this permission notice (including the 24 * next paragraph) shall be included in all copies or substantial portions 25 * of the Software. 26 * 27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 28 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 30 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 31 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 32 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 33 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 34 * 35 **************************************************************************/ 36 37 #pragma ident "%Z%%M% %I% %E% SMI" 38 39 #include "drmP.h" 40 #include "drm.h" 41 #include "i915_drm.h" 42 #include "i915_drv.h" 43 44 #define USER_INT_FLAG 0x2 45 #define MAX_NOPID ((u32)~0) 46 #define READ_BREADCRUMB(dev_priv) (((u32*)(dev_priv->hw_status_page))[5]) 47 48 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) 49 { 50 drm_device_t *dev = (drm_device_t *) arg; 51 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 52 u16 temp; 53 54 temp = I915_READ16(I915REG_INT_IDENTITY_R); 55 temp &= USER_INT_FLAG; 56 57 DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); 58 59 if (temp == 0) { 60 return (IRQ_NONE); 61 } 62 I915_WRITE16(I915REG_INT_IDENTITY_R, temp); 63 DRM_WAKEUP(&dev_priv->irq_queue); 64 65 return IRQ_HANDLED; 66 } 67 68 static int i915_emit_irq(drm_device_t * dev) 69 { 70 drm_i915_private_t *dev_priv = dev->dev_private; 71 u32 ret; 72 RING_LOCALS; 73 74 i915_kernel_lost_context(dev); 75 76 DRM_DEBUG("%s\n", __FUNCTION__); 77 78 ret = dev_priv->counter; 79 80 /*NOSTRICT*/ 81 BEGIN_LP_RING(2); 82 OUT_RING(0); 83 OUT_RING(GFX_OP_USER_INTERRUPT); 84 ADVANCE_LP_RING(); 85 /*LINT*/ 86 87 return ret; 88 } 89 90 static int i915_wait_irq(drm_device_t * dev, int irq_nr) 91 { 92 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 93 int ret = 0; 94 95 DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr, 96 READ_BREADCRUMB(dev_priv)); 97 98 if (READ_BREADCRUMB(dev_priv) >= irq_nr) 99 return 0; 100 101 dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; 102 103 DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, 104 READ_BREADCRUMB(dev_priv) >= irq_nr); 105 106 if (ret == -EBUSY) { 107 DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n", 108 __FUNCTION__, 109 READ_BREADCRUMB(dev_priv), (int)dev_priv->counter); 110 } 111 112 dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); 113 return ret; 114 } 115 116 /* Needs the lock as it touches the ring. 117 */ 118 /*ARGSUSED*/ 119 int i915_irq_emit(DRM_IOCTL_ARGS) 120 { 121 DRM_DEVICE; 122 drm_i915_private_t *dev_priv = dev->dev_private; 123 drm_i915_irq_emit_t emit; 124 int result; 125 126 LOCK_TEST_WITH_RETURN(dev, filp); 127 128 if (!dev_priv) { 129 DRM_ERROR("%s called with no initialization\n", __FUNCTION__); 130 return DRM_ERR(EINVAL); 131 } 132 133 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 134 drm_i915_irq_emit32_t irq_emit32; 135 136 DRM_COPY_FROM_USER_IOCTL(irq_emit32, 137 (drm_i915_irq_emit32_t __user *) data, 138 sizeof (drm_i915_irq_emit32_t)); 139 emit.irq_seq = (int __user *)(uintptr_t)irq_emit32.irq_seq; 140 } else 141 DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data, 142 sizeof(emit)); 143 144 result = i915_emit_irq(dev); 145 146 if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) { 147 DRM_ERROR("copy_to_user\n"); 148 return DRM_ERR(EFAULT); 149 } 150 151 return 0; 152 } 153 154 /* Doesn't need the hardware lock. 155 */ 156 /*ARGSUSED*/ 157 int i915_irq_wait(DRM_IOCTL_ARGS) 158 { 159 DRM_DEVICE; 160 drm_i915_private_t *dev_priv = dev->dev_private; 161 drm_i915_irq_wait_t irqwait; 162 163 if (!dev_priv) { 164 DRM_ERROR("%s called with no initialization\n", __FUNCTION__); 165 return DRM_ERR(EINVAL); 166 } 167 168 DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data, 169 sizeof(irqwait)); 170 171 return i915_wait_irq(dev, irqwait.irq_seq); 172 } 173 174 /* drm_dma.h hooks 175 */ 176 void i915_driver_irq_preinstall(drm_device_t * dev) 177 { 178 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 179 180 I915_WRITE16(I915REG_HWSTAM, 0xfffe); 181 I915_WRITE16(I915REG_INT_MASK_R, 0x0); 182 I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); 183 } 184 185 void i915_driver_irq_postinstall(drm_device_t * dev) 186 { 187 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 188 189 I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG); 190 DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); 191 } 192 193 void i915_driver_irq_uninstall(drm_device_t * dev) 194 { 195 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; 196 if (!dev_priv) 197 return; 198 199 I915_WRITE16(I915REG_HWSTAM, 0xffff); 200 I915_WRITE16(I915REG_INT_MASK_R, 0xffff); 201 I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); 202 #if defined(__SOLARIS__) || defined(sun) 203 cv_destroy(&dev_priv->irq_queue); 204 #endif 205 } 206