i915_dma.c 24.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 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
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
592 593 594 595

	return i915_quiescent(dev);
}

596 597
static int i915_batchbuffer(struct drm_device *dev, void *data,
			    struct drm_file *file_priv)
L
Linus Torvalds 已提交
598 599
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
600
	u32 *hw_status = dev_priv->hw_status_page;
L
Linus Torvalds 已提交
601 602
	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
	    dev_priv->sarea_priv;
603
	drm_i915_batchbuffer_t *batch = data;
L
Linus Torvalds 已提交
604 605 606 607
	int ret;

	if (!dev_priv->allow_batchbuffer) {
		DRM_ERROR("Batchbuffer ioctl disabled\n");
E
Eric Anholt 已提交
608
		return -EINVAL;
L
Linus Torvalds 已提交
609 610 611
	}

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

614
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
615

616 617
	if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
						       batch->num_cliprects *
618
						       sizeof(struct drm_clip_rect)))
E
Eric Anholt 已提交
619
		return -EFAULT;
L
Linus Torvalds 已提交
620

621
	ret = i915_dispatch_batchbuffer(dev, batch);
L
Linus Torvalds 已提交
622

623
	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
624 625 626
	return ret;
}

627 628
static int i915_cmdbuffer(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
629 630
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
631
	u32 *hw_status = dev_priv->hw_status_page;
L
Linus Torvalds 已提交
632 633
	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
	    dev_priv->sarea_priv;
634
	drm_i915_cmdbuffer_t *cmdbuf = data;
L
Linus Torvalds 已提交
635 636 637
	int ret;

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

640
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
641

642 643 644
	if (cmdbuf->num_cliprects &&
	    DRM_VERIFYAREA_READ(cmdbuf->cliprects,
				cmdbuf->num_cliprects *
645
				sizeof(struct drm_clip_rect))) {
L
Linus Torvalds 已提交
646
		DRM_ERROR("Fault accessing cliprects\n");
E
Eric Anholt 已提交
647
		return -EFAULT;
L
Linus Torvalds 已提交
648 649
	}

650
	ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
L
Linus Torvalds 已提交
651 652 653 654 655
	if (ret) {
		DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
		return ret;
	}

656
	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
657 658 659
	return 0;
}

660 661
static int i915_flip_bufs(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
662
{
663
	DRM_DEBUG("%s\n", __func__);
L
Linus Torvalds 已提交
664

665
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
666

667
	return i915_dispatch_flip(dev);
L
Linus Torvalds 已提交
668 669
}

670 671
static int i915_getparam(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
672 673
{
	drm_i915_private_t *dev_priv = dev->dev_private;
674
	drm_i915_getparam_t *param = data;
L
Linus Torvalds 已提交
675 676 677
	int value;

	if (!dev_priv) {
678
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
679
		return -EINVAL;
L
Linus Torvalds 已提交
680 681
	}

682
	switch (param->param) {
L
Linus Torvalds 已提交
683
	case I915_PARAM_IRQ_ACTIVE:
684
		value = dev->pdev->irq ? 1 : 0;
L
Linus Torvalds 已提交
685 686 687 688
		break;
	case I915_PARAM_ALLOW_BATCHBUFFER:
		value = dev_priv->allow_batchbuffer ? 1 : 0;
		break;
D
Dave Airlie 已提交
689 690 691
	case I915_PARAM_LAST_DISPATCH:
		value = READ_BREADCRUMB(dev_priv);
		break;
692 693 694
	case I915_PARAM_HAS_GEM:
		value = 1;
		break;
L
Linus Torvalds 已提交
695
	default:
696
		DRM_ERROR("Unknown parameter %d\n", param->param);
E
Eric Anholt 已提交
697
		return -EINVAL;
L
Linus Torvalds 已提交
698 699
	}

700
	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
L
Linus Torvalds 已提交
701
		DRM_ERROR("DRM_COPY_TO_USER failed\n");
E
Eric Anholt 已提交
702
		return -EFAULT;
L
Linus Torvalds 已提交
703 704 705 706 707
	}

	return 0;
}

708 709
static int i915_setparam(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
710 711
{
	drm_i915_private_t *dev_priv = dev->dev_private;
712
	drm_i915_setparam_t *param = data;
L
Linus Torvalds 已提交
713 714

	if (!dev_priv) {
715
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
716
		return -EINVAL;
L
Linus Torvalds 已提交
717 718
	}

719
	switch (param->param) {
L
Linus Torvalds 已提交
720 721 722
	case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
		break;
	case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
723
		dev_priv->tex_lru_log_granularity = param->value;
L
Linus Torvalds 已提交
724 725
		break;
	case I915_SETPARAM_ALLOW_BATCHBUFFER:
726
		dev_priv->allow_batchbuffer = param->value;
L
Linus Torvalds 已提交
727 728
		break;
	default:
729
		DRM_ERROR("unknown parameter %d\n", param->param);
E
Eric Anholt 已提交
730
		return -EINVAL;
L
Linus Torvalds 已提交
731 732 733 734 735
	}

	return 0;
}

736 737
static int i915_set_status_page(struct drm_device *dev, void *data,
				struct drm_file *file_priv)
738 739
{
	drm_i915_private_t *dev_priv = dev->dev_private;
740
	drm_i915_hws_addr_t *hws = data;
741 742 743

	if (!I915_NEED_GFX_HWS(dev))
		return -EINVAL;
744 745

	if (!dev_priv) {
746
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
747
		return -EINVAL;
748 749
	}

750 751 752
	printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr);

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

754
	dev_priv->hws_map.offset = dev->agp->base + hws->addr;
755 756 757 758 759 760 761 762 763 764 765
	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 已提交
766
		return -ENOMEM;
767 768 769 770
	}
	dev_priv->hw_status_page = dev_priv->hws_map.handle;

	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
771 772
	I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
	DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n",
773 774 775 776 777
			dev_priv->status_gfx_addr);
	DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
	return 0;
}

778
int i915_driver_load(struct drm_device *dev, unsigned long flags)
779
{
J
Jesse Barnes 已提交
780 781 782 783
	struct drm_i915_private *dev_priv = dev->dev_private;
	unsigned long base, size;
	int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;

784 785 786 787 788 789 790
	/* 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 已提交
791 792 793 794 795 796 797
	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;
798
	dev_priv->dev = dev;
J
Jesse Barnes 已提交
799 800 801 802 803

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

804 805
	ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
			 _DRM_KERNEL | _DRM_DRIVER,
J
Jesse Barnes 已提交
806
			 &dev_priv->mmio_map);
807

808 809
	i915_gem_load(dev);

810 811 812 813 814 815
	/* Init HWS */
	if (!I915_NEED_GFX_HWS(dev)) {
		ret = i915_init_phys_hws(dev);
		if (ret != 0)
			return ret;
	}
816 817 818 819 820 821 822 823 824

	/* 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))
825 826
		if (pci_enable_msi(dev->pdev))
			DRM_ERROR("failed to enable MSI\n");
827

828 829
	intel_opregion_init(dev);

830 831
	spin_lock_init(&dev_priv->user_irq_lock);

J
Jesse Barnes 已提交
832 833 834 835 836 837 838
	return ret;
}

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

839 840 841
	if (dev->pdev->msi_enabled)
		pci_disable_msi(dev->pdev);

842 843
	i915_free_hws(dev);

J
Jesse Barnes 已提交
844 845 846
	if (dev_priv->mmio_map)
		drm_rmmap(dev, dev_priv->mmio_map);

847 848
	intel_opregion_free(dev);

J
Jesse Barnes 已提交
849 850 851
	drm_free(dev->dev_private, sizeof(drm_i915_private_t),
		 DRM_MEM_DRIVER);

852 853 854
	return 0;
}

855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
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;
}

874
void i915_driver_lastclose(struct drm_device * dev)
L
Linus Torvalds 已提交
875
{
J
Jesse Barnes 已提交
876 877
	drm_i915_private_t *dev_priv = dev->dev_private;

D
Dave Airlie 已提交
878 879 880
	if (!dev_priv)
		return;

881 882
	i915_gem_lastclose(dev);

J
Jesse Barnes 已提交
883
	if (dev_priv->agp_heap)
D
Dave Airlie 已提交
884
		i915_mem_takedown(&(dev_priv->agp_heap));
J
Jesse Barnes 已提交
885

D
Dave Airlie 已提交
886
	i915_dma_cleanup(dev);
L
Linus Torvalds 已提交
887 888
}

889
void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
L
Linus Torvalds 已提交
890
{
J
Jesse Barnes 已提交
891 892
	drm_i915_private_t *dev_priv = dev->dev_private;
	i915_mem_release(dev, file_priv, dev_priv->agp_heap);
L
Linus Torvalds 已提交
893 894
}

895 896 897 898 899 900 901
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);
}

902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
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),
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
	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 已提交
936 937 938
};

int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
939 940 941 942 943 944 945 946 947 948 949 950

/**
 * 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.
 */
951
int i915_driver_device_is_agp(struct drm_device * dev)
952 953 954
{
	return 1;
}