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