i915_irq.c 15.4 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 279 280
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	RING_LOCALS;

	i915_kernel_lost_context(dev);

	DRM_DEBUG("%s\n", __FUNCTION__);

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();
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 303 304 305 306 307 308 309 310 311 312 313
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
	int ret = 0;

	DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr,
		  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) {
L
Linus Torvalds 已提交
315 316 317 318 319 320 321 322 323
		DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n",
			  __FUNCTION__,
			  READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
	}

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

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

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

	DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
337
		    (((cur_vblank = atomic_read(counter))
D
Dave Airlie 已提交
338 339 340 341 342 343 344 345
			- *sequence) <= (1<<23)));
	
	*sequence = cur_vblank;

	return ret;
}


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

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

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

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

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

	result = i915_emit_irq(dev);

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

	return 0;
}

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

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

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

398
static void i915_enable_interrupt (struct drm_device *dev)
399 400 401 402 403 404 405 406 407
{
	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;
408

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

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

	if (!dev_priv) {
		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
E
Eric Anholt 已提交
422
		return -EINVAL;
423 424
	}

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

431
	dev_priv->vblank_pipe = pipe->pipe;
432 433 434 435

	i915_enable_interrupt (dev);

	return 0;
436 437
}

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

	if (!dev_priv) {
		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
E
Eric Anholt 已提交
447
		return -EINVAL;
448 449 450
	}

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

457 458 459
	return 0;
}

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

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

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

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

489
	pipe = (swap->seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0;
490

491
	seqtype = swap->seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE);
492 493 494

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

	spin_lock_irqsave(&dev->drw_lock, irqflags);

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

	spin_unlock_irqrestore(&dev->drw_lock, irqflags);

508 509
	curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received);

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

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

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

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

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

	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);

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

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

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

	DRM_DEBUG("\n");

552
	vbl_swap->drw_id = swap->drawable;
553
	vbl_swap->pipe = pipe;
554
	vbl_swap->sequence = swap->sequence;
555 556 557 558 559 560 561 562 563 564 565

	spin_lock_irqsave(&dev_priv->swaps_lock, irqflags);

	list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head);
	dev_priv->swaps_pending++;

	spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags);

	return 0;
}

L
Linus Torvalds 已提交
566 567
/* drm_dma.h hooks
*/
568
void i915_driver_irq_preinstall(struct drm_device * dev)
L
Linus Torvalds 已提交
569 570 571 572 573 574 575 576
{
	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);
}

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

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

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

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

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

	I915_WRITE16(I915REG_HWSTAM, 0xffff);
	I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
	I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
602 603 604

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