i915_irq.c 15.7 KB
Newer Older
D
Dave Airlie 已提交
1
/* i915_irq.c -- IRQ support for the I915 -*- linux-c -*-
L
Linus Torvalds 已提交
2
 */
D
Dave Airlie 已提交
3
/*
L
Linus Torvalds 已提交
4 5
 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
 * All Rights Reserved.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
D
Dave Airlie 已提交
27
 */
L
Linus Torvalds 已提交
28 29 30 31 32 33

#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
#include "i915_drv.h"

D
Dave Airlie 已提交
34 35 36 37
#define USER_INT_FLAG (1<<1)
#define VSYNC_PIPEB_FLAG (1<<5)
#define VSYNC_PIPEA_FLAG (1<<7)

L
Linus Torvalds 已提交
38 39
#define MAX_NOPID ((u32)~0)

40 41 42 43 44
/**
 * Emit blits for scheduled buffer swaps.
 *
 * This function will be called with the HW lock held.
 */
45
static void i915_vblank_tasklet(struct drm_device *dev)
46 47
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
48
	unsigned long irqflags;
49
	struct list_head *list, *tmp, hits, *hit;
50 51 52
	int nhits, nrects, slice[2], upper[2], lower[2], i;
	unsigned counter[2] = { atomic_read(&dev->vbl_received),
				atomic_read(&dev->vbl_received2) };
53
	struct drm_drawable_info *drw;
54
	drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
55
	u32 cpp = dev_priv->cpp;
56 57 58 59
	u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
				XY_SRC_COPY_BLT_WRITE_ALPHA |
				XY_SRC_COPY_BLT_WRITE_RGB)
			     : XY_SRC_COPY_BLT_CMD;
60 61 62
	u32 src_pitch = sarea_priv->pitch * cpp;
	u32 dst_pitch = sarea_priv->pitch * cpp;
	u32 ropcpp = (0xcc << 16) | ((cpp - 1) << 24);
63
	RING_LOCALS;
64

65
	if (IS_I965G(dev) && sarea_priv->front_tiled) {
66 67 68
		cmd |= XY_SRC_COPY_BLT_DST_TILED;
		dst_pitch >>= 2;
	}
69
	if (IS_I965G(dev) && sarea_priv->back_tiled) {
70 71 72 73
		cmd |= XY_SRC_COPY_BLT_SRC_TILED;
		src_pitch >>= 2;
	}

74 75
	DRM_DEBUG("\n");

76 77 78 79
	INIT_LIST_HEAD(&hits);

	nhits = nrects = 0;

80
	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);
81

82
	/* Find buffer swaps scheduled for this vertical blank */
83 84 85 86
	list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
		drm_i915_vbl_swap_t *vbl_swap =
			list_entry(list, drm_i915_vbl_swap_t, head);

87
		if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
88 89 90 91 92 93 94
			continue;

		list_del(list);
		dev_priv->swaps_pending--;

		spin_unlock(&dev_priv->swaps_lock);
		spin_lock(&dev->drw_lock);
95

96
		drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
97

98 99 100 101 102 103
		if (!drw) {
			spin_unlock(&dev->drw_lock);
			drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
			spin_lock(&dev_priv->swaps_lock);
			continue;
		}
104

105 106 107
		list_for_each(hit, &hits) {
			drm_i915_vbl_swap_t *swap_cmp =
				list_entry(hit, drm_i915_vbl_swap_t, head);
108
			struct drm_drawable_info *drw_cmp =
109
				drm_get_drawable_info(dev, swap_cmp->drw_id);
110

111 112 113 114
			if (drw_cmp &&
			    drw_cmp->rects[0].y1 > drw->rects[0].y1) {
				list_add_tail(list, hit);
				break;
115
			}
116
		}
117

118
		spin_unlock(&dev->drw_lock);
119

120 121 122
		/* List of hits was empty, or we reached the end of it */
		if (hit == &hits)
			list_add_tail(list, hits.prev);
123

124
		nhits++;
125

126 127 128
		spin_lock(&dev_priv->swaps_lock);
	}

129 130
	if (nhits == 0) {
		spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
131
		return;
132 133 134
	}

	spin_unlock(&dev_priv->swaps_lock);
135

136
	i915_kernel_lost_context(dev);
137

138 139 140 141 142 143 144 145 146 147
	if (IS_I965G(dev)) {
		BEGIN_LP_RING(4);

		OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
		OUT_RING(0);
		OUT_RING(((sarea_priv->width - 1) & 0xffff) | ((sarea_priv->height - 1) << 16));
		OUT_RING(0);
		ADVANCE_LP_RING();
	} else {
		BEGIN_LP_RING(6);
148

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
		OUT_RING(GFX_OP_DRAWRECT_INFO);
		OUT_RING(0);
		OUT_RING(0);
		OUT_RING(sarea_priv->width | sarea_priv->height << 16);
		OUT_RING(sarea_priv->width | sarea_priv->height << 16);
		OUT_RING(0);

		ADVANCE_LP_RING();
	}

	sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT;

	upper[0] = upper[1] = 0;
	slice[0] = max(sarea_priv->pipeA_h / nhits, 1);
	slice[1] = max(sarea_priv->pipeB_h / nhits, 1);
	lower[0] = sarea_priv->pipeA_y + slice[0];
	lower[1] = sarea_priv->pipeB_y + slice[0];
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182

	spin_lock(&dev->drw_lock);

	/* Emit blits for buffer swaps, partitioning both outputs into as many
	 * slices as there are buffer swaps scheduled in order to avoid tearing
	 * (based on the assumption that a single buffer swap would always
	 * complete before scanout starts).
	 */
	for (i = 0; i++ < nhits;
	     upper[0] = lower[0], lower[0] += slice[0],
	     upper[1] = lower[1], lower[1] += slice[1]) {
		if (i == nhits)
			lower[0] = lower[1] = sarea_priv->height;

		list_for_each(hit, &hits) {
			drm_i915_vbl_swap_t *swap_hit =
				list_entry(hit, drm_i915_vbl_swap_t, head);
183
			struct drm_clip_rect *rect;
184
			int num_rects, pipe;
185 186 187 188 189 190 191 192
			unsigned short top, bottom;

			drw = drm_get_drawable_info(dev, swap_hit->drw_id);

			if (!drw)
				continue;

			rect = drw->rects;
193 194 195
			pipe = swap_hit->pipe;
			top = upper[pipe];
			bottom = lower[pipe];
196 197 198 199 200 201 202 203 204 205 206

			for (num_rects = drw->num_rects; num_rects--; rect++) {
				int y1 = max(rect->y1, top);
				int y2 = min(rect->y2, bottom);

				if (y1 >= y2)
					continue;

				BEGIN_LP_RING(8);

				OUT_RING(cmd);
207
				OUT_RING(ropcpp | dst_pitch);
208 209
				OUT_RING((y1 << 16) | rect->x1);
				OUT_RING((y2 << 16) | rect->x2);
210
				OUT_RING(sarea_priv->front_offset);
211
				OUT_RING((y1 << 16) | rect->x1);
212
				OUT_RING(src_pitch);
213
				OUT_RING(sarea_priv->back_offset);
214 215 216

				ADVANCE_LP_RING();
			}
217 218 219
		}
	}

220
	spin_unlock_irqrestore(&dev->drw_lock, irqflags);
221 222 223 224 225 226 227 228 229

	list_for_each_safe(hit, tmp, &hits) {
		drm_i915_vbl_swap_t *swap_hit =
			list_entry(hit, drm_i915_vbl_swap_t, head);

		list_del(hit);

		drm_free(swap_hit, sizeof(*swap_hit), DRM_MEM_DRIVER);
	}
230 231
}

L
Linus Torvalds 已提交
232 233
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
234
	struct drm_device *dev = (struct drm_device *) arg;
L
Linus Torvalds 已提交
235
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
236
	u16 temp;
237
	u32 pipea_stats, pipeb_stats;
L
Linus Torvalds 已提交
238

239 240
	pipea_stats = I915_READ(I915REG_PIPEASTAT);
	pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
241

242
	temp = I915_READ16(I915REG_INT_IDENTITY_R);
D
Dave Airlie 已提交
243

244
	temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
245

246 247 248 249 250 251 252 253 254 255 256 257
	DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);

	if (temp == 0)
		return IRQ_NONE;

	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
	(void) I915_READ16(I915REG_INT_IDENTITY_R);
	DRM_READMEMORYBARRIER();

	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);

	if (temp & USER_INT_FLAG)
258
		DRM_WAKEUP(&dev_priv->irq_queue);
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278

	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
		int vblank_pipe = dev_priv->vblank_pipe;

		if ((vblank_pipe &
		     (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B))
		    == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) {
			if (temp & VSYNC_PIPEA_FLAG)
				atomic_inc(&dev->vbl_received);
			if (temp & VSYNC_PIPEB_FLAG)
				atomic_inc(&dev->vbl_received2);
		} else if (((temp & VSYNC_PIPEA_FLAG) &&
			    (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
			   ((temp & VSYNC_PIPEB_FLAG) &&
			    (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
			atomic_inc(&dev->vbl_received);

		DRM_WAKEUP(&dev->vbl_queue);
		drm_vbl_send_signals(dev);

=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
279 280
		if (dev_priv->swaps_pending > 0)
			drm_locked_tasklet(dev, i915_vblank_tasklet);
281 282 283 284 285 286
		I915_WRITE(I915REG_PIPEASTAT,
			pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
			I915_VBLANK_CLEAR);
		I915_WRITE(I915REG_PIPEBSTAT,
			pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
			I915_VBLANK_CLEAR);
D
Dave Airlie 已提交
287
	}
L
Linus Torvalds 已提交
288 289 290 291

	return IRQ_HANDLED;
}

292
static int i915_emit_irq(struct drm_device * dev)
L
Linus Torvalds 已提交
293 294 295 296 297 298
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	RING_LOCALS;

	i915_kernel_lost_context(dev);

299
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
300

301
	dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
L
Linus Torvalds 已提交
302

303 304 305 306 307 308 309 310
	if (dev_priv->counter > 0x7FFFFFFFUL)
		dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;

	BEGIN_LP_RING(6);
	OUT_RING(CMD_STORE_DWORD_IDX);
	OUT_RING(20);
	OUT_RING(dev_priv->counter);
	OUT_RING(0);
L
Linus Torvalds 已提交
311 312 313
	OUT_RING(0);
	OUT_RING(GFX_OP_USER_INTERRUPT);
	ADVANCE_LP_RING();
D
Dave Airlie 已提交
314

315
	return dev_priv->counter;
L
Linus Torvalds 已提交
316 317
}

318
static int i915_wait_irq(struct drm_device * dev, int irq_nr)
L
Linus Torvalds 已提交
319 320 321 322
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	int ret = 0;

323
	DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
L
Linus Torvalds 已提交
324 325 326 327 328 329 330 331 332 333
		  READ_BREADCRUMB(dev_priv));

	if (READ_BREADCRUMB(dev_priv) >= irq_nr)
		return 0;

	dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;

	DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
		    READ_BREADCRUMB(dev_priv) >= irq_nr);

E
Eric Anholt 已提交
334
	if (ret == -EBUSY) {
335
		DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
L
Linus Torvalds 已提交
336 337 338
			  READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
	}

339
	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
L
Linus Torvalds 已提交
340 341 342
	return ret;
}

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence,
				      atomic_t *counter)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	unsigned int cur_vblank;
	int ret = 0;

	if (!dev_priv) {
		DRM_ERROR("called with no initialization\n");
		return -EINVAL;
	}

	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
		    (((cur_vblank = atomic_read(counter))
			- *sequence) <= (1<<23)));

	*sequence = cur_vblank;

	return ret;
}


int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
{
	return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received);
}

int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
{
	return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
}

L
Linus Torvalds 已提交
375 376
/* Needs the lock as it touches the ring.
 */
377 378
int i915_irq_emit(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
379 380
{
	drm_i915_private_t *dev_priv = dev->dev_private;
381
	drm_i915_irq_emit_t *emit = data;
L
Linus Torvalds 已提交
382 383
	int result;

384
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
385 386

	if (!dev_priv) {
387
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
388
		return -EINVAL;
L
Linus Torvalds 已提交
389 390 391 392
	}

	result = i915_emit_irq(dev);

393
	if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
L
Linus Torvalds 已提交
394
		DRM_ERROR("copy_to_user\n");
E
Eric Anholt 已提交
395
		return -EFAULT;
L
Linus Torvalds 已提交
396 397 398 399 400 401 402
	}

	return 0;
}

/* Doesn't need the hardware lock.
 */
403 404
int i915_irq_wait(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
405 406
{
	drm_i915_private_t *dev_priv = dev->dev_private;
407
	drm_i915_irq_wait_t *irqwait = data;
L
Linus Torvalds 已提交
408 409

	if (!dev_priv) {
410
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
411
		return -EINVAL;
L
Linus Torvalds 已提交
412 413
	}

414
	return i915_wait_irq(dev, irqwait->irq_seq);
L
Linus Torvalds 已提交
415 416
}

417
static void i915_enable_interrupt (struct drm_device *dev)
418 419
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
420
	u16 flag;
421

422 423 424 425 426
	flag = 0;
	if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
		flag |= VSYNC_PIPEA_FLAG;
	if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
		flag |= VSYNC_PIPEB_FLAG;
427

428
	I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
429 430 431 432
}

/* Set the vblank monitor pipe
 */
433 434
int i915_vblank_pipe_set(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
435 436
{
	drm_i915_private_t *dev_priv = dev->dev_private;
437
	drm_i915_vblank_pipe_t *pipe = data;
438 439

	if (!dev_priv) {
440
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
441
		return -EINVAL;
442 443
	}

444
	if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
445
		DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe);
E
Eric Anholt 已提交
446
		return -EINVAL;
447 448
	}

449
	dev_priv->vblank_pipe = pipe->pipe;
450

451 452
	i915_enable_interrupt (dev);

453
	return 0;
454 455
}

456 457
int i915_vblank_pipe_get(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
458 459
{
	drm_i915_private_t *dev_priv = dev->dev_private;
460
	drm_i915_vblank_pipe_t *pipe = data;
461 462 463
	u16 flag;

	if (!dev_priv) {
464
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
465
		return -EINVAL;
466 467 468
	}

	flag = I915_READ(I915REG_INT_ENABLE_R);
469
	pipe->pipe = 0;
470
	if (flag & VSYNC_PIPEA_FLAG)
471
		pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
472
	if (flag & VSYNC_PIPEB_FLAG)
473 474
		pipe->pipe |= DRM_I915_VBLANK_PIPE_B;

475 476 477
	return 0;
}

478 479 480
/**
 * Schedule buffer swap at given vertical blank.
 */
481 482
int i915_vblank_swap(struct drm_device *dev, void *data,
		     struct drm_file *file_priv)
483 484
{
	drm_i915_private_t *dev_priv = dev->dev_private;
485
	drm_i915_vblank_swap_t *swap = data;
486
	drm_i915_vbl_swap_t *vbl_swap;
487
	unsigned int pipe, seqtype, curseq;
488
	unsigned long irqflags;
489 490 491 492
	struct list_head *list;

	if (!dev_priv) {
		DRM_ERROR("%s called with no initialization\n", __func__);
E
Eric Anholt 已提交
493
		return -EINVAL;
494 495
	}

496
	if (dev_priv->sarea_priv->rotation) {
497
		DRM_DEBUG("Rotation not supported\n");
E
Eric Anholt 已提交
498
		return -EINVAL;
499 500
	}

501
	if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
502
			     _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
503
		DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
E
Eric Anholt 已提交
504
		return -EINVAL;
505 506
	}

507
	pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
508

509
	seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
510 511 512

	if (!(dev_priv->vblank_pipe & (1 << pipe))) {
		DRM_ERROR("Invalid pipe %d\n", pipe);
E
Eric Anholt 已提交
513
		return -EINVAL;
514 515 516 517
	}

	spin_lock_irqsave(&dev->drw_lock, irqflags);

518
	if (!drm_get_drawable_info(dev, swap->drawable)) {
519
		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
520
		DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
E
Eric Anholt 已提交
521
		return -EINVAL;
522 523 524 525
	}

	spin_unlock_irqrestore(&dev->drw_lock, irqflags);

526
	curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);
527

=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
528
	if (seqtype == _DRM_VBLANK_RELATIVE)
529
		swap->sequence += curseq;
=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
530

531 532 533
	if ((curseq - swap->sequence) <= (1<<23)) {
		if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) {
			swap->sequence = curseq + 1;
=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
534
		} else {
535
			DRM_DEBUG("Missed target sequence\n");
E
Eric Anholt 已提交
536
			return -EINVAL;
537 538 539
		}
	}

=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
540 541
	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);

542 543 544
	list_for_each(list, &dev_priv->vbl_swaps.head) {
		vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);

545
		if (vbl_swap->drw_id == swap->drawable &&
546
		    vbl_swap->pipe == pipe &&
547
		    vbl_swap->sequence == swap->sequence) {
548 549 550 551 552 553 554 555
			spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
			DRM_DEBUG("Already scheduled\n");
			return 0;
		}
	}

	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);

556 557
	if (dev_priv->swaps_pending >= 100) {
		DRM_DEBUG("Too many swaps queued\n");
E
Eric Anholt 已提交
558
		return -EBUSY;
559 560
	}

D
Dave Airlie 已提交
561
	vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
562 563 564

	if (!vbl_swap) {
		DRM_ERROR("Failed to allocate memory to queue swap\n");
E
Eric Anholt 已提交
565
		return -ENOMEM;
566 567 568 569
	}

	DRM_DEBUG("\n");

570
	vbl_swap->drw_id = swap->drawable;
571
	vbl_swap->pipe = pipe;
572
	vbl_swap->sequence = swap->sequence;
573 574 575

	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);

576
	list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head);
577 578 579 580 581 582 583
	dev_priv->swaps_pending++;

	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);

	return 0;
}

L
Linus Torvalds 已提交
584 585
/* drm_dma.h hooks
*/
586
void i915_driver_irq_preinstall(struct drm_device * dev)
L
Linus Torvalds 已提交
587 588 589
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;

590
	I915_WRITE16(I915REG_HWSTAM, 0xfffe);
L
Linus Torvalds 已提交
591 592 593 594
	I915_WRITE16(I915REG_INT_MASK_R, 0x0);
	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
}

595
void i915_driver_irq_postinstall(struct drm_device * dev)
L
Linus Torvalds 已提交
596 597 598
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;

599
	spin_lock_init(&dev_priv->swaps_lock);
600 601 602
	INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
	dev_priv->swaps_pending = 0;

603 604
	if (!dev_priv->vblank_pipe)
		dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
605
	i915_enable_interrupt(dev);
L
Linus Torvalds 已提交
606 607 608
	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}

609
void i915_driver_irq_uninstall(struct drm_device * dev)
L
Linus Torvalds 已提交
610 611
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
612
	u16 temp;
613

L
Linus Torvalds 已提交
614 615 616
	if (!dev_priv)
		return;

617 618 619 620 621 622
	I915_WRITE16(I915REG_HWSTAM, 0xffff);
	I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);

	temp = I915_READ16(I915REG_INT_IDENTITY_R);
	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
L
Linus Torvalds 已提交
623
}