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 struct drm_device *dev = (struct drm_device *) 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(struct drm_device *dev) 57{ 58 drm_i830_private_t *dev_priv = dev->dev_private; 59 RING_LOCALS; 60 61 DRM_DEBUG("%s\n", __func__); 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(struct drm_device *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", __func__); 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 drm_device *dev, void *data, 118 struct drm_file *file_priv) 119{ 120 drm_i830_private_t *dev_priv = dev->dev_private; 121 drm_i830_irq_emit_t *emit = data; 122 int result; 123 124 LOCK_TEST_WITH_RETURN(dev, file_priv); 125 126 if (!dev_priv) { 127 DRM_ERROR("%s called with no initialization\n", __func__); 128 return -EINVAL; 129 } 130 131 result = i830_emit_irq(dev); 132 133 if (copy_to_user(emit->irq_seq, &result, sizeof(int))) { 134 DRM_ERROR("copy_to_user\n"); 135 return -EFAULT; 136 } 137 138 return 0; 139} 140 141/* Doesn't need the hardware lock. 142 */ 143int i830_irq_wait(struct drm_device *dev, void *data, 144 struct drm_file *file_priv) 145{ 146 drm_i830_private_t *dev_priv = dev->dev_private; 147 drm_i830_irq_wait_t *irqwait = data; 148 149 if (!dev_priv) { 150 DRM_ERROR("%s called with no initialization\n", __func__); 151 return -EINVAL; 152 } 153 154 return i830_wait_irq(dev, irqwait->irq_seq); 155} 156 157/* drm_dma.h hooks 158*/ 159void i830_driver_irq_preinstall(struct drm_device *dev) 160{ 161 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; 162 163 I830_WRITE16(I830REG_HWSTAM, 0xffff); 164 I830_WRITE16(I830REG_INT_MASK_R, 0x0); 165 I830_WRITE16(I830REG_INT_ENABLE_R, 0x0); 166 atomic_set(&dev_priv->irq_received, 0); 167 atomic_set(&dev_priv->irq_emitted, 0); 168 init_waitqueue_head(&dev_priv->irq_queue); 169} 170 171void i830_driver_irq_postinstall(struct drm_device *dev) 172{ 173 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; 174 175 I830_WRITE16(I830REG_INT_ENABLE_R, 0x2); 176} 177 178void i830_driver_irq_uninstall(struct drm_device *dev) 179{ 180 drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; 181 if (!dev_priv) 182 return; 183 184 I830_WRITE16(I830REG_INT_MASK_R, 0xffff); 185 I830_WRITE16(I830REG_INT_ENABLE_R, 0x0); 186} 187