drm/cred: wrap task credential accesses in the drm driver.
[linux-block.git] / drivers / gpu / drm / i915 / i915_irq.c
CommitLineData
0d6aa60b 1/* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
1da177e4 2 */
0d6aa60b 3/*
1da177e4
LT
4 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
5 * All Rights Reserved.
bc54fd1a
DA
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 *
0d6aa60b 27 */
1da177e4
LT
28
29#include "drmP.h"
30#include "drm.h"
31#include "i915_drm.h"
32#include "i915_drv.h"
33
1da177e4 34#define MAX_NOPID ((u32)~0)
1da177e4 35
ed4cb414
EA
36/** These are the interrupts used by the driver */
37#define I915_INTERRUPT_ENABLE_MASK (I915_USER_INTERRUPT | \
38 I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT | \
8ee1c3db
MG
39 I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT | \
40 I915_ASLE_INTERRUPT | \
41 I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
ed4cb414 42
8ee1c3db 43void
ed4cb414
EA
44i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
45{
46 if ((dev_priv->irq_mask_reg & mask) != 0) {
47 dev_priv->irq_mask_reg &= ~mask;
48 I915_WRITE(IMR, dev_priv->irq_mask_reg);
49 (void) I915_READ(IMR);
50 }
51}
52
53static inline void
54i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
55{
56 if ((dev_priv->irq_mask_reg & mask) != mask) {
57 dev_priv->irq_mask_reg |= mask;
58 I915_WRITE(IMR, dev_priv->irq_mask_reg);
59 (void) I915_READ(IMR);
60 }
61}
62
a6b54f3f
MCA
63/**
64 * Emit blits for scheduled buffer swaps.
65 *
66 * This function will be called with the HW lock held.
67 */
84b1fd10 68static void i915_vblank_tasklet(struct drm_device *dev)
a6b54f3f
MCA
69{
70 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
af6061af 71 unsigned long irqflags;
3188a24c 72 struct list_head *list, *tmp, hits, *hit;
af6061af
DA
73 int nhits, nrects, slice[2], upper[2], lower[2], i;
74 unsigned counter[2] = { atomic_read(&dev->vbl_received),
75 atomic_read(&dev->vbl_received2) };
c60ce623 76 struct drm_drawable_info *drw;
3188a24c 77 drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
af6061af 78 u32 cpp = dev_priv->cpp;
3188a24c
MCA
79 u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
80 XY_SRC_COPY_BLT_WRITE_ALPHA |
81 XY_SRC_COPY_BLT_WRITE_RGB)
82 : XY_SRC_COPY_BLT_CMD;
7b832b56
KP
83 u32 src_pitch = sarea_priv->pitch * cpp;
84 u32 dst_pitch = sarea_priv->pitch * cpp;
85 u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24);
3188a24c 86 RING_LOCALS;
a6b54f3f 87
3d25802e 88 if (IS_I965G(dev) && sarea_priv->front_tiled) {
7b832b56
KP
89 cmd |= XY_SRC_COPY_BLT_DST_TILED;
90 dst_pitch >>= 2;
91 }
3d25802e 92 if (IS_I965G(dev) && sarea_priv->back_tiled) {
7b832b56
KP
93 cmd |= XY_SRC_COPY_BLT_SRC_TILED;
94 src_pitch >>= 2;
95 }
96
a6b54f3f
MCA
97 DRM_DEBUG("\n");
98
3188a24c
MCA
99 INIT_LIST_HEAD(&hits);
100
101 nhits = nrects = 0;
102
af6061af 103 spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
a6b54f3f 104
3188a24c 105 /* Find buffer swaps scheduled for this vertical blank */
a6b54f3f
MCA
106 list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
107 drm_i915_vbl_swap_t *vbl_swap =
108 list_entry(list, drm_i915_vbl_swap_t, head);
a6b54f3f 109
af6061af 110 if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
3188a24c
MCA
111 continue;
112
113 list_del(list);
114 dev_priv->swaps_pending--;
115
116 spin_unlock(&dev_priv->swaps_lock);
117 spin_lock(&dev->drw_lock);
a6b54f3f 118
3188a24c 119 drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
a6b54f3f 120
3188a24c
MCA
121 if (!drw) {
122 spin_unlock(&dev->drw_lock);
123 drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
124 spin_lock(&dev_priv->swaps_lock);
125 continue;
126 }
a6b54f3f 127
3188a24c
MCA
128 list_for_each(hit, &hits) {
129 drm_i915_vbl_swap_t *swap_cmp =
130 list_entry(hit, drm_i915_vbl_swap_t, head);
c60ce623 131 struct drm_drawable_info *drw_cmp =
3188a24c 132 drm_get_drawable_info(dev, swap_cmp->drw_id);
a6b54f3f 133
3188a24c
MCA
134 if (drw_cmp &&
135 drw_cmp->rects[0].y1 > drw->rects[0].y1) {
136 list_add_tail(list, hit);
137 break;
a6b54f3f 138 }
3188a24c 139 }
a6b54f3f 140
3188a24c 141 spin_unlock(&dev->drw_lock);
a6b54f3f 142
3188a24c
MCA
143 /* List of hits was empty, or we reached the end of it */
144 if (hit == &hits)
145 list_add_tail(list, hits.prev);
a6b54f3f 146
3188a24c 147 nhits++;
a6b54f3f 148
3188a24c
MCA
149 spin_lock(&dev_priv->swaps_lock);
150 }
151
af6061af
DA
152 if (nhits == 0) {
153 spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
ac741ab7 154 return;
af6061af
DA
155 }
156
157 spin_unlock(&dev_priv->swaps_lock);
3188a24c 158
ac741ab7 159 i915_kernel_lost_context(dev);
3188a24c 160
af6061af
DA
161 if (IS_I965G(dev)) {
162 BEGIN_LP_RING(4);
163
164 OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
165 OUT_RING(0);
166 OUT_RING(((sarea_priv->width - 1) & 0xffff) | ((sarea_priv->height - 1) << 16));
167 OUT_RING(0);
168 ADVANCE_LP_RING();
169 } else {
170 BEGIN_LP_RING(6);
ac741ab7 171
af6061af
DA
172 OUT_RING(GFX_OP_DRAWRECT_INFO);
173 OUT_RING(0);
174 OUT_RING(0);
175 OUT_RING(sarea_priv->width | sarea_priv->height << 16);
176 OUT_RING(sarea_priv->width | sarea_priv->height << 16);
177 OUT_RING(0);
178
179 ADVANCE_LP_RING();
180 }
181
182 sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
183
184 upper[0] = upper[1] = 0;
185 slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
186 slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
187 lower[0] = sarea_priv->pipeA_y + slice[0];
188 lower[1] = sarea_priv->pipeB_y + slice[0];
3188a24c
MCA
189
190 spin_lock(&dev->drw_lock);
191
192 /* Emit blits for buffer swaps, partitioning both outputs into as many
193 * slices as there are buffer swaps scheduled in order to avoid tearing
194 * (based on the assumption that a single buffer swap would always
195 * complete before scanout starts).
196 */
197 for (i = 0; i++ < nhits;
198 upper[0] = lower[0], lower[0] += slice[0],
199 upper[1] = lower[1], lower[1] += slice[1]) {
200 if (i == nhits)
201 lower[0] = lower[1] = sarea_priv->height;
202
203 list_for_each(hit, &hits) {
204 drm_i915_vbl_swap_t *swap_hit =
205 list_entry(hit, drm_i915_vbl_swap_t, head);
c60ce623 206 struct drm_clip_rect *rect;
af6061af 207 int num_rects, pipe;
3188a24c
MCA
208 unsigned short top, bottom;
209
210 drw = drm_get_drawable_info(dev, swap_hit->drw_id);
211
212 if (!drw)
213 continue;
214
215 rect = drw->rects;
af6061af
DA
216 pipe = swap_hit->pipe;
217 top = upper[pipe];
218 bottom = lower[pipe];
3188a24c
MCA
219
220 for (num_rects = drw->num_rects; num_rects--; rect++) {
221 int y1 = max(rect->y1, top);
222 int y2 = min(rect->y2, bottom);
223
224 if (y1 >= y2)
225 continue;
226
227 BEGIN_LP_RING(8);
228
229 OUT_RING(cmd);
7b832b56 230 OUT_RING(ropcpp | dst_pitch);
3188a24c
MCA
231 OUT_RING((y1 << 16) | rect->x1);
232 OUT_RING((y2 << 16) | rect->x2);
af6061af 233 OUT_RING(sarea_priv->front_offset);
3188a24c 234 OUT_RING((y1 << 16) | rect->x1);
7b832b56 235 OUT_RING(src_pitch);
af6061af 236 OUT_RING(sarea_priv->back_offset);
3188a24c
MCA
237
238 ADVANCE_LP_RING();
239 }
a6b54f3f
MCA
240 }
241 }
242
af6061af 243 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
3188a24c
MCA
244
245 list_for_each_safe(hit, tmp, &hits) {
246 drm_i915_vbl_swap_t *swap_hit =
247 list_entry(hit, drm_i915_vbl_swap_t, head);
248
249 list_del(hit);
250
251 drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER);
252 }
a6b54f3f
MCA
253}
254
1da177e4
LT
255irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
256{
84b1fd10 257 struct drm_device *dev = (struct drm_device *) arg;
1da177e4 258 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
e4a7b1d1 259 u32 pipea_stats, pipeb_stats;
ed4cb414 260 u32 iir;
1da177e4 261
585fb111
JB
262 pipea_stats = I915_READ(PIPEASTAT);
263 pipeb_stats = I915_READ(PIPEBSTAT);
6e5fca53 264
ed4cb414
EA
265 if (dev->pdev->msi_enabled)
266 I915_WRITE(IMR, ~0);
267 iir = I915_READ(IIR);
a6b54f3f 268
ed4cb414 269 DRM_DEBUG("iir=%08x\n", iir);
af6061af 270
ed4cb414
EA
271 if (iir == 0) {
272 if (dev->pdev->msi_enabled) {
273 I915_WRITE(IMR, dev_priv->irq_mask_reg);
274 (void) I915_READ(IMR);
275 }
af6061af 276 return IRQ_NONE;
ed4cb414 277 }
af6061af 278
8ee1c3db
MG
279 I915_WRITE(PIPEASTAT, pipea_stats);
280 I915_WRITE(PIPEBSTAT, pipeb_stats);
281
ed4cb414
EA
282 I915_WRITE(IIR, iir);
283 if (dev->pdev->msi_enabled)
284 I915_WRITE(IMR, dev_priv->irq_mask_reg);
285 (void) I915_READ(IIR); /* Flush posted writes */
af6061af
DA
286
287 dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
288
ed4cb414 289 if (iir & I915_USER_INTERRUPT)
ac741ab7 290 DRM_WAKEUP(&dev_priv->irq_queue);
af6061af 291
ed4cb414
EA
292 if (iir & (I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
293 I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)) {
af6061af
DA
294 int vblank_pipe = dev_priv->vblank_pipe;
295
296 if ((vblank_pipe &
297 (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
298 == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
ed4cb414 299 if (iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT)
af6061af 300 atomic_inc(&dev->vbl_received);
ed4cb414 301 if (iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)
af6061af 302 atomic_inc(&dev->vbl_received2);
ed4cb414 303 } else if (((iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) &&
af6061af 304 (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
ed4cb414 305 ((iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) &&
af6061af
DA
306 (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
307 atomic_inc(&dev->vbl_received);
308
309 DRM_WAKEUP(&dev->vbl_queue);
310 drm_vbl_send_signals(dev);
311
2228ed67
MCA
312 if (dev_priv->swaps_pending > 0)
313 drm_locked_tasklet(dev, i915_vblank_tasklet);
0d6aa60b 314 }
1da177e4 315
8ee1c3db
MG
316 if (iir & I915_ASLE_INTERRUPT)
317 opregion_asle_intr(dev);
318
319 if (iir & I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
320 opregion_asle_intr(dev);
321
1da177e4
LT
322 return IRQ_HANDLED;
323}
324
af6061af 325static int i915_emit_irq(struct drm_device * dev)
1da177e4
LT
326{
327 drm_i915_private_t *dev_priv = dev->dev_private;
1da177e4
LT
328 RING_LOCALS;
329
330 i915_kernel_lost_context(dev);
331
3e684eae 332 DRM_DEBUG("\n");
1da177e4 333
c29b669c 334 dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
1da177e4 335
c29b669c
AH
336 if (dev_priv->counter > 0x7FFFFFFFUL)
337 dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
338
339 BEGIN_LP_RING(6);
585fb111
JB
340 OUT_RING(MI_STORE_DWORD_INDEX);
341 OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
c29b669c
AH
342 OUT_RING(dev_priv->counter);
343 OUT_RING(0);
1da177e4 344 OUT_RING(0);
585fb111 345 OUT_RING(MI_USER_INTERRUPT);
1da177e4 346 ADVANCE_LP_RING();
bc5f4523 347
c29b669c 348 return dev_priv->counter;
1da177e4
LT
349}
350
ed4cb414
EA
351static void i915_user_irq_get(struct drm_device *dev)
352{
353 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
354
355 spin_lock(&dev_priv->user_irq_lock);
356 if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1))
357 i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
358 spin_unlock(&dev_priv->user_irq_lock);
359}
360
361static void i915_user_irq_put(struct drm_device *dev)
362{
363 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
364
365 spin_lock(&dev_priv->user_irq_lock);
366 BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
367 if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0))
368 i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
369 spin_unlock(&dev_priv->user_irq_lock);
370}
371
84b1fd10 372static int i915_wait_irq(struct drm_device * dev, int irq_nr)
1da177e4
LT
373{
374 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
375 int ret = 0;
376
3e684eae 377 DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
1da177e4
LT
378 READ_BREADCRUMB(dev_priv));
379
ed4cb414
EA
380 if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
381 dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
1da177e4 382 return 0;
ed4cb414 383 }
1da177e4
LT
384
385 dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
386
ed4cb414 387 i915_user_irq_get(dev);
1da177e4
LT
388 DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
389 READ_BREADCRUMB(dev_priv) >= irq_nr);
ed4cb414 390 i915_user_irq_put(dev);
1da177e4 391
20caafa6 392 if (ret == -EBUSY) {
3e684eae 393 DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
1da177e4
LT
394 READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
395 }
396
af6061af 397 dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
1da177e4
LT
398 return ret;
399}
400
af6061af
DA
401static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence,
402 atomic_t *counter)
403{
404 drm_i915_private_t *dev_priv = dev->dev_private;
405 unsigned int cur_vblank;
406 int ret = 0;
407
408 if (!dev_priv) {
409 DRM_ERROR("called with no initialization\n");
410 return -EINVAL;
411 }
412
413 DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
414 (((cur_vblank = atomic_read(counter))
415 - *sequence) <= (1<<23)));
416
417 *sequence = cur_vblank;
418
419 return ret;
420}
421
422
423int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
424{
425 return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
426}
427
428int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
429{
430 return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
431}
432
1da177e4
LT
433/* Needs the lock as it touches the ring.
434 */
c153f45f
EA
435int i915_irq_emit(struct drm_device *dev, void *data,
436 struct drm_file *file_priv)
1da177e4 437{
1da177e4 438 drm_i915_private_t *dev_priv = dev->dev_private;
c153f45f 439 drm_i915_irq_emit_t *emit = data;
1da177e4
LT
440 int result;
441
6c340eac 442 LOCK_TEST_WITH_RETURN(dev, file_priv);
1da177e4
LT
443
444 if (!dev_priv) {
3e684eae 445 DRM_ERROR("called with no initialization\n");
20caafa6 446 return -EINVAL;
1da177e4
LT
447 }
448
1da177e4
LT
449 result = i915_emit_irq(dev);
450
c153f45f 451 if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
1da177e4 452 DRM_ERROR("copy_to_user\n");
20caafa6 453 return -EFAULT;
1da177e4
LT
454 }
455
456 return 0;
457}
458
459/* Doesn't need the hardware lock.
460 */
c153f45f
EA
461int i915_irq_wait(struct drm_device *dev, void *data,
462 struct drm_file *file_priv)
1da177e4 463{
1da177e4 464 drm_i915_private_t *dev_priv = dev->dev_private;
c153f45f 465 drm_i915_irq_wait_t *irqwait = data;
1da177e4
LT
466
467 if (!dev_priv) {
3e684eae 468 DRM_ERROR("called with no initialization\n");
20caafa6 469 return -EINVAL;
1da177e4
LT
470 }
471
c153f45f 472 return i915_wait_irq(dev, irqwait->irq_seq);
1da177e4
LT
473}
474
702880f2
DA
475/* Set the vblank monitor pipe
476 */
c153f45f
EA
477int i915_vblank_pipe_set(struct drm_device *dev, void *data,
478 struct drm_file *file_priv)
702880f2 479{
702880f2 480 drm_i915_private_t *dev_priv = dev->dev_private;
c153f45f 481 drm_i915_vblank_pipe_t *pipe = data;
ed4cb414 482 u32 enable_mask = 0, disable_mask = 0;
702880f2
DA
483
484 if (!dev_priv) {
3e684eae 485 DRM_ERROR("called with no initialization\n");
20caafa6 486 return -EINVAL;
702880f2
DA
487 }
488
c153f45f 489 if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
3e684eae 490 DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe);
20caafa6 491 return -EINVAL;
5b51694a
MCA
492 }
493
ed4cb414
EA
494 if (pipe->pipe & DRM_I915_VBLANK_PIPE_A)
495 enable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
496 else
497 disable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
498
499 if (pipe->pipe & DRM_I915_VBLANK_PIPE_B)
500 enable_mask |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
501 else
502 disable_mask |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
5b51694a 503
ed4cb414
EA
504 i915_enable_irq(dev_priv, enable_mask);
505 i915_disable_irq(dev_priv, disable_mask);
506
507 dev_priv->vblank_pipe = pipe->pipe;
af6061af 508
5b51694a 509 return 0;
702880f2
DA
510}
511
c153f45f
EA
512int i915_vblank_pipe_get(struct drm_device *dev, void *data,
513 struct drm_file *file_priv)
702880f2 514{
702880f2 515 drm_i915_private_t *dev_priv = dev->dev_private;
c153f45f 516 drm_i915_vblank_pipe_t *pipe = data;
702880f2
DA
517 u16 flag;
518
519 if (!dev_priv) {
3e684eae 520 DRM_ERROR("called with no initialization\n");
20caafa6 521 return -EINVAL;
702880f2
DA
522 }
523
ed4cb414 524 flag = I915_READ(IMR);
c153f45f 525 pipe->pipe = 0;
585fb111 526 if (flag & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT)
c153f45f 527 pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
585fb111 528 if (flag & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT)
c153f45f
EA
529 pipe->pipe |= DRM_I915_VBLANK_PIPE_B;
530
702880f2
DA
531 return 0;
532}
533
a6b54f3f
MCA
534/**
535 * Schedule buffer swap at given vertical blank.
536 */
c153f45f
EA
537int i915_vblank_swap(struct drm_device *dev, void *data,
538 struct drm_file *file_priv)
a6b54f3f 539{
a6b54f3f 540 drm_i915_private_t *dev_priv = dev->dev_private;
c153f45f 541 drm_i915_vblank_swap_t *swap = data;
a6b54f3f 542 drm_i915_vbl_swap_t *vbl_swap;
af6061af 543 unsigned int pipe, seqtype, curseq;
a0b136bb 544 unsigned long irqflags;
a6b54f3f
MCA
545 struct list_head *list;
546
547 if (!dev_priv) {
548 DRM_ERROR("%s called with no initialization\n", __func__);
20caafa6 549 return -EINVAL;
a6b54f3f
MCA
550 }
551
af6061af 552 if (dev_priv->sarea_priv->rotation) {
a6b54f3f 553 DRM_DEBUG("Rotation not supported\n");
20caafa6 554 return -EINVAL;
a6b54f3f
MCA
555 }
556
c153f45f 557 if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
af6061af 558 _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
c153f45f 559 DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
20caafa6 560 return -EINVAL;
541f29aa
MCA
561 }
562
af6061af 563 pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
541f29aa 564
c153f45f 565 seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
541f29aa 566
541f29aa
MCA
567 if (!(dev_priv->vblank_pipe & (1 << pipe))) {
568 DRM_ERROR("Invalid pipe %d\n", pipe);
20caafa6 569 return -EINVAL;
a6b54f3f
MCA
570 }
571
572 spin_lock_irqsave(&dev->drw_lock, irqflags);
573
c153f45f 574 if (!drm_get_drawable_info(dev, swap->drawable)) {
a6b54f3f 575 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
c153f45f 576 DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
20caafa6 577 return -EINVAL;
a6b54f3f
MCA
578 }
579
580 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
581
af6061af 582 curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
541f29aa 583
2228ed67 584 if (seqtype == _DRM_VBLANK_RELATIVE)
c153f45f 585 swap->sequence += curseq;
2228ed67 586
c153f45f
EA
587 if ((curseq - swap->sequence) <= (1<<23)) {
588 if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) {
589 swap->sequence = curseq + 1;
2228ed67 590 } else {
541f29aa 591 DRM_DEBUG("Missed target sequence\n");
20caafa6 592 return -EINVAL;
541f29aa 593 }
541f29aa
MCA
594 }
595
2228ed67
MCA
596 spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
597
a6b54f3f
MCA
598 list_for_each(list, &dev_priv->vbl_swaps.head) {
599 vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
600
c153f45f 601 if (vbl_swap->drw_id == swap->drawable &&
af6061af 602 vbl_swap->pipe == pipe &&
c153f45f 603 vbl_swap->sequence == swap->sequence) {
a6b54f3f
MCA
604 spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
605 DRM_DEBUG("Already scheduled\n");
606 return 0;
607 }
608 }
609
610 spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
611
21fa60ed
MCA
612 if (dev_priv->swaps_pending >= 100) {
613 DRM_DEBUG("Too many swaps queued\n");
20caafa6 614 return -EBUSY;
21fa60ed
MCA
615 }
616
54583bf4 617 vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
a6b54f3f
MCA
618
619 if (!vbl_swap) {
620 DRM_ERROR("Failed to allocate memory to queue swap\n");
20caafa6 621 return -ENOMEM;
a6b54f3f
MCA
622 }
623
624 DRM_DEBUG("\n");
625
c153f45f 626 vbl_swap->drw_id = swap->drawable;
af6061af 627 vbl_swap->pipe = pipe;
c153f45f 628 vbl_swap->sequence = swap->sequence;
a6b54f3f
MCA
629
630 spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
631
d5b0d1b5 632 list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head);
a6b54f3f
MCA
633 dev_priv->swaps_pending++;
634
635 spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
636
637 return 0;
638}
639
1da177e4
LT
640/* drm_dma.h hooks
641*/
84b1fd10 642void i915_driver_irq_preinstall(struct drm_device * dev)
1da177e4
LT
643{
644 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
645
ed4cb414
EA
646 I915_WRITE(HWSTAM, 0xfffe);
647 I915_WRITE(IMR, 0x0);
648 I915_WRITE(IER, 0x0);
1da177e4
LT
649}
650
af6061af 651void i915_driver_irq_postinstall(struct drm_device * dev)
1da177e4
LT
652{
653 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
654
a6399bdd 655 spin_lock_init(&dev_priv->swaps_lock);
a6b54f3f
MCA
656 INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
657 dev_priv->swaps_pending = 0;
658
af6061af
DA
659 if (!dev_priv->vblank_pipe)
660 dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
ed4cb414
EA
661
662 /* Set initial unmasked IRQs to just the selected vblank pipes. */
663 dev_priv->irq_mask_reg = ~0;
664 if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
665 dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
666 if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
667 dev_priv->irq_mask_reg &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
668
8ee1c3db
MG
669 dev_priv->irq_mask_reg &= I915_INTERRUPT_ENABLE_MASK;
670
ed4cb414
EA
671 I915_WRITE(IMR, dev_priv->irq_mask_reg);
672 I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
673 (void) I915_READ(IER);
674
8ee1c3db
MG
675 opregion_enable_asle(dev);
676
1da177e4
LT
677 DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
678}
679
84b1fd10 680void i915_driver_irq_uninstall(struct drm_device * dev)
1da177e4
LT
681{
682 drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
af6061af 683 u16 temp;
91e3738e 684
1da177e4
LT
685 if (!dev_priv)
686 return;
687
ed4cb414
EA
688 I915_WRITE(HWSTAM, 0xffff);
689 I915_WRITE(IMR, 0xffff);
690 I915_WRITE(IER, 0x0);
af6061af 691
ed4cb414
EA
692 temp = I915_READ(IIR);
693 I915_WRITE(IIR, temp);
1da177e4 694}