OSDN Git Service

Revert "drm/ttm: cleanup mm_ioctl ioctls to be separate ioctls."
[android-x86/external-libdrm.git] / shared-core / 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 /**
41  * Emit a synchronous flip.
42  *
43  * This function must be called with the drawable spinlock held.
44  */
45 static void
46 i915_dispatch_vsync_flip(drm_device_t *dev, drm_drawable_info_t *drw, int pipe)
47 {
48         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
49         drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
50         u16 x1, y1, x2, y2;
51         int pf_pipes = 1 << pipe;
52
53         /* If the window is visible on the other pipe, we have to flip on that
54          * pipe as well.
55          */
56         if (pipe == 1) {
57                 x1 = sarea_priv->pipeA_x;
58                 y1 = sarea_priv->pipeA_y;
59                 x2 = x1 + sarea_priv->pipeA_w;
60                 y2 = y1 + sarea_priv->pipeA_h;
61         } else {
62                 x1 = sarea_priv->pipeB_x;
63                 y1 = sarea_priv->pipeB_y;
64                 x2 = x1 + sarea_priv->pipeB_w;
65                 y2 = y1 + sarea_priv->pipeB_h;
66         }
67
68         if (x2 > 0 && y2 > 0) {
69                 int i, num_rects = drw->num_rects;
70                 drm_clip_rect_t *rect = drw->rects;
71
72                 for (i = 0; i < num_rects; i++)
73                         if (!(rect[i].x1 >= x2 || rect[i].y1 >= y2 ||
74                               rect[i].x2 <= x1 || rect[i].y2 <= y1)) {
75                                 pf_pipes = 0x3;
76
77                                 break;
78                         }
79         }
80
81         i915_dispatch_flip(dev, pf_pipes, 1);
82 }
83
84 /**
85  * Emit blits for scheduled buffer swaps.
86  *
87  * This function will be called with the HW lock held.
88  */
89 static void i915_vblank_tasklet(drm_device_t *dev)
90 {
91         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
92         unsigned long irqflags;
93         struct list_head *list, *tmp, hits, *hit;
94         int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages;
95         unsigned counter[2] = { atomic_read(&dev->vbl_received),
96                                 atomic_read(&dev->vbl_received2) };
97         drm_drawable_info_t *drw;
98         drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
99         u32 cpp = dev_priv->cpp,  offsets[3];
100         u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
101                                 XY_SRC_COPY_BLT_WRITE_ALPHA |
102                                 XY_SRC_COPY_BLT_WRITE_RGB)
103                              : XY_SRC_COPY_BLT_CMD;
104         u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
105                           (cpp << 23) | (1 << 24);
106         RING_LOCALS;
107
108         DRM_DEBUG("\n");
109
110         INIT_LIST_HEAD(&hits);
111
112         nhits = nrects = 0;
113
114         spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
115
116         /* Find buffer swaps scheduled for this vertical blank */
117         list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
118                 drm_i915_vbl_swap_t *vbl_swap =
119                         list_entry(list, drm_i915_vbl_swap_t, head);
120
121                 if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
122                         continue;
123
124                 list_del(list);
125                 dev_priv->swaps_pending--;
126
127                 spin_unlock(&dev_priv->swaps_lock);
128                 spin_lock(&dev->drw_lock);
129
130                 drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
131
132                 if (!drw) {
133                         spin_unlock(&dev->drw_lock);
134                         drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
135                         spin_lock(&dev_priv->swaps_lock);
136                         continue;
137                 }
138
139                 list_for_each(hit, &hits) {
140                         drm_i915_vbl_swap_t *swap_cmp =
141                                 list_entry(hit, drm_i915_vbl_swap_t, head);
142                         drm_drawable_info_t *drw_cmp =
143                                 drm_get_drawable_info(dev, swap_cmp->drw_id);
144
145                         if (drw_cmp &&
146                             drw_cmp->rects[0].y1 > drw->rects[0].y1) {
147                                 list_add_tail(list, hit);
148                                 break;
149                         }
150                 }
151
152                 spin_unlock(&dev->drw_lock);
153
154                 /* List of hits was empty, or we reached the end of it */
155                 if (hit == &hits)
156                         list_add_tail(list, hits.prev);
157
158                 nhits++;
159
160                 spin_lock(&dev_priv->swaps_lock);
161         }
162
163         if (nhits == 0) {
164                 spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
165                 return;
166         }
167
168         spin_unlock(&dev_priv->swaps_lock);
169
170         i915_kernel_lost_context(dev);
171
172         upper[0] = upper[1] = 0;
173         slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
174         slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
175         lower[0] = sarea_priv->pipeA_y + slice[0];
176         lower[1] = sarea_priv->pipeB_y + slice[0];
177
178         offsets[0] = sarea_priv->front_offset;
179         offsets[1] = sarea_priv->back_offset;
180         offsets[2] = sarea_priv->third_offset;
181         num_pages = sarea_priv->third_handle ? 3 : 2;
182
183         spin_lock(&dev->drw_lock);
184
185         /* Emit blits for buffer swaps, partitioning both outputs into as many
186          * slices as there are buffer swaps scheduled in order to avoid tearing
187          * (based on the assumption that a single buffer swap would always
188          * complete before scanout starts).
189          */
190         for (i = 0; i++ < nhits;
191              upper[0] = lower[0], lower[0] += slice[0],
192              upper[1] = lower[1], lower[1] += slice[1]) {
193                 int init_drawrect = 1;
194
195                 if (i == nhits)
196                         lower[0] = lower[1] = sarea_priv->height;
197
198                 list_for_each(hit, &hits) {
199                         drm_i915_vbl_swap_t *swap_hit =
200                                 list_entry(hit, drm_i915_vbl_swap_t, head);
201                         drm_clip_rect_t *rect;
202                         int num_rects, pipe, front, back;
203                         unsigned short top, bottom;
204
205                         drw = drm_get_drawable_info(dev, swap_hit->drw_id);
206
207                         if (!drw)
208                                 continue;
209
210                         pipe = swap_hit->pipe;
211
212                         if (swap_hit->flip) {
213                                 i915_dispatch_vsync_flip(dev, drw, pipe);
214                                 continue;
215                         }
216
217                         if (init_drawrect) {
218                                 BEGIN_LP_RING(6);
219
220                                 OUT_RING(GFX_OP_DRAWRECT_INFO);
221                                 OUT_RING(0);
222                                 OUT_RING(0);
223                                 OUT_RING(sarea_priv->width | sarea_priv->height << 16);
224                                 OUT_RING(sarea_priv->width | sarea_priv->height << 16);
225                                 OUT_RING(0);
226
227                                 ADVANCE_LP_RING();
228
229                                 sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;
230
231                                 init_drawrect = 0;
232                         }
233
234                         rect = drw->rects;
235                         top = upper[pipe];
236                         bottom = lower[pipe];
237
238                         front = (dev_priv->sarea_priv->pf_current_page >>
239                                  (2 * pipe)) & 0x3;
240                         back = (front + 1) % num_pages;
241
242                         for (num_rects = drw->num_rects; num_rects--; rect++) {
243                                 int y1 = max(rect->y1, top);
244                                 int y2 = min(rect->y2, bottom);
245
246                                 if (y1 >= y2)
247                                         continue;
248
249                                 BEGIN_LP_RING(8);
250
251                                 OUT_RING(cmd);
252                                 OUT_RING(pitchropcpp);
253                                 OUT_RING((y1 << 16) | rect->x1);
254                                 OUT_RING((y2 << 16) | rect->x2);
255                                 OUT_RING(offsets[front]);
256                                 OUT_RING((y1 << 16) | rect->x1);
257                                 OUT_RING(pitchropcpp & 0xffff);
258                                 OUT_RING(offsets[back]);
259
260                                 ADVANCE_LP_RING();
261                         }
262                 }
263         }
264
265         spin_unlock_irqrestore(&dev->drw_lock, irqflags);
266
267         list_for_each_safe(hit, tmp, &hits) {
268                 drm_i915_vbl_swap_t *swap_hit =
269                         list_entry(hit, drm_i915_vbl_swap_t, head);
270
271                 list_del(hit);
272
273                 drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER);
274         }
275 }
276
277 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
278 {
279         drm_device_t *dev = (drm_device_t *) arg;
280         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
281         u16 temp;
282         u32 pipea_stats, pipeb_stats;
283
284         pipea_stats = I915_READ(I915REG_PIPEASTAT);
285         pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
286                 
287         temp = I915_READ16(I915REG_INT_IDENTITY_R);
288         temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG);
289
290 #if 0
291         DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
292 #endif
293         if (temp == 0)
294                 return IRQ_NONE;
295
296         I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
297         (void) I915_READ16(I915REG_INT_IDENTITY_R);
298         DRM_READMEMORYBARRIER();
299
300         dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
301
302         if (temp & USER_INT_FLAG) {
303                 DRM_WAKEUP(&dev_priv->irq_queue);
304 #ifdef I915_HAVE_FENCE
305                 i915_fence_handler(dev);
306 #endif
307         }
308
309         if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
310                 int vblank_pipe = dev_priv->vblank_pipe;
311
312                 if ((vblank_pipe &
313                      (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
314                     == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
315                         if (temp & VSYNC_PIPEA_FLAG)
316                                 atomic_inc(&dev->vbl_received);
317                         if (temp & VSYNC_PIPEB_FLAG)
318                                 atomic_inc(&dev->vbl_received2);
319                 } else if (((temp & VSYNC_PIPEA_FLAG) &&
320                             (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
321                            ((temp & VSYNC_PIPEB_FLAG) &&
322                             (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
323                         atomic_inc(&dev->vbl_received);
324
325                 DRM_WAKEUP(&dev->vbl_queue);
326                 drm_vbl_send_signals(dev);
327
328                 if (dev_priv->swaps_pending > 0)
329                         drm_locked_tasklet(dev, i915_vblank_tasklet);
330                 I915_WRITE(I915REG_PIPEASTAT, 
331                         pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
332                         I915_VBLANK_CLEAR);
333                 I915_WRITE(I915REG_PIPEBSTAT,
334                         pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
335                         I915_VBLANK_CLEAR);
336         }
337
338         return IRQ_HANDLED;
339 }
340
341 int i915_emit_irq(drm_device_t * dev)
342 {
343         
344         drm_i915_private_t *dev_priv = dev->dev_private;
345         RING_LOCALS;
346
347         i915_kernel_lost_context(dev);
348
349         DRM_DEBUG("%s\n", __FUNCTION__);
350
351         i915_emit_breadcrumb(dev);
352
353         BEGIN_LP_RING(2);
354         OUT_RING(0);
355         OUT_RING(GFX_OP_USER_INTERRUPT);
356         ADVANCE_LP_RING();
357
358         return dev_priv->counter;
359
360
361 }
362
363 void i915_user_irq_on(drm_i915_private_t *dev_priv)
364 {
365         spin_lock(&dev_priv->user_irq_lock);
366         if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
367                 dev_priv->irq_enable_reg |= USER_INT_FLAG;
368                 I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
369         }
370         spin_unlock(&dev_priv->user_irq_lock);
371
372 }
373                 
374 void i915_user_irq_off(drm_i915_private_t *dev_priv)
375 {
376         spin_lock(&dev_priv->user_irq_lock);
377         if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
378                 //              dev_priv->irq_enable_reg &= ~USER_INT_FLAG;
379                 //              I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
380         }
381         spin_unlock(&dev_priv->user_irq_lock);
382 }
383                 
384 static int wait_compare(struct drm_device *dev, void *priv)
385 {
386         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
387         int irq_nr = (u64)priv;
388
389         return (READ_BREADCRUMB(dev_priv) >= irq_nr);
390 }
391
392 static int i915_wait_irq(drm_device_t * dev, int irq_nr)
393 {
394         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
395         int ret = 0;
396
397         DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr,
398                   READ_BREADCRUMB(dev_priv));
399
400         if (READ_BREADCRUMB(dev_priv) >= irq_nr)
401                 return 0;
402
403         dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
404         
405         i915_user_irq_on(dev_priv);
406         ret = drm_wait_on(dev, &dev_priv->irq_queue, 3 * DRM_HZ, wait_compare,
407                           (void *)(u64)irq_nr);
408         i915_user_irq_off(dev_priv);
409
410         if (ret == DRM_ERR(EBUSY)) {
411                 DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
412                           __FUNCTION__,
413                           READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
414         }
415
416         dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
417         return ret;
418 }
419
420 static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence,
421                                       atomic_t *counter)
422 {
423         drm_i915_private_t *dev_priv = dev->dev_private;
424         unsigned int cur_vblank;
425         int ret = 0;
426
427         if (!dev_priv) {
428                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
429                 return DRM_ERR(EINVAL);
430         }
431
432         DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
433                     (((cur_vblank = atomic_read(counter))
434                         - *sequence) <= (1<<23)));
435         
436         *sequence = cur_vblank;
437
438         return ret;
439 }
440
441 int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
442 {
443         return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
444 }
445
446 int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence)
447 {
448         return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
449 }
450
451 /* Needs the lock as it touches the ring.
452  */
453 int i915_irq_emit(DRM_IOCTL_ARGS)
454 {
455         DRM_DEVICE;
456         drm_i915_private_t *dev_priv = dev->dev_private;
457         drm_i915_irq_emit_t emit;
458         int result;
459
460         LOCK_TEST_WITH_RETURN(dev, filp);
461
462         if (!dev_priv) {
463                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
464                 return DRM_ERR(EINVAL);
465         }
466
467         DRM_COPY_FROM_USER_IOCTL(emit, (drm_i915_irq_emit_t __user *) data,
468                                  sizeof(emit));
469
470         result = i915_emit_irq(dev);
471
472         if (DRM_COPY_TO_USER(emit.irq_seq, &result, sizeof(int))) {
473                 DRM_ERROR("copy_to_user\n");
474                 return DRM_ERR(EFAULT);
475         }
476
477         return 0;
478 }
479
480 /* Doesn't need the hardware lock.
481  */
482 int i915_irq_wait(DRM_IOCTL_ARGS)
483 {
484         DRM_DEVICE;
485         drm_i915_private_t *dev_priv = dev->dev_private;
486         drm_i915_irq_wait_t irqwait;
487
488         if (!dev_priv) {
489                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
490                 return DRM_ERR(EINVAL);
491         }
492
493         DRM_COPY_FROM_USER_IOCTL(irqwait, (drm_i915_irq_wait_t __user *) data,
494                                  sizeof(irqwait));
495
496         return i915_wait_irq(dev, irqwait.irq_seq);
497 }
498
499 static void i915_enable_interrupt (drm_device_t *dev)
500 {
501         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
502         
503         dev_priv->irq_enable_reg = USER_INT_FLAG; 
504         if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
505                 dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
506         if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
507                 dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG;
508
509         I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
510         dev_priv->irq_enabled = 1;
511 }
512
513 /* Set the vblank monitor pipe
514  */
515 int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
516 {
517         DRM_DEVICE;
518         drm_i915_private_t *dev_priv = dev->dev_private;
519         drm_i915_vblank_pipe_t pipe;
520
521         if (!dev_priv) {
522                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
523                 return DRM_ERR(EINVAL);
524         }
525
526         DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
527                                  sizeof(pipe));
528
529         if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
530                 DRM_ERROR("%s called with invalid pipe 0x%x\n", 
531                           __FUNCTION__, pipe.pipe);
532                 return DRM_ERR(EINVAL);
533         }
534
535         dev_priv->vblank_pipe = pipe.pipe;
536
537         i915_enable_interrupt (dev);
538
539         return 0;
540 }
541
542 int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
543 {
544         DRM_DEVICE;
545         drm_i915_private_t *dev_priv = dev->dev_private;
546         drm_i915_vblank_pipe_t pipe;
547         u16 flag;
548
549         if (!dev_priv) {
550                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
551                 return DRM_ERR(EINVAL);
552         }
553
554         flag = I915_READ(I915REG_INT_ENABLE_R);
555         pipe.pipe = 0;
556         if (flag & VSYNC_PIPEA_FLAG)
557                 pipe.pipe |= DRM_I915_VBLANK_PIPE_A;
558         if (flag & VSYNC_PIPEB_FLAG)
559                 pipe.pipe |= DRM_I915_VBLANK_PIPE_B;
560         DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe,
561                                  sizeof(pipe));
562         return 0;
563 }
564
565 /**
566  * Schedule buffer swap at given vertical blank.
567  */
568 int i915_vblank_swap(DRM_IOCTL_ARGS)
569 {
570         DRM_DEVICE;
571         drm_i915_private_t *dev_priv = dev->dev_private;
572         drm_i915_vblank_swap_t swap;
573         drm_i915_vbl_swap_t *vbl_swap;
574         unsigned int pipe, seqtype, curseq;
575         unsigned long irqflags;
576         struct list_head *list;
577
578         if (!dev_priv) {
579                 DRM_ERROR("%s called with no initialization\n", __func__);
580                 return DRM_ERR(EINVAL);
581         }
582
583         if (dev_priv->sarea_priv->rotation) {
584                 DRM_DEBUG("Rotation not supported\n");
585                 return DRM_ERR(EINVAL);
586         }
587
588         DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data,
589                                  sizeof(swap));
590
591         if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
592                              _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS |
593                              _DRM_VBLANK_FLIP)) {
594                 DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype);
595                 return DRM_ERR(EINVAL);
596         }
597
598         pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
599
600         seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
601
602         if (!(dev_priv->vblank_pipe & (1 << pipe))) {
603                 DRM_ERROR("Invalid pipe %d\n", pipe);
604                 return DRM_ERR(EINVAL);
605         }
606
607         spin_lock_irqsave(&dev->drw_lock, irqflags);
608
609         if (!drm_get_drawable_info(dev, swap.drawable)) {
610                 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
611                 DRM_DEBUG("Invalid drawable ID %d\n", swap.drawable);
612                 return DRM_ERR(EINVAL);
613         }
614
615         spin_unlock_irqrestore(&dev->drw_lock, irqflags);
616
617         curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
618
619         if (seqtype == _DRM_VBLANK_RELATIVE)
620                 swap.sequence += curseq;
621
622         if ((curseq - swap.sequence) <= (1<<23)) {
623                 if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) {
624                         swap.sequence = curseq + 1;
625                 } else {
626                         DRM_DEBUG("Missed target sequence\n");
627                         return DRM_ERR(EINVAL);
628                 }
629         }
630
631         if (swap.seqtype & _DRM_VBLANK_FLIP) {
632                 swap.sequence--;
633
634                 if ((curseq - swap.sequence) <= (1<<23)) {
635                         drm_drawable_info_t *drw;
636
637                         LOCK_TEST_WITH_RETURN(dev, filp);
638
639                         spin_lock_irqsave(&dev->drw_lock, irqflags);
640
641                         drw = drm_get_drawable_info(dev, swap.drawable);
642
643                         if (!drw) {
644                                 spin_unlock_irqrestore(&dev->drw_lock, irqflags);
645                                 DRM_DEBUG("Invalid drawable ID %d\n",
646                                           swap.drawable);
647                                 return DRM_ERR(EINVAL);
648                         }
649
650                         i915_dispatch_vsync_flip(dev, drw, pipe);
651
652                         spin_unlock_irqrestore(&dev->drw_lock, irqflags);
653
654                         return 0;
655                 }
656         }
657
658         spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
659
660         list_for_each(list, &dev_priv->vbl_swaps.head) {
661                 vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
662
663                 if (vbl_swap->drw_id == swap.drawable &&
664                     vbl_swap->pipe == pipe &&
665                     vbl_swap->sequence == swap.sequence) {
666                         vbl_swap->flip = (swap.seqtype & _DRM_VBLANK_FLIP);
667                         spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
668                         DRM_DEBUG("Already scheduled\n");
669                         return 0;
670                 }
671         }
672
673         spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
674
675         if (dev_priv->swaps_pending >= 100) {
676                 DRM_DEBUG("Too many swaps queued\n");
677                 return DRM_ERR(EBUSY);
678         }
679
680         vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER);
681
682         if (!vbl_swap) {
683                 DRM_ERROR("Failed to allocate memory to queue swap\n");
684                 return DRM_ERR(ENOMEM);
685         }
686
687         DRM_DEBUG("\n");
688
689         vbl_swap->drw_id = swap.drawable;
690         vbl_swap->pipe = pipe;
691         vbl_swap->sequence = swap.sequence;
692         vbl_swap->flip = (swap.seqtype & _DRM_VBLANK_FLIP);
693
694         if (vbl_swap->flip)
695                 swap.sequence++;
696
697         spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
698
699         list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head);
700         dev_priv->swaps_pending++;
701
702         spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
703
704         DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap,
705                                sizeof(swap));
706
707         return 0;
708 }
709
710 /* drm_dma.h hooks
711 */
712 void i915_driver_irq_preinstall(drm_device_t * dev)
713 {
714         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
715
716         I915_WRITE16(I915REG_HWSTAM, 0xeffe);
717         I915_WRITE16(I915REG_INT_MASK_R, 0x0);
718         I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
719 }
720
721 void i915_driver_irq_postinstall(drm_device_t * dev)
722 {
723         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
724
725         dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED;
726         INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
727         dev_priv->swaps_pending = 0;
728
729         dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED;
730         INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
731         dev_priv->swaps_pending = 0;
732
733         dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED;
734         dev_priv->user_irq_refcount = 0;
735
736         i915_enable_interrupt(dev);
737         DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
738
739         /*
740          * Initialize the hardware status page IRQ location.
741          */
742
743         I915_WRITE(I915REG_INSTPM, ( 1 << 5) | ( 1 << 21));
744 }
745
746 void i915_driver_irq_uninstall(drm_device_t * dev)
747 {
748         drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
749         u16 temp;
750         if (!dev_priv)
751                 return;
752
753         dev_priv->irq_enabled = 0;
754         I915_WRITE16(I915REG_HWSTAM, 0xffff);
755         I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
756         I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
757
758         temp = I915_READ16(I915REG_INT_IDENTITY_R);
759         I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
760 }