i915_dma.c 26.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
 */
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 34 35 36 37 38

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

/* Really want an OS-independent resettable timer.  Would like to have
 * this loop run for (eg) 3 sec, but have the timer reset every time
 * the head pointer changes, so that EBUSY only happens if the ring
 * actually stalls for (eg) 3 seconds.
 */
39
int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
L
Linus Torvalds 已提交
40 41
{
	drm_i915_private_t *dev_priv = dev->dev_private;
42
	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
L
Linus Torvalds 已提交
43
	drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
44 45 46
	u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
	u32 last_acthd = I915_READ(acthd_reg);
	u32 acthd;
47
	u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
L
Linus Torvalds 已提交
48 49
	int i;

50
	for (i = 0; i < 100000; i++) {
51
		ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
52
		acthd = I915_READ(acthd_reg);
L
Linus Torvalds 已提交
53 54 55 56 57 58
		ring->space = ring->head - (ring->tail + 8);
		if (ring->space < 0)
			ring->space += ring->Size;
		if (ring->space >= n)
			return 0;

59 60
		if (master_priv->sarea_priv)
			master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
L
Linus Torvalds 已提交
61 62 63

		if (ring->head != last_head)
			i = 0;
64 65
		if (acthd != last_acthd)
			i = 0;
L
Linus Torvalds 已提交
66 67

		last_head = ring->head;
68 69 70
		last_acthd = acthd;
		msleep_interruptible(10);

L
Linus Torvalds 已提交
71 72
	}

E
Eric Anholt 已提交
73
	return -EBUSY;
L
Linus Torvalds 已提交
74 75
}

76 77 78 79
/**
 * Sets up the hardware status page for devices that need a physical address
 * in the register.
 */
80
static int i915_init_phys_hws(struct drm_device *dev)
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	/* Program Hardware Status Page */
	dev_priv->status_page_dmah =
		drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);

	if (!dev_priv->status_page_dmah) {
		DRM_ERROR("Can not allocate hardware status page\n");
		return -ENOMEM;
	}
	dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
	dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;

	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);

	I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
	DRM_DEBUG("Enabled hardware status page\n");
	return 0;
}

/**
 * Frees the hardware status page, whether it's a physical address or a virtual
 * address set up by the X Server.
 */
105
static void i915_free_hws(struct drm_device *dev)
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	if (dev_priv->status_page_dmah) {
		drm_pci_free(dev, dev_priv->status_page_dmah);
		dev_priv->status_page_dmah = NULL;
	}

	if (dev_priv->status_gfx_addr) {
		dev_priv->status_gfx_addr = 0;
		drm_core_ioremapfree(&dev_priv->hws_map, dev);
	}

	/* Need to rewrite hardware status page */
	I915_WRITE(HWS_PGA, 0x1ffff000);
}

122
void i915_kernel_lost_context(struct drm_device * dev)
L
Linus Torvalds 已提交
123 124
{
	drm_i915_private_t *dev_priv = dev->dev_private;
125
	struct drm_i915_master_private *master_priv;
L
Linus Torvalds 已提交
126 127
	drm_i915_ring_buffer_t *ring = &(dev_priv->ring);

128 129
	ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
	ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
L
Linus Torvalds 已提交
130 131 132 133
	ring->space = ring->head - (ring->tail + 8);
	if (ring->space < 0)
		ring->space += ring->Size;

134 135 136 137 138 139
	if (!dev->primary->master)
		return;

	master_priv = dev->primary->master->driver_priv;
	if (ring->head == ring->tail && master_priv->sarea_priv)
		master_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
L
Linus Torvalds 已提交
140 141
}

142
static int i915_dma_cleanup(struct drm_device * dev)
L
Linus Torvalds 已提交
143
{
J
Jesse Barnes 已提交
144
	drm_i915_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
145 146 147 148
	/* Make sure interrupts are disabled here because the uninstall ioctl
	 * may not have been called from userspace and after dev_private
	 * is freed, it's too late.
	 */
149
	if (dev->irq_enabled)
D
Dave Airlie 已提交
150
		drm_irq_uninstall(dev);
L
Linus Torvalds 已提交
151

J
Jesse Barnes 已提交
152 153
	if (dev_priv->ring.virtual_start) {
		drm_core_ioremapfree(&dev_priv->ring.map, dev);
154 155
		dev_priv->ring.virtual_start = NULL;
		dev_priv->ring.map.handle = NULL;
J
Jesse Barnes 已提交
156 157
		dev_priv->ring.map.size = 0;
	}
158

159 160 161
	/* Clear the HWS virtual address at teardown */
	if (I915_NEED_GFX_HWS(dev))
		i915_free_hws(dev);
L
Linus Torvalds 已提交
162 163 164 165

	return 0;
}

J
Jesse Barnes 已提交
166
static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
L
Linus Torvalds 已提交
167
{
J
Jesse Barnes 已提交
168
	drm_i915_private_t *dev_priv = dev->dev_private;
169
	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
L
Linus Torvalds 已提交
170

171 172 173 174 175 176 177
	if (init->ring_size != 0) {
		if (dev_priv->ring.ring_obj != NULL) {
			i915_dma_cleanup(dev);
			DRM_ERROR("Client tried to initialize ringbuffer in "
				  "GEM mode\n");
			return -EINVAL;
		}
L
Linus Torvalds 已提交
178

179 180
		dev_priv->ring.Size = init->ring_size;
		dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
L
Linus Torvalds 已提交
181

182 183 184 185 186
		dev_priv->ring.map.offset = init->ring_start;
		dev_priv->ring.map.size = init->ring_size;
		dev_priv->ring.map.type = 0;
		dev_priv->ring.map.flags = 0;
		dev_priv->ring.map.mtrr = 0;
L
Linus Torvalds 已提交
187

188 189 190 191 192 193 194 195
		drm_core_ioremap(&dev_priv->ring.map, dev);

		if (dev_priv->ring.map.handle == NULL) {
			i915_dma_cleanup(dev);
			DRM_ERROR("can not ioremap virtual address for"
				  " ring buffer\n");
			return -ENOMEM;
		}
L
Linus Torvalds 已提交
196 197 198 199
	}

	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;

200
	dev_priv->cpp = init->cpp;
L
Linus Torvalds 已提交
201 202 203
	dev_priv->back_offset = init->back_offset;
	dev_priv->front_offset = init->front_offset;
	dev_priv->current_page = 0;
204 205
	if (master_priv->sarea_priv)
		master_priv->sarea_priv->pf_current_page = 0;
L
Linus Torvalds 已提交
206 207 208 209 210 211 212 213

	/* Allow hardware batchbuffers unless told otherwise.
	 */
	dev_priv->allow_batchbuffer = 1;

	return 0;
}

214
static int i915_dma_resume(struct drm_device * dev)
L
Linus Torvalds 已提交
215 216 217
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;

218
	DRM_DEBUG("%s\n", __func__);
L
Linus Torvalds 已提交
219 220 221 222

	if (dev_priv->ring.map.handle == NULL) {
		DRM_ERROR("can not ioremap virtual address for"
			  " ring buffer\n");
E
Eric Anholt 已提交
223
		return -ENOMEM;
L
Linus Torvalds 已提交
224 225 226 227 228
	}

	/* Program Hardware Status Page */
	if (!dev_priv->hw_status_page) {
		DRM_ERROR("Can not find hardware status page\n");
E
Eric Anholt 已提交
229
		return -EINVAL;
L
Linus Torvalds 已提交
230 231 232
	}
	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);

233
	if (dev_priv->status_gfx_addr != 0)
234
		I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
235
	else
236
		I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
L
Linus Torvalds 已提交
237 238 239 240 241
	DRM_DEBUG("Enabled hardware status page\n");

	return 0;
}

242 243
static int i915_dma_init(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
244
{
245
	drm_i915_init_t *init = data;
L
Linus Torvalds 已提交
246 247
	int retcode = 0;

248
	switch (init->func) {
L
Linus Torvalds 已提交
249
	case I915_INIT_DMA:
J
Jesse Barnes 已提交
250
		retcode = i915_initialize(dev, init);
L
Linus Torvalds 已提交
251 252 253 254 255
		break;
	case I915_CLEANUP_DMA:
		retcode = i915_dma_cleanup(dev);
		break;
	case I915_RESUME_DMA:
D
Dave Airlie 已提交
256
		retcode = i915_dma_resume(dev);
L
Linus Torvalds 已提交
257 258
		break;
	default:
E
Eric Anholt 已提交
259
		retcode = -EINVAL;
L
Linus Torvalds 已提交
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
		break;
	}

	return retcode;
}

/* Implement basically the same security restrictions as hardware does
 * for MI_BATCH_NON_SECURE.  These can be made stricter at any time.
 *
 * Most of the calculations below involve calculating the size of a
 * particular instruction.  It's important to get the size right as
 * that tells us where the next instruction to check is.  Any illegal
 * instruction detected will be given a size of zero, which is a
 * signal to abort the rest of the buffer.
 */
static int do_validate_cmd(int cmd)
{
	switch (((cmd >> 29) & 0x7)) {
	case 0x0:
		switch ((cmd >> 23) & 0x3f) {
		case 0x0:
			return 1;	/* MI_NOOP */
		case 0x4:
			return 1;	/* MI_FLUSH */
		default:
			return 0;	/* disallow everything else */
		}
		break;
	case 0x1:
		return 0;	/* reserved */
	case 0x2:
		return (cmd & 0xff) + 2;	/* 2d commands */
	case 0x3:
		if (((cmd >> 24) & 0x1f) <= 0x18)
			return 1;

		switch ((cmd >> 24) & 0x1f) {
		case 0x1c:
			return 1;
		case 0x1d:
D
Dave Airlie 已提交
300
			switch ((cmd >> 16) & 0xff) {
L
Linus Torvalds 已提交
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
			case 0x3:
				return (cmd & 0x1f) + 2;
			case 0x4:
				return (cmd & 0xf) + 2;
			default:
				return (cmd & 0xffff) + 2;
			}
		case 0x1e:
			if (cmd & (1 << 23))
				return (cmd & 0xffff) + 1;
			else
				return 1;
		case 0x1f:
			if ((cmd & (1 << 23)) == 0)	/* inline vertices */
				return (cmd & 0x1ffff) + 2;
			else if (cmd & (1 << 17))	/* indirect random */
				if ((cmd & 0xffff) == 0)
					return 0;	/* unknown length, too hard */
				else
					return (((cmd & 0xffff) + 1) / 2) + 1;
			else
				return 2;	/* indirect sequential */
		default:
			return 0;
		}
	default:
		return 0;
	}

	return 0;
}

static int validate_cmd(int cmd)
{
	int ret = do_validate_cmd(cmd);

D
Dave Airlie 已提交
337
/*	printk("validate_cmd( %x ): %d\n", cmd, ret); */
L
Linus Torvalds 已提交
338 339 340 341

	return ret;
}

342
static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwords)
L
Linus Torvalds 已提交
343 344 345 346 347
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	int i;
	RING_LOCALS;

348
	if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
E
Eric Anholt 已提交
349
		return -EINVAL;
350

351
	BEGIN_LP_RING((dwords+1)&~1);
352

L
Linus Torvalds 已提交
353 354 355 356
	for (i = 0; i < dwords;) {
		int cmd, sz;

		if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))
E
Eric Anholt 已提交
357
			return -EINVAL;
L
Linus Torvalds 已提交
358 359

		if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
E
Eric Anholt 已提交
360
			return -EINVAL;
L
Linus Torvalds 已提交
361 362 363 364 365 366

		OUT_RING(cmd);

		while (++i, --sz) {
			if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i],
							 sizeof(cmd))) {
E
Eric Anholt 已提交
367
				return -EINVAL;
L
Linus Torvalds 已提交
368 369 370 371 372
			}
			OUT_RING(cmd);
		}
	}

373 374 375 376 377
	if (dwords & 1)
		OUT_RING(0);

	ADVANCE_LP_RING();

L
Linus Torvalds 已提交
378 379 380
	return 0;
}

381 382 383 384
int
i915_emit_box(struct drm_device *dev,
	      struct drm_clip_rect __user *boxes,
	      int i, int DR1, int DR4)
L
Linus Torvalds 已提交
385 386
{
	drm_i915_private_t *dev_priv = dev->dev_private;
387
	struct drm_clip_rect box;
L
Linus Torvalds 已提交
388 389 390
	RING_LOCALS;

	if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
E
Eric Anholt 已提交
391
		return -EFAULT;
L
Linus Torvalds 已提交
392 393 394 395 396
	}

	if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
		DRM_ERROR("Bad box %d,%d..%d,%d\n",
			  box.x1, box.y1, box.x2, box.y2);
E
Eric Anholt 已提交
397
		return -EINVAL;
L
Linus Torvalds 已提交
398 399
	}

400 401 402 403
	if (IS_I965G(dev)) {
		BEGIN_LP_RING(4);
		OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
A
Andrew Morton 已提交
404
		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
405 406 407 408 409 410 411 412 413 414 415 416
		OUT_RING(DR4);
		ADVANCE_LP_RING();
	} else {
		BEGIN_LP_RING(6);
		OUT_RING(GFX_OP_DRAWRECT_INFO);
		OUT_RING(DR1);
		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
		OUT_RING(DR4);
		OUT_RING(0);
		ADVANCE_LP_RING();
	}
L
Linus Torvalds 已提交
417 418 419 420

	return 0;
}

421 422 423 424
/* XXX: Emitting the counter should really be moved to part of the IRQ
 * emit. For now, do it in both places:
 */

425
static void i915_emit_breadcrumb(struct drm_device *dev)
426 427
{
	drm_i915_private_t *dev_priv = dev->dev_private;
428
	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
429 430
	RING_LOCALS;

431
	dev_priv->counter++;
432
	if (dev_priv->counter > 0x7FFFFFFFUL)
433
		dev_priv->counter = 0;
434 435
	if (master_priv->sarea_priv)
		master_priv->sarea_priv->last_enqueue = dev_priv->counter;
436 437

	BEGIN_LP_RING(4);
438
	OUT_RING(MI_STORE_DWORD_INDEX);
439
	OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
440 441 442 443 444
	OUT_RING(dev_priv->counter);
	OUT_RING(0);
	ADVANCE_LP_RING();
}

445
static int i915_dispatch_cmdbuffer(struct drm_device * dev,
L
Linus Torvalds 已提交
446 447 448 449 450 451 452
				   drm_i915_cmdbuffer_t * cmd)
{
	int nbox = cmd->num_cliprects;
	int i = 0, count, ret;

	if (cmd->sz & 0x3) {
		DRM_ERROR("alignment");
E
Eric Anholt 已提交
453
		return -EINVAL;
L
Linus Torvalds 已提交
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
	}

	i915_kernel_lost_context(dev);

	count = nbox ? nbox : 1;

	for (i = 0; i < count; i++) {
		if (i < nbox) {
			ret = i915_emit_box(dev, cmd->cliprects, i,
					    cmd->DR1, cmd->DR4);
			if (ret)
				return ret;
		}

		ret = i915_emit_cmds(dev, (int __user *)cmd->buf, cmd->sz / 4);
		if (ret)
			return ret;
	}

473
	i915_emit_breadcrumb(dev);
L
Linus Torvalds 已提交
474 475 476
	return 0;
}

477
static int i915_dispatch_batchbuffer(struct drm_device * dev,
L
Linus Torvalds 已提交
478 479 480
				     drm_i915_batchbuffer_t * batch)
{
	drm_i915_private_t *dev_priv = dev->dev_private;
481
	struct drm_clip_rect __user *boxes = batch->cliprects;
L
Linus Torvalds 已提交
482 483 484 485 486 487
	int nbox = batch->num_cliprects;
	int i = 0, count;
	RING_LOCALS;

	if ((batch->start | batch->used) & 0x7) {
		DRM_ERROR("alignment");
E
Eric Anholt 已提交
488
		return -EINVAL;
L
Linus Torvalds 已提交
489 490 491 492 493 494 495 496 497 498 499 500 501 502
	}

	i915_kernel_lost_context(dev);

	count = nbox ? nbox : 1;

	for (i = 0; i < count; i++) {
		if (i < nbox) {
			int ret = i915_emit_box(dev, boxes, i,
						batch->DR1, batch->DR4);
			if (ret)
				return ret;
		}

503
		if (!IS_I830(dev) && !IS_845G(dev)) {
L
Linus Torvalds 已提交
504
			BEGIN_LP_RING(2);
505 506 507 508 509 510 511
			if (IS_I965G(dev)) {
				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
				OUT_RING(batch->start);
			} else {
				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
				OUT_RING(batch->start | MI_BATCH_NON_SECURE);
			}
L
Linus Torvalds 已提交
512 513 514 515 516 517 518 519 520 521 522
			ADVANCE_LP_RING();
		} else {
			BEGIN_LP_RING(4);
			OUT_RING(MI_BATCH_BUFFER);
			OUT_RING(batch->start | MI_BATCH_NON_SECURE);
			OUT_RING(batch->start + batch->used - 4);
			OUT_RING(0);
			ADVANCE_LP_RING();
		}
	}

523
	i915_emit_breadcrumb(dev);
L
Linus Torvalds 已提交
524 525 526 527

	return 0;
}

528
static int i915_dispatch_flip(struct drm_device * dev)
L
Linus Torvalds 已提交
529 530
{
	drm_i915_private_t *dev_priv = dev->dev_private;
531 532
	struct drm_i915_master_private *master_priv =
		dev->primary->master->driver_priv;
L
Linus Torvalds 已提交
533 534
	RING_LOCALS;

535
	if (!master_priv->sarea_priv)
536 537
		return -EINVAL;

538
	DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
539
		  __func__,
540
		  dev_priv->current_page,
541
		  master_priv->sarea_priv->pf_current_page);
L
Linus Torvalds 已提交
542

543 544 545
	i915_kernel_lost_context(dev);

	BEGIN_LP_RING(2);
546
	OUT_RING(MI_FLUSH | MI_READ_FLUSH);
547 548
	OUT_RING(0);
	ADVANCE_LP_RING();
L
Linus Torvalds 已提交
549

550 551 552 553 554 555
	BEGIN_LP_RING(6);
	OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP);
	OUT_RING(0);
	if (dev_priv->current_page == 0) {
		OUT_RING(dev_priv->back_offset);
		dev_priv->current_page = 1;
L
Linus Torvalds 已提交
556
	} else {
557 558
		OUT_RING(dev_priv->front_offset);
		dev_priv->current_page = 0;
L
Linus Torvalds 已提交
559
	}
560 561
	OUT_RING(0);
	ADVANCE_LP_RING();
L
Linus Torvalds 已提交
562

563 564 565 566
	BEGIN_LP_RING(2);
	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
	OUT_RING(0);
	ADVANCE_LP_RING();
L
Linus Torvalds 已提交
567

568
	master_priv->sarea_priv->last_enqueue = dev_priv->counter++;
L
Linus Torvalds 已提交
569 570

	BEGIN_LP_RING(4);
571
	OUT_RING(MI_STORE_DWORD_INDEX);
572
	OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
573 574
	OUT_RING(dev_priv->counter);
	OUT_RING(0);
L
Linus Torvalds 已提交
575 576
	ADVANCE_LP_RING();

577
	master_priv->sarea_priv->pf_current_page = dev_priv->current_page;
578
	return 0;
L
Linus Torvalds 已提交
579 580
}

581
static int i915_quiescent(struct drm_device * dev)
L
Linus Torvalds 已提交
582 583 584 585
{
	drm_i915_private_t *dev_priv = dev->dev_private;

	i915_kernel_lost_context(dev);
586
	return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
L
Linus Torvalds 已提交
587 588
}

589 590
static int i915_flush_ioctl(struct drm_device *dev, void *data,
			    struct drm_file *file_priv)
L
Linus Torvalds 已提交
591
{
592 593 594
	int ret;

	RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
595

596 597 598 599 600
	mutex_lock(&dev->struct_mutex);
	ret = i915_quiescent(dev);
	mutex_unlock(&dev->struct_mutex);

	return ret;
L
Linus Torvalds 已提交
601 602
}

603 604
static int i915_batchbuffer(struct drm_device *dev, void *data,
			    struct drm_file *file_priv)
L
Linus Torvalds 已提交
605 606
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
607
	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
L
Linus Torvalds 已提交
608
	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
609
	    master_priv->sarea_priv;
610
	drm_i915_batchbuffer_t *batch = data;
L
Linus Torvalds 已提交
611 612 613 614
	int ret;

	if (!dev_priv->allow_batchbuffer) {
		DRM_ERROR("Batchbuffer ioctl disabled\n");
E
Eric Anholt 已提交
615
		return -EINVAL;
L
Linus Torvalds 已提交
616 617 618
	}

	DRM_DEBUG("i915 batchbuffer, start %x used %d cliprects %d\n",
619
		  batch->start, batch->used, batch->num_cliprects);
L
Linus Torvalds 已提交
620

621
	RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
622

623 624
	if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
						       batch->num_cliprects *
625
						       sizeof(struct drm_clip_rect)))
E
Eric Anholt 已提交
626
		return -EFAULT;
L
Linus Torvalds 已提交
627

628
	mutex_lock(&dev->struct_mutex);
629
	ret = i915_dispatch_batchbuffer(dev, batch);
630
	mutex_unlock(&dev->struct_mutex);
L
Linus Torvalds 已提交
631

632
	if (sarea_priv)
633
		sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
L
Linus Torvalds 已提交
634 635 636
	return ret;
}

637 638
static int i915_cmdbuffer(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
639 640
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
641
	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
L
Linus Torvalds 已提交
642
	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
643
	    master_priv->sarea_priv;
644
	drm_i915_cmdbuffer_t *cmdbuf = data;
L
Linus Torvalds 已提交
645 646 647
	int ret;

	DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
648
		  cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
L
Linus Torvalds 已提交
649

650
	RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
651

652 653 654
	if (cmdbuf->num_cliprects &&
	    DRM_VERIFYAREA_READ(cmdbuf->cliprects,
				cmdbuf->num_cliprects *
655
				sizeof(struct drm_clip_rect))) {
L
Linus Torvalds 已提交
656
		DRM_ERROR("Fault accessing cliprects\n");
E
Eric Anholt 已提交
657
		return -EFAULT;
L
Linus Torvalds 已提交
658 659
	}

660
	mutex_lock(&dev->struct_mutex);
661
	ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
662
	mutex_unlock(&dev->struct_mutex);
L
Linus Torvalds 已提交
663 664 665 666 667
	if (ret) {
		DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
		return ret;
	}

668
	if (sarea_priv)
669
		sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
L
Linus Torvalds 已提交
670 671 672
	return 0;
}

673 674
static int i915_flip_bufs(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
675
{
676 677
	int ret;

678
	DRM_DEBUG("%s\n", __func__);
L
Linus Torvalds 已提交
679

680
	RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
681

682 683 684 685 686
	mutex_lock(&dev->struct_mutex);
	ret = i915_dispatch_flip(dev);
	mutex_unlock(&dev->struct_mutex);

	return ret;
L
Linus Torvalds 已提交
687 688
}

689 690
static int i915_getparam(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
691 692
{
	drm_i915_private_t *dev_priv = dev->dev_private;
693
	drm_i915_getparam_t *param = data;
L
Linus Torvalds 已提交
694 695 696
	int value;

	if (!dev_priv) {
697
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
698
		return -EINVAL;
L
Linus Torvalds 已提交
699 700
	}

701
	switch (param->param) {
L
Linus Torvalds 已提交
702
	case I915_PARAM_IRQ_ACTIVE:
703
		value = dev->pdev->irq ? 1 : 0;
L
Linus Torvalds 已提交
704 705 706 707
		break;
	case I915_PARAM_ALLOW_BATCHBUFFER:
		value = dev_priv->allow_batchbuffer ? 1 : 0;
		break;
D
Dave Airlie 已提交
708 709 710
	case I915_PARAM_LAST_DISPATCH:
		value = READ_BREADCRUMB(dev_priv);
		break;
K
Kristian Høgsberg 已提交
711 712 713
	case I915_PARAM_CHIPSET_ID:
		value = dev->pci_device;
		break;
714
	case I915_PARAM_HAS_GEM:
715
		value = dev_priv->has_gem;
716
		break;
L
Linus Torvalds 已提交
717
	default:
718
		DRM_ERROR("Unknown parameter %d\n", param->param);
E
Eric Anholt 已提交
719
		return -EINVAL;
L
Linus Torvalds 已提交
720 721
	}

722
	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
L
Linus Torvalds 已提交
723
		DRM_ERROR("DRM_COPY_TO_USER failed\n");
E
Eric Anholt 已提交
724
		return -EFAULT;
L
Linus Torvalds 已提交
725 726 727 728 729
	}

	return 0;
}

730 731
static int i915_setparam(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
732 733
{
	drm_i915_private_t *dev_priv = dev->dev_private;
734
	drm_i915_setparam_t *param = data;
L
Linus Torvalds 已提交
735 736

	if (!dev_priv) {
737
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
738
		return -EINVAL;
L
Linus Torvalds 已提交
739 740
	}

741
	switch (param->param) {
L
Linus Torvalds 已提交
742 743 744
	case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
		break;
	case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
745
		dev_priv->tex_lru_log_granularity = param->value;
L
Linus Torvalds 已提交
746 747
		break;
	case I915_SETPARAM_ALLOW_BATCHBUFFER:
748
		dev_priv->allow_batchbuffer = param->value;
L
Linus Torvalds 已提交
749 750
		break;
	default:
751
		DRM_ERROR("unknown parameter %d\n", param->param);
E
Eric Anholt 已提交
752
		return -EINVAL;
L
Linus Torvalds 已提交
753 754 755 756 757
	}

	return 0;
}

758 759
static int i915_set_status_page(struct drm_device *dev, void *data,
				struct drm_file *file_priv)
760 761
{
	drm_i915_private_t *dev_priv = dev->dev_private;
762
	drm_i915_hws_addr_t *hws = data;
763 764 765

	if (!I915_NEED_GFX_HWS(dev))
		return -EINVAL;
766 767

	if (!dev_priv) {
768
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
769
		return -EINVAL;
770 771
	}

772 773 774
	printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr);

	dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
775

776
	dev_priv->hws_map.offset = dev->agp->base + hws->addr;
777 778 779 780 781 782 783 784 785 786 787
	dev_priv->hws_map.size = 4*1024;
	dev_priv->hws_map.type = 0;
	dev_priv->hws_map.flags = 0;
	dev_priv->hws_map.mtrr = 0;

	drm_core_ioremap(&dev_priv->hws_map, dev);
	if (dev_priv->hws_map.handle == NULL) {
		i915_dma_cleanup(dev);
		dev_priv->status_gfx_addr = 0;
		DRM_ERROR("can not ioremap virtual address for"
				" G33 hw status page\n");
E
Eric Anholt 已提交
788
		return -ENOMEM;
789 790 791 792
	}
	dev_priv->hw_status_page = dev_priv->hws_map.handle;

	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
793 794
	I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
	DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n",
795 796 797 798 799
			dev_priv->status_gfx_addr);
	DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
	return 0;
}

800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
int i915_master_create(struct drm_device *dev, struct drm_master *master)
{
	struct drm_i915_master_private *master_priv;

	master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER);
	if (!master_priv)
		return -ENOMEM;

	master->driver_priv = master_priv;
	return 0;
}

void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
{
	struct drm_i915_master_private *master_priv = master->driver_priv;

	if (!master_priv)
		return;

	drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER);

	master->driver_priv = NULL;
}

824
int i915_driver_load(struct drm_device *dev, unsigned long flags)
825
{
J
Jesse Barnes 已提交
826 827 828 829
	struct drm_i915_private *dev_priv = dev->dev_private;
	unsigned long base, size;
	int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;

830 831 832 833 834 835 836
	/* i915 has 4 more counters */
	dev->counters += 4;
	dev->types[6] = _DRM_STAT_IRQ;
	dev->types[7] = _DRM_STAT_PRIMARY;
	dev->types[8] = _DRM_STAT_SECONDARY;
	dev->types[9] = _DRM_STAT_DMA;

J
Jesse Barnes 已提交
837 838 839 840 841 842 843
	dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER);
	if (dev_priv == NULL)
		return -ENOMEM;

	memset(dev_priv, 0, sizeof(drm_i915_private_t));

	dev->dev_private = (void *)dev_priv;
844
	dev_priv->dev = dev;
J
Jesse Barnes 已提交
845 846 847 848 849

	/* Add register map (needed for suspend/resume) */
	base = drm_get_resource_start(dev, mmio_bar);
	size = drm_get_resource_len(dev, mmio_bar);

850
	dev_priv->regs = ioremap(base, size);
851

852 853 854 855 856 857 858 859
#ifdef CONFIG_HIGHMEM64G
	/* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */
	dev_priv->has_gem = 0;
#else
	/* enable GEM by default */
	dev_priv->has_gem = 1;
#endif

860 861
	i915_gem_load(dev);

862 863 864 865 866 867
	/* Init HWS */
	if (!I915_NEED_GFX_HWS(dev)) {
		ret = i915_init_phys_hws(dev);
		if (ret != 0)
			return ret;
	}
868 869 870 871 872 873 874

	/* On the 945G/GM, the chipset reports the MSI capability on the
	 * integrated graphics even though the support isn't actually there
	 * according to the published specs.  It doesn't appear to function
	 * correctly in testing on 945G.
	 * This may be a side effect of MSI having been made available for PEG
	 * and the registers being closely associated.
875 876
	 *
	 * According to chipset errata, on the 965GM, MSI interrupts may
877 878
	 * be lost or delayed, but we use them anyways to avoid
	 * stuck interrupts on some machines.
879
	 */
880
	if (!IS_I945G(dev) && !IS_I945GM(dev))
881
		pci_enable_msi(dev->pdev);
882

883 884
	intel_opregion_init(dev);

885 886
	spin_lock_init(&dev_priv->user_irq_lock);

887 888 889 890 891 892 893
	ret = drm_vblank_init(dev, I915_NUM_PIPE);

	if (ret) {
		(void) i915_driver_unload(dev);
		return ret;
	}

J
Jesse Barnes 已提交
894 895 896 897 898 899 900
	return ret;
}

int i915_driver_unload(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = dev->dev_private;

901 902 903
	if (dev->pdev->msi_enabled)
		pci_disable_msi(dev->pdev);

904 905
	i915_free_hws(dev);

906 907
	if (dev_priv->regs != NULL)
		iounmap(dev_priv->regs);
J
Jesse Barnes 已提交
908

909 910
	intel_opregion_free(dev);

J
Jesse Barnes 已提交
911 912 913
	drm_free(dev->dev_private, sizeof(drm_i915_private_t),
		 DRM_MEM_DRIVER);

914 915 916
	return 0;
}

917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
{
	struct drm_i915_file_private *i915_file_priv;

	DRM_DEBUG("\n");
	i915_file_priv = (struct drm_i915_file_private *)
	    drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES);

	if (!i915_file_priv)
		return -ENOMEM;

	file_priv->driver_priv = i915_file_priv;

	i915_file_priv->mm.last_gem_seqno = 0;
	i915_file_priv->mm.last_gem_throttle_seqno = 0;

	return 0;
}

936
void i915_driver_lastclose(struct drm_device * dev)
L
Linus Torvalds 已提交
937
{
J
Jesse Barnes 已提交
938 939
	drm_i915_private_t *dev_priv = dev->dev_private;

D
Dave Airlie 已提交
940 941 942
	if (!dev_priv)
		return;

943 944
	i915_gem_lastclose(dev);

J
Jesse Barnes 已提交
945
	if (dev_priv->agp_heap)
D
Dave Airlie 已提交
946
		i915_mem_takedown(&(dev_priv->agp_heap));
J
Jesse Barnes 已提交
947

D
Dave Airlie 已提交
948
	i915_dma_cleanup(dev);
L
Linus Torvalds 已提交
949 950
}

951
void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
L
Linus Torvalds 已提交
952
{
J
Jesse Barnes 已提交
953 954
	drm_i915_private_t *dev_priv = dev->dev_private;
	i915_mem_release(dev, file_priv, dev_priv->agp_heap);
L
Linus Torvalds 已提交
955 956
}

957 958 959 960 961 962 963
void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
{
	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;

	drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES);
}

964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
struct drm_ioctl_desc i915_ioctls[] = {
	DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
	DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_FLIP, i915_flip_bufs, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_BATCHBUFFER, i915_batchbuffer, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_IRQ_EMIT, i915_irq_emit, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_IRQ_WAIT, i915_irq_wait, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_GETPARAM, i915_getparam, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_SETPARAM, i915_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
	DRM_IOCTL_DEF(DRM_I915_ALLOC, i915_mem_alloc, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_FREE, i915_mem_free, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_INIT_HEAP, i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
	DRM_IOCTL_DEF(DRM_I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_DESTROY_HEAP,  i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
	DRM_IOCTL_DEF(DRM_I915_SET_VBLANK_PIPE,  i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY ),
	DRM_IOCTL_DEF(DRM_I915_GET_VBLANK_PIPE,  i915_vblank_pipe_get, DRM_AUTH ),
	DRM_IOCTL_DEF(DRM_I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
981
	DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
982
	DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
983 984 985 986 987
	DRM_IOCTL_DEF(DRM_I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
	DRM_IOCTL_DEF(DRM_I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY),
	DRM_IOCTL_DEF(DRM_I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_GEM_THROTTLE, i915_gem_throttle_ioctl, DRM_AUTH),
988 989
	DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
	DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
990 991 992 993
	DRM_IOCTL_DEF(DRM_I915_GEM_CREATE, i915_gem_create_ioctl, 0),
	DRM_IOCTL_DEF(DRM_I915_GEM_PREAD, i915_gem_pread_ioctl, 0),
	DRM_IOCTL_DEF(DRM_I915_GEM_PWRITE, i915_gem_pwrite_ioctl, 0),
	DRM_IOCTL_DEF(DRM_I915_GEM_MMAP, i915_gem_mmap_ioctl, 0),
994
	DRM_IOCTL_DEF(DRM_I915_GEM_MMAP_GTT, i915_gem_mmap_gtt_ioctl, 0),
995 996 997 998
	DRM_IOCTL_DEF(DRM_I915_GEM_SET_DOMAIN, i915_gem_set_domain_ioctl, 0),
	DRM_IOCTL_DEF(DRM_I915_GEM_SW_FINISH, i915_gem_sw_finish_ioctl, 0),
	DRM_IOCTL_DEF(DRM_I915_GEM_SET_TILING, i915_gem_set_tiling, 0),
	DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0),
999
	DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, 0),
D
Dave Airlie 已提交
1000 1001 1002
};

int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014

/**
 * Determine if the device really is AGP or not.
 *
 * All Intel graphics chipsets are treated as AGP, even if they are really
 * PCI-e.
 *
 * \param dev   The device to be tested.
 *
 * \returns
 * A value of 1 is always retured to indictate every i9x5 is AGP.
 */
1015
int i915_driver_device_is_agp(struct drm_device * dev)
1016 1017 1018
{
	return 1;
}