i915_dma.c 24.9 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 42
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
43 44 45
	u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
	u32 last_acthd = I915_READ(acthd_reg);
	u32 acthd;
46
	u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
L
Linus Torvalds 已提交
47 48
	int i;

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

		dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;

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

		last_head = ring->head;
66 67 68
		last_acthd = acthd;
		msleep_interruptible(10);

L
Linus Torvalds 已提交
69 70
	}

E
Eric Anholt 已提交
71
	return -EBUSY;
L
Linus Torvalds 已提交
72 73
}

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
/**
 * Sets up the hardware status page for devices that need a physical address
 * in the register.
 */
int i915_init_phys_hws(struct drm_device *dev)
{
	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.
 */
void i915_free_hws(struct drm_device *dev)
{
	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);
}

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

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

	if (ring->head == ring->tail)
		dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
}

135
static int i915_dma_cleanup(struct drm_device * dev)
L
Linus Torvalds 已提交
136
{
J
Jesse Barnes 已提交
137
	drm_i915_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
138 139 140 141
	/* 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.
	 */
142
	if (dev->irq_enabled)
D
Dave Airlie 已提交
143
		drm_irq_uninstall(dev);
L
Linus Torvalds 已提交
144

J
Jesse Barnes 已提交
145 146 147 148 149 150
	if (dev_priv->ring.virtual_start) {
		drm_core_ioremapfree(&dev_priv->ring.map, dev);
		dev_priv->ring.virtual_start = 0;
		dev_priv->ring.map.handle = 0;
		dev_priv->ring.map.size = 0;
	}
151

152 153 154
	/* Clear the HWS virtual address at teardown */
	if (I915_NEED_GFX_HWS(dev))
		i915_free_hws(dev);
L
Linus Torvalds 已提交
155 156 157 158

	return 0;
}

J
Jesse Barnes 已提交
159
static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
L
Linus Torvalds 已提交
160
{
J
Jesse Barnes 已提交
161
	drm_i915_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
162

163
	dev_priv->sarea = drm_getsarea(dev);
L
Linus Torvalds 已提交
164 165 166
	if (!dev_priv->sarea) {
		DRM_ERROR("can not find sarea!\n");
		i915_dma_cleanup(dev);
E
Eric Anholt 已提交
167
		return -EINVAL;
L
Linus Torvalds 已提交
168 169 170 171 172
	}

	dev_priv->sarea_priv = (drm_i915_sarea_t *)
	    ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);

173 174 175 176 177 178 179
	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 已提交
180

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

184 185 186 187 188
		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 已提交
189

190 191 192 193 194 195 196 197
		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 已提交
198 199 200 201
	}

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

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

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

	return 0;
}

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

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

	if (!dev_priv->sarea) {
		DRM_ERROR("can not find sarea!\n");
E
Eric Anholt 已提交
223
		return -EINVAL;
L
Linus Torvalds 已提交
224 225 226 227 228
	}

	if (dev_priv->ring.map.handle == NULL) {
		DRM_ERROR("can not ioremap virtual address for"
			  " ring buffer\n");
E
Eric Anholt 已提交
229
		return -ENOMEM;
L
Linus Torvalds 已提交
230 231 232 233 234
	}

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

239
	if (dev_priv->status_gfx_addr != 0)
240
		I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
241
	else
242
		I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
L
Linus Torvalds 已提交
243 244 245 246 247
	DRM_DEBUG("Enabled hardware status page\n");

	return 0;
}

248 249
static int i915_dma_init(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
250
{
251
	drm_i915_init_t *init = data;
L
Linus Torvalds 已提交
252 253
	int retcode = 0;

254
	switch (init->func) {
L
Linus Torvalds 已提交
255
	case I915_INIT_DMA:
J
Jesse Barnes 已提交
256
		retcode = i915_initialize(dev, init);
L
Linus Torvalds 已提交
257 258 259 260 261
		break;
	case I915_CLEANUP_DMA:
		retcode = i915_dma_cleanup(dev);
		break;
	case I915_RESUME_DMA:
D
Dave Airlie 已提交
262
		retcode = i915_dma_resume(dev);
L
Linus Torvalds 已提交
263 264
		break;
	default:
E
Eric Anholt 已提交
265
		retcode = -EINVAL;
L
Linus Torvalds 已提交
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 300 301 302 303 304 305
		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 已提交
306
			switch ((cmd >> 16) & 0xff) {
L
Linus Torvalds 已提交
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 337 338 339 340 341 342
			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 已提交
343
/*	printk("validate_cmd( %x ): %d\n", cmd, ret); */
L
Linus Torvalds 已提交
344 345 346 347

	return ret;
}

348
static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwords)
L
Linus Torvalds 已提交
349 350 351 352 353
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	int i;
	RING_LOCALS;

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

357
	BEGIN_LP_RING((dwords+1)&~1);
358

L
Linus Torvalds 已提交
359 360 361 362
	for (i = 0; i < dwords;) {
		int cmd, sz;

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

		if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
E
Eric Anholt 已提交
366
			return -EINVAL;
L
Linus Torvalds 已提交
367 368 369 370 371 372

		OUT_RING(cmd);

		while (++i, --sz) {
			if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i],
							 sizeof(cmd))) {
E
Eric Anholt 已提交
373
				return -EINVAL;
L
Linus Torvalds 已提交
374 375 376 377 378
			}
			OUT_RING(cmd);
		}
	}

379 380 381 382 383
	if (dwords & 1)
		OUT_RING(0);

	ADVANCE_LP_RING();

L
Linus Torvalds 已提交
384 385 386
	return 0;
}

387 388 389 390
int
i915_emit_box(struct drm_device *dev,
	      struct drm_clip_rect __user *boxes,
	      int i, int DR1, int DR4)
L
Linus Torvalds 已提交
391 392
{
	drm_i915_private_t *dev_priv = dev->dev_private;
393
	struct drm_clip_rect box;
L
Linus Torvalds 已提交
394 395 396
	RING_LOCALS;

	if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
E
Eric Anholt 已提交
397
		return -EFAULT;
L
Linus Torvalds 已提交
398 399 400 401 402
	}

	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 已提交
403
		return -EINVAL;
L
Linus Torvalds 已提交
404 405
	}

406 407 408 409
	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 已提交
410
		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
411 412 413 414 415 416 417 418 419 420 421 422
		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 已提交
423 424 425 426

	return 0;
}

427 428 429 430
/* XXX: Emitting the counter should really be moved to part of the IRQ
 * emit. For now, do it in both places:
 */

431
static void i915_emit_breadcrumb(struct drm_device *dev)
432 433 434 435
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	RING_LOCALS;

436
	dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
437

438 439
	if (dev_priv->counter > 0x7FFFFFFFUL)
		dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
440 441

	BEGIN_LP_RING(4);
442 443
	OUT_RING(MI_STORE_DWORD_INDEX);
	OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
444 445 446 447 448
	OUT_RING(dev_priv->counter);
	OUT_RING(0);
	ADVANCE_LP_RING();
}

449
static int i915_dispatch_cmdbuffer(struct drm_device * dev,
L
Linus Torvalds 已提交
450 451 452 453 454 455 456
				   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 已提交
457
		return -EINVAL;
L
Linus Torvalds 已提交
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
	}

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

477
	i915_emit_breadcrumb(dev);
L
Linus Torvalds 已提交
478 479 480
	return 0;
}

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

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

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

507
		if (!IS_I830(dev) && !IS_845G(dev)) {
L
Linus Torvalds 已提交
508
			BEGIN_LP_RING(2);
509 510 511 512 513 514 515
			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 已提交
516 517 518 519 520 521 522 523 524 525 526
			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();
		}
	}

527
	i915_emit_breadcrumb(dev);
L
Linus Torvalds 已提交
528 529 530 531

	return 0;
}

532
static int i915_dispatch_flip(struct drm_device * dev)
L
Linus Torvalds 已提交
533 534 535 536
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	RING_LOCALS;

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

542 543 544
	i915_kernel_lost_context(dev);

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

549 550 551 552 553 554
	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 已提交
555
	} else {
556 557
		OUT_RING(dev_priv->front_offset);
		dev_priv->current_page = 0;
L
Linus Torvalds 已提交
558
	}
559 560
	OUT_RING(0);
	ADVANCE_LP_RING();
L
Linus Torvalds 已提交
561

562 563 564 565
	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 已提交
566

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

631
	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
632 633 634
	return ret;
}

635 636
static int i915_cmdbuffer(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
637 638
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
639
	u32 *hw_status = dev_priv->hw_status_page;
L
Linus Torvalds 已提交
640 641
	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
	    dev_priv->sarea_priv;
642
	drm_i915_cmdbuffer_t *cmdbuf = data;
L
Linus Torvalds 已提交
643 644 645
	int ret;

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

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

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

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

666
	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
667 668 669
	return 0;
}

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

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

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

679 680 681 682 683
	mutex_lock(&dev->struct_mutex);
	ret = i915_dispatch_flip(dev);
	mutex_unlock(&dev->struct_mutex);

	return ret;
L
Linus Torvalds 已提交
684 685
}

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

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

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

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

	return 0;
}

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

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

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

	return 0;
}

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

	if (!I915_NEED_GFX_HWS(dev))
		return -EINVAL;
763 764

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

769 770 771
	printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr);

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

773
	dev_priv->hws_map.offset = dev->agp->base + hws->addr;
774 775 776 777 778 779 780 781 782 783 784
	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 已提交
785
		return -ENOMEM;
786 787 788 789
	}
	dev_priv->hw_status_page = dev_priv->hws_map.handle;

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

797
int i915_driver_load(struct drm_device *dev, unsigned long flags)
798
{
J
Jesse Barnes 已提交
799 800 801 802
	struct drm_i915_private *dev_priv = dev->dev_private;
	unsigned long base, size;
	int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;

803 804 805 806 807 808 809
	/* 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 已提交
810 811 812 813 814 815 816
	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;
817
	dev_priv->dev = dev;
J
Jesse Barnes 已提交
818 819 820 821 822

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

823 824
	ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
			 _DRM_KERNEL | _DRM_DRIVER,
J
Jesse Barnes 已提交
825
			 &dev_priv->mmio_map);
826

827 828
	i915_gem_load(dev);

829 830 831 832 833 834
	/* Init HWS */
	if (!I915_NEED_GFX_HWS(dev)) {
		ret = i915_init_phys_hws(dev);
		if (ret != 0)
			return ret;
	}
835 836 837 838 839 840 841 842 843

	/* 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.
	 */
	if (!IS_I945G(dev) && !IS_I945GM(dev))
844 845
		if (pci_enable_msi(dev->pdev))
			DRM_ERROR("failed to enable MSI\n");
846

847 848
	intel_opregion_init(dev);

849 850
	spin_lock_init(&dev_priv->user_irq_lock);

J
Jesse Barnes 已提交
851 852 853 854 855 856 857
	return ret;
}

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

858 859 860
	if (dev->pdev->msi_enabled)
		pci_disable_msi(dev->pdev);

861 862
	i915_free_hws(dev);

J
Jesse Barnes 已提交
863 864 865
	if (dev_priv->mmio_map)
		drm_rmmap(dev, dev_priv->mmio_map);

866 867
	intel_opregion_free(dev);

J
Jesse Barnes 已提交
868 869 870
	drm_free(dev->dev_private, sizeof(drm_i915_private_t),
		 DRM_MEM_DRIVER);

871 872 873
	return 0;
}

874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
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;
}

893
void i915_driver_lastclose(struct drm_device * dev)
L
Linus Torvalds 已提交
894
{
J
Jesse Barnes 已提交
895 896
	drm_i915_private_t *dev_priv = dev->dev_private;

D
Dave Airlie 已提交
897 898 899
	if (!dev_priv)
		return;

900 901
	i915_gem_lastclose(dev);

J
Jesse Barnes 已提交
902
	if (dev_priv->agp_heap)
D
Dave Airlie 已提交
903
		i915_mem_takedown(&(dev_priv->agp_heap));
J
Jesse Barnes 已提交
904

D
Dave Airlie 已提交
905
	i915_dma_cleanup(dev);
L
Linus Torvalds 已提交
906 907
}

908
void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
L
Linus Torvalds 已提交
909
{
J
Jesse Barnes 已提交
910 911
	drm_i915_private_t *dev_priv = dev->dev_private;
	i915_mem_release(dev, file_priv, dev_priv->agp_heap);
L
Linus Torvalds 已提交
912 913
}

914 915 916 917 918 919 920
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);
}

921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938
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),
	DRM_IOCTL_DEF(DRM_I915_HWS_ADDR, i915_set_status_page, DRM_AUTH),
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954
	DRM_IOCTL_DEF(DRM_I915_GEM_INIT, i915_gem_init_ioctl, DRM_AUTH),
	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),
	DRM_IOCTL_DEF(DRM_I915_GEM_ENTERVT, i915_gem_entervt_ioctl, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I915_GEM_LEAVEVT, i915_gem_leavevt_ioctl, DRM_AUTH),
	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),
	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),
D
Dave Airlie 已提交
955 956 957
};

int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
958 959 960 961 962 963 964 965 966 967 968 969

/**
 * 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.
 */
970
int i915_driver_device_is_agp(struct drm_device * dev)
971 972 973
{
	return 1;
}