linux/drivers/gpu/drm/i830/i830_irq.c
<<
>>
Prefs
   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