i915_irq.c 15.2 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 50 51 52
	struct list_head *list, *tmp, hits, *hit;
	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 55 56 57 58 59 60 61 62
	drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
	u32 cpp = dev_priv->cpp;
	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;
	u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
			  (cpp << 23) | (1 << 24);
	RING_LOCALS;
63 64 65

	DRM_DEBUG("\n");

66 67 68 69
	INIT_LIST_HEAD(&hits);

	nhits = nrects = 0;

70 71
	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);

72
	/* Find buffer swaps scheduled for this vertical blank */
73 74 75 76
	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);

77 78 79 80 81 82 83 84
		if ((counter[vbl_swap->pipe] - vbl_swap->sequence) > (1<<23))
			continue;

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

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

86
		drw = drm_get_drawable_info(dev, vbl_swap->drw_id);
87

88 89 90 91 92 93
		if (!drw) {
			spin_unlock(&dev->drw_lock);
			drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER);
			spin_lock(&dev_priv->swaps_lock);
			continue;
		}
94

95 96 97
		list_for_each(hit, &hits) {
			drm_i915_vbl_swap_t *swap_cmp =
				list_entry(hit, drm_i915_vbl_swap_t, head);
98
			struct drm_drawable_info *drw_cmp =
99
				drm_get_drawable_info(dev, swap_cmp->drw_id);
100

101 102 103 104
			if (drw_cmp &&
			    drw_cmp->rects[0].y1 > drw->rects[0].y1) {
				list_add_tail(list, hit);
				break;
105
			}
106
		}
107

108
		spin_unlock(&dev->drw_lock);
109

110 111 112
		/* List of hits was empty, or we reached the end of it */
		if (hit == &hits)
			list_add_tail(list, hits.prev);
113

114
		nhits++;
115

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
		spin_lock(&dev_priv->swaps_lock);
	}

	if (nhits == 0) {
		spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
		return;
	}

	spin_unlock(&dev_priv->swaps_lock);

	i915_kernel_lost_context(dev);

	BEGIN_LP_RING(6);

	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);
136

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
	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];

	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);
163
			struct drm_clip_rect *rect;
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
			int num_rects, pipe;
			unsigned short top, bottom;

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

			if (!drw)
				continue;

			rect = drw->rects;
			pipe = swap_hit->pipe;
			top = upper[pipe];
			bottom = lower[pipe];

			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);
				OUT_RING(pitchropcpp);
				OUT_RING((y1 << 16) | rect->x1);
				OUT_RING((y2 << 16) | rect->x2);
				OUT_RING(sarea_priv->front_offset);
				OUT_RING((y1 << 16) | rect->x1);
				OUT_RING(pitchropcpp & 0xffff);
				OUT_RING(sarea_priv->back_offset);

				ADVANCE_LP_RING();
			}
197 198 199
		}
	}

200 201 202 203 204 205 206 207 208 209
	spin_unlock_irqrestore(&dev->drw_lock, irqflags);

	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);
	}
210 211
}

L
Linus Torvalds 已提交
212 213
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
214
	struct drm_device *dev = (struct drm_device *) arg;
L
Linus Torvalds 已提交
215 216
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	u16 temp;
217 218 219 220
	u32 pipea_stats, pipeb_stats;

	pipea_stats = I915_READ(I915REG_PIPEASTAT);
	pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
L
Linus Torvalds 已提交
221 222

	temp = I915_READ16(I915REG_INT_IDENTITY_R);
223 224

	temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
L
Linus Torvalds 已提交
225 226 227 228 229 230 231

	DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);

	if (temp == 0)
		return IRQ_NONE;

	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
232 233
	(void) I915_READ16(I915REG_INT_IDENTITY_R);
	DRM_READMEMORYBARRIER();
D
Dave Airlie 已提交
234

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

D
Dave Airlie 已提交
237 238 239
	if (temp & USER_INT_FLAG)
		DRM_WAKEUP(&dev_priv->irq_queue);

240
	if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
241 242 243
		int vblank_pipe = dev_priv->vblank_pipe;

		if ((vblank_pipe &
244 245 246 247 248 249
		     (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);
=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
250 251 252 253
		} else if (((temp & VSYNC_PIPEA_FLAG) &&
			    (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) ||
			   ((temp & VSYNC_PIPEB_FLAG) &&
			    (vblank_pipe & DRM_I915_VBLANK_PIPE_B)))
254 255
			atomic_inc(&dev->vbl_received);

D
Dave Airlie 已提交
256 257
		DRM_WAKEUP(&dev->vbl_queue);
		drm_vbl_send_signals(dev);
258

=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
259 260
		if (dev_priv->swaps_pending > 0)
			drm_locked_tasklet(dev, i915_vblank_tasklet);
261 262 263 264 265 266
		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 已提交
267
	}
L
Linus Torvalds 已提交
268 269 270 271

	return IRQ_HANDLED;
}

272
static int i915_emit_irq(struct drm_device * dev)
L
Linus Torvalds 已提交
273 274 275 276 277 278
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	RING_LOCALS;

	i915_kernel_lost_context(dev);

279
	DRM_DEBUG("\n");
L
Linus Torvalds 已提交
280

281
	dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
L
Linus Torvalds 已提交
282

283 284 285 286 287 288 289 290
	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 已提交
291 292 293
	OUT_RING(0);
	OUT_RING(GFX_OP_USER_INTERRUPT);
	ADVANCE_LP_RING();
D
Dave Airlie 已提交
294

295
	return dev_priv->counter;
L
Linus Torvalds 已提交
296 297
}

298
static int i915_wait_irq(struct drm_device * dev, int irq_nr)
L
Linus Torvalds 已提交
299 300 301 302
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	int ret = 0;

303
	DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
L
Linus Torvalds 已提交
304 305 306 307 308 309 310 311 312 313
		  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 已提交
314
	if (ret == -EBUSY) {
315
		DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
L
Linus Torvalds 已提交
316 317 318 319 320 321 322
			  READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
	}

	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
	return ret;
}

323
static int i915_driver_vblank_do_wait(struct drm_device *dev, unsigned int *sequence,
324
				      atomic_t *counter)
D
Dave Airlie 已提交
325 326 327 328 329 330
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	unsigned int cur_vblank;
	int ret = 0;

	if (!dev_priv) {
331
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
332
		return -EINVAL;
D
Dave Airlie 已提交
333 334 335
	}

	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
336
		    (((cur_vblank = atomic_read(counter))
D
Dave Airlie 已提交
337
			- *sequence) <= (1<<23)));
D
Dave Airlie 已提交
338

D
Dave Airlie 已提交
339 340 341 342 343 344
	*sequence = cur_vblank;

	return ret;
}


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

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

L
Linus Torvalds 已提交
355 356
/* Needs the lock as it touches the ring.
 */
357 358
int i915_irq_emit(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
359 360
{
	drm_i915_private_t *dev_priv = dev->dev_private;
361
	drm_i915_irq_emit_t *emit = data;
L
Linus Torvalds 已提交
362 363
	int result;

364
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
365 366

	if (!dev_priv) {
367
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
368
		return -EINVAL;
L
Linus Torvalds 已提交
369 370 371 372
	}

	result = i915_emit_irq(dev);

373
	if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
L
Linus Torvalds 已提交
374
		DRM_ERROR("copy_to_user\n");
E
Eric Anholt 已提交
375
		return -EFAULT;
L
Linus Torvalds 已提交
376 377 378 379 380 381 382
	}

	return 0;
}

/* Doesn't need the hardware lock.
 */
383 384
int i915_irq_wait(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
385 386
{
	drm_i915_private_t *dev_priv = dev->dev_private;
387
	drm_i915_irq_wait_t *irqwait = data;
L
Linus Torvalds 已提交
388 389

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

394
	return i915_wait_irq(dev, irqwait->irq_seq);
L
Linus Torvalds 已提交
395 396
}

397
static void i915_enable_interrupt (struct drm_device *dev)
398 399 400 401 402 403 404 405 406
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	u16 flag;

	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;
407

408 409 410 411 412
	I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
}

/* Set the vblank monitor pipe
 */
413 414
int i915_vblank_pipe_set(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
415 416
{
	drm_i915_private_t *dev_priv = dev->dev_private;
417
	drm_i915_vblank_pipe_t *pipe = data;
418 419

	if (!dev_priv) {
420
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
421
		return -EINVAL;
422 423
	}

424
	if (pipe->pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
425
		DRM_ERROR("called with invalid pipe 0x%x\n", pipe->pipe);
E
Eric Anholt 已提交
426
		return -EINVAL;
427 428
	}

429
	dev_priv->vblank_pipe = pipe->pipe;
430 431 432 433

	i915_enable_interrupt (dev);

	return 0;
434 435
}

436 437
int i915_vblank_pipe_get(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
438 439
{
	drm_i915_private_t *dev_priv = dev->dev_private;
440
	drm_i915_vblank_pipe_t *pipe = data;
441 442 443
	u16 flag;

	if (!dev_priv) {
444
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
445
		return -EINVAL;
446 447 448
	}

	flag = I915_READ(I915REG_INT_ENABLE_R);
449
	pipe->pipe = 0;
450
	if (flag & VSYNC_PIPEA_FLAG)
451
		pipe->pipe |= DRM_I915_VBLANK_PIPE_A;
452
	if (flag & VSYNC_PIPEB_FLAG)
453 454
		pipe->pipe |= DRM_I915_VBLANK_PIPE_B;

455 456 457
	return 0;
}

458 459 460
/**
 * Schedule buffer swap at given vertical blank.
 */
461 462
int i915_vblank_swap(struct drm_device *dev, void *data,
		     struct drm_file *file_priv)
463 464
{
	drm_i915_private_t *dev_priv = dev->dev_private;
465
	drm_i915_vblank_swap_t *swap = data;
466
	drm_i915_vbl_swap_t *vbl_swap;
467 468
	unsigned int pipe, seqtype, curseq;
	unsigned long irqflags;
469 470 471 472
	struct list_head *list;

	if (!dev_priv) {
		DRM_ERROR("%s called with no initialization\n", __func__);
E
Eric Anholt 已提交
473
		return -EINVAL;
474 475 476 477
	}

	if (dev_priv->sarea_priv->rotation) {
		DRM_DEBUG("Rotation not supported\n");
E
Eric Anholt 已提交
478
		return -EINVAL;
479 480
	}

481
	if (swap->seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE |
=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
482
			     _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) {
483
		DRM_ERROR("Invalid sequence type 0x%x\n", swap->seqtype);
E
Eric Anholt 已提交
484
		return -EINVAL;
485 486
	}

487
	pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
488

489
	seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
490 491 492

	if (!(dev_priv->vblank_pipe & (1 << pipe))) {
		DRM_ERROR("Invalid pipe %d\n", pipe);
E
Eric Anholt 已提交
493
		return -EINVAL;
494 495 496 497
	}

	spin_lock_irqsave(&dev->drw_lock, irqflags);

498
	if (!drm_get_drawable_info(dev, swap->drawable)) {
499
		spin_unlock_irqrestore(&dev->drw_lock, irqflags);
500
		DRM_DEBUG("Invalid drawable ID %d\n", swap->drawable);
E
Eric Anholt 已提交
501
		return -EINVAL;
502 503 504 505
	}

	spin_unlock_irqrestore(&dev->drw_lock, irqflags);

506 507
	curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);

=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
508
	if (seqtype == _DRM_VBLANK_RELATIVE)
509
		swap->sequence += curseq;
=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
510

511 512 513
	if ((curseq - swap->sequence) <= (1<<23)) {
		if (swap->seqtype & _DRM_VBLANK_NEXTONMISS) {
			swap->sequence = curseq + 1;
=
=?utf-8?q?Michel_D=C3=A4nzer?= 已提交
514
		} else {
515
			DRM_DEBUG("Missed target sequence\n");
E
Eric Anholt 已提交
516
			return -EINVAL;
517 518 519
		}
	}

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

522 523 524
	list_for_each(list, &dev_priv->vbl_swaps.head) {
		vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);

525
		if (vbl_swap->drw_id == swap->drawable &&
526
		    vbl_swap->pipe == pipe &&
527
		    vbl_swap->sequence == swap->sequence) {
528 529 530 531 532 533 534 535
			spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);
			DRM_DEBUG("Already scheduled\n");
			return 0;
		}
	}

	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);

536 537
	if (dev_priv->swaps_pending >= 100) {
		DRM_DEBUG("Too many swaps queued\n");
E
Eric Anholt 已提交
538
		return -EBUSY;
539 540
	}

D
Dave Airlie 已提交
541
	vbl_swap = drm_calloc(1, sizeof(*vbl_swap), DRM_MEM_DRIVER);
542 543 544

	if (!vbl_swap) {
		DRM_ERROR("Failed to allocate memory to queue swap\n");
E
Eric Anholt 已提交
545
		return -ENOMEM;
546 547 548 549
	}

	DRM_DEBUG("\n");

550
	vbl_swap->drw_id = swap->drawable;
551
	vbl_swap->pipe = pipe;
552
	vbl_swap->sequence = swap->sequence;
553 554 555

	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);

556
	list_add_tail(&vbl_swap->head, &dev_priv->vbl_swaps.head);
557 558 559 560 561 562 563
	dev_priv->swaps_pending++;

	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);

	return 0;
}

L
Linus Torvalds 已提交
564 565
/* drm_dma.h hooks
*/
566
void i915_driver_irq_preinstall(struct drm_device * dev)
L
Linus Torvalds 已提交
567 568 569 570 571 572 573 574
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;

	I915_WRITE16(I915REG_HWSTAM, 0xfffe);
	I915_WRITE16(I915REG_INT_MASK_R, 0x0);
	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
}

575
void i915_driver_irq_postinstall(struct drm_device * dev)
L
Linus Torvalds 已提交
576 577 578
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;

579
	spin_lock_init(&dev_priv->swaps_lock);
580 581 582
	INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
	dev_priv->swaps_pending = 0;

583 584
	if (!dev_priv->vblank_pipe)
		dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A;
585
	i915_enable_interrupt(dev);
L
Linus Torvalds 已提交
586 587 588
	DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}

589
void i915_driver_irq_uninstall(struct drm_device * dev)
L
Linus Torvalds 已提交
590 591
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
592 593
	u16 temp;

L
Linus Torvalds 已提交
594 595 596 597 598 599
	if (!dev_priv)
		return;

	I915_WRITE16(I915REG_HWSTAM, 0xffff);
	I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
600 601 602

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