1/* i830_dma.c -- DMA support for the I830 -*- linux-c -*- 2 * 3 * Copyright 2002 Tungsten Graphics, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 * Authors: Keith Whitwell <keith@tungstengraphics.com> 26 * 27 */ 28 29#include "drmP.h" 30#include "drm.h" 31#include "i830_drm.h" 32#include "i830_drv.h" 33#include <linux/interrupt.h> /* For task queue support */ 34#include <linux/delay.h> 35 36irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS) 37{ 38 drm_device_t *dev = (drm_device_t *) arg; 39 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; 40 u16 temp; 41 42 temp = I830_READ16(I830REG_INT_IDENTITY_R); 43 DRM_DEBUG("%x\n", temp); 44 45 if (!(temp & 2)) 46 return IRQ_NONE; 47 48 I830_WRITE16(I830REG_INT_IDENTITY_R, temp); 49 50 atomic_inc(&dev_priv->irq_received); 51 wake_up_interruptible(&dev_priv->irq_queue); 52 53 return IRQ_HANDLED; 54} 55 56static int i830_emit_irq(drm_device_t * dev) 57{ 58 drm_i830_private_t *dev_priv = dev->dev_private; 59 RING_LOCALS; 60 61 DRM_DEBUG("%s\n", __FUNCTION__); 62 63 atomic_inc(&dev_priv->irq_emitted); 64 65 BEGIN_LP_RING(2); 66 OUT_RING(0); 67 OUT_RING(GFX_OP_USER_INTERRUPT); 68 ADVANCE_LP_RING(); 69 70 return atomic_read(&dev_priv->irq_emitted); 71} 72 73static int i830_wait_irq(drm_device_t * dev, int irq_nr) 74{ 75 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; 76 DECLARE_WAITQUEUE(entry, current); 77 unsigned long end = jiffies + HZ * 3; 78 int ret = 0; 79 80 DRM_DEBUG("%s\n", __FUNCTION__); 81 82 if (atomic_read(&dev_priv->irq_received) >= irq_nr) 83 return 0; 84 85 dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT; 86 87 add_wait_queue(&dev_priv->irq_queue, &entry); 88 89 for (;;) { 90 __set_current_state(TASK_INTERRUPTIBLE); 91 if (atomic_read(&dev_priv->irq_received) >= irq_nr) 92 break; 93 if ((signed)(end - jiffies) <= 0) { 94 DRM_ERROR("timeout iir %x imr %x ier %x hwstam %x\n", 95 I830_READ16(I830REG_INT_IDENTITY_R), 96 I830_READ16(I830REG_INT_MASK_R), 97 I830_READ16(I830REG_INT_ENABLE_R), 98 I830_READ16(I830REG_HWSTAM)); 99 100 ret = -EBUSY; /* Lockup? Missed irq? */ 101 break; 102 } 103 schedule_timeout(HZ * 3); 104 if (signal_pending(current)) { 105 ret = -EINTR; 106 break; 107 } 108 } 109 110 __set_current_state(TASK_RUNNING); 111 remove_wait_queue(&dev_priv->irq_queue, &entry); 112 return ret; 113} 114 115/* Needs the lock as it touches the ring. 116 */ 117int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd, 118 unsigned long arg) 119{ 120 drm_file_t *priv = filp->private_data; 121 drm_device_t *dev = priv->head->dev; 122 drm_i830_private_t *dev_priv = dev->dev_private; 123 drm_i830_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 -EINVAL; 131 } 132 133 if (copy_from_user 134 (&emit, (drm_i830_irq_emit_t __user *) arg, sizeof(emit))) 135 return -EFAULT; 136 137 result = i830_emit_irq(dev); 138 139 if (copy_to_user(emit.irq_seq, &result, sizeof(int))) { 140 DRM_ERROR("copy_to_user\n"); 141 return -EFAULT; 142 } 143 144 return 0; 145} 146 147/* Doesn't need the hardware lock. 148 */ 149int i830_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd, 150 unsigned long arg) 151{ 152 drm_file_t *priv = filp->private_data; 153 drm_device_t *dev = priv->head->dev; 154 drm_i830_private_t *dev_priv = dev->dev_private; 155 drm_i830_irq_wait_t irqwait; 156 157 if (!dev_priv) { 158 DRM_ERROR("%s called with no initialization\n", __FUNCTION__); 159 return -EINVAL; 160 } 161 162 if (copy_from_user(&irqwait, (drm_i830_irq_wait_t __user *) arg, 163 sizeof(irqwait))) 164 return -EFAULT; 165 166 return i830_wait_irq(dev, irqwait.irq_seq); 167} 168 169/* drm_dma.h hooks 170*/ 171void i830_driver_irq_preinstall(drm_device_t * dev) 172{ 173 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; 174 175 I830_WRITE16(I830REG_HWSTAM, 0xffff); 176 I830_WRITE16(I830REG_INT_MASK_R, 0x0); 177 I830_WRITE16(I830REG_INT_ENABLE_R, 0x0); 178 atomic_set(&dev_priv->irq_received, 0); 179 atomic_set(&dev_priv->irq_emitted, 0); 180 init_waitqueue_head(&dev_priv->irq_queue); 181} 182 183void i830_driver_irq_postinstall(drm_device_t * dev) 184{ 185 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; 186 187 I830_WRITE16(I830REG_INT_ENABLE_R, 0x2); 188} 189 190void i830_driver_irq_uninstall(drm_device_t * dev) 191{ 192 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; 193 if (!dev_priv) 194 return; 195 196 I830_WRITE16(I830REG_INT_MASK_R, 0xffff); 197 I830_WRITE16(I830REG_INT_ENABLE_R, 0x0); 198} 199