This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / char / drm / i915_irq.c
1 /* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
2  */
3 /**************************************************************************
4  * 
5  * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
6  * All Rights Reserved.
7  * 
8  **************************************************************************/
9
10 #include "i915.h"
11 #include "drmP.h"
12 #include "drm.h"
13 #include "i915_drm.h"
14 #include "i915_drv.h"
15
16 #define USER_INT_FLAG 0x2
17 #define MAX_NOPID ((u32)~0)
18 #define READ_BREADCRUMB(dev_priv)  (((u32*)(dev_priv->hw_status_page))[5])
19
20 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
21 {
22         drm_device_t *dev = (drm_device_t *) arg;
23         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
24         u16 temp;
25
26         temp = I915_READ16(I915REG_INT_IDENTITY_R);
27         temp &= USER_INT_FLAG;
28
29         DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
30
31         if (temp == 0)
32                 return IRQ_NONE;
33
34         I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
35         DRM_WAKEUP(&dev_priv->irq_queue);
36
37         return IRQ_HANDLED;
38 }
39
40 int i915_emit_irq(drm_device_t * dev)
41 {
42         drm_i915_private_t *dev_priv = dev->dev_private;
43         u32 ret;
44         RING_LOCALS;
45
46         i915_kernel_lost_context(dev);
47
48         DRM_DEBUG("%s\n", __FUNCTION__);
49
50         ret = dev_priv->counter;
51
52         BEGIN_LP_RING(2);
53         OUT_RING(0);
54         OUT_RING(GFX_OP_USER_INTERRUPT);
55         ADVANCE_LP_RING();
56
57         return ret;
58 }
59
60 int i915_wait_irq(drm_device_t * dev, int irq_nr)
61 {
62         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
63         int ret = 0;
64
65         DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr,
66                   READ_BREADCRUMB(dev_priv));
67
68         if (READ_BREADCRUMB(dev_priv) >= irq_nr)
69                 return 0;
70
71         dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
72
73         DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
74                     READ_BREADCRUMB(dev_priv) >= irq_nr);
75
76         if (ret == DRM_ERR(EBUSY)) {
77                 DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
78                           __FUNCTION__,
79                           READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
80         }
81
82         dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
83         return ret;
84 }
85
86 /* Needs the lock as it touches the ring.
87  */
88 int i915_irq_emit(DRM_IOCTL_ARGS)
89 {
90         DRM_DEVICE;
91         drm_i915_private_t *dev_priv = dev->dev_private;
92         drm_i915_irq_emit_t emit;
93         int result;
94
95         if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
96                 DRM_ERROR("i915_irq_emit called without lock held\n");
97                 return DRM_ERR(EINVAL);
98         }
99
100         if (!dev_priv) {
101                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
102                 return DRM_ERR(EINVAL);
103         }
104
105         DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data,
106                                  sizeof(emit));
107
108         result = i915_emit_irq(dev);
109
110         if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
111                 DRM_ERROR("copy_to_user\n");
112                 return DRM_ERR(EFAULT);
113         }
114
115         return 0;
116 }
117
118 /* Doesn't need the hardware lock.
119  */
120 int i915_irq_wait(DRM_IOCTL_ARGS)
121 {
122         DRM_DEVICE;
123         drm_i915_private_t *dev_priv = dev->dev_private;
124         drm_i915_irq_wait_t irqwait;
125
126         if (!dev_priv) {
127                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
128                 return DRM_ERR(EINVAL);
129         }
130
131         DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data,
132                                  sizeof(irqwait));
133
134         return i915_wait_irq(dev, irqwait.irq_seq);
135 }
136
137 /* drm_dma.h hooks
138 */
139 void i915_driver_irq_preinstall(drm_device_t * dev)
140 {
141         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
142
143         I915_WRITE16(I915REG_HWSTAM, 0xfffe);
144         I915_WRITE16(I915REG_INT_MASK_R, 0x0);
145         I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
146 }
147
148 void i915_driver_irq_postinstall(drm_device_t * dev)
149 {
150         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
151
152         I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG);
153         DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
154 }
155
156 void i915_driver_irq_uninstall(drm_device_t * dev)
157 {
158         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
159         if (!dev_priv)
160                 return;
161
162         I915_WRITE16(I915REG_HWSTAM, 0xffff);
163         I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
164         I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
165 }