i915_dma.c 22.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 173 174 175 176 177 178 179 180 181 182 183
	}

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

	dev_priv->ring.Start = init->ring_start;
	dev_priv->ring.End = init->ring_end;
	dev_priv->ring.Size = init->ring_size;
	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;

	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;

D
Dave Airlie 已提交
184
	drm_core_ioremap(&dev_priv->ring.map, dev);
L
Linus Torvalds 已提交
185 186 187 188 189

	if (dev_priv->ring.map.handle == NULL) {
		i915_dma_cleanup(dev);
		DRM_ERROR("can not ioremap virtual address for"
			  " ring buffer\n");
E
Eric Anholt 已提交
190
		return -ENOMEM;
L
Linus Torvalds 已提交
191 192 193 194
	}

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

195
	dev_priv->cpp = init->cpp;
L
Linus Torvalds 已提交
196 197 198 199 200 201 202 203 204 205 206 207
	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;
}

208
static int i915_dma_resume(struct drm_device * dev)
L
Linus Torvalds 已提交
209 210 211
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;

212
	DRM_DEBUG("%s\n", __func__);
L
Linus Torvalds 已提交
213 214 215

	if (!dev_priv->sarea) {
		DRM_ERROR("can not find sarea!\n");
E
Eric Anholt 已提交
216
		return -EINVAL;
L
Linus Torvalds 已提交
217 218 219 220 221
	}

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

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

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

	return 0;
}

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

247
	switch (init->func) {
L
Linus Torvalds 已提交
248
	case I915_INIT_DMA:
J
Jesse Barnes 已提交
249
		retcode = i915_initialize(dev, init);
L
Linus Torvalds 已提交
250 251 252 253 254
		break;
	case I915_CLEANUP_DMA:
		retcode = i915_dma_cleanup(dev);
		break;
	case I915_RESUME_DMA:
D
Dave Airlie 已提交
255
		retcode = i915_dma_resume(dev);
L
Linus Torvalds 已提交
256 257
		break;
	default:
E
Eric Anholt 已提交
258
		retcode = -EINVAL;
L
Linus Torvalds 已提交
259 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
		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 已提交
299
			switch ((cmd >> 16) & 0xff) {
L
Linus Torvalds 已提交
300 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
			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 已提交
336
/*	printk("validate_cmd( %x ): %d\n", cmd, ret); */
L
Linus Torvalds 已提交
337 338 339 340

	return ret;
}

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

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

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

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

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

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

		OUT_RING(cmd);

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

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

	ADVANCE_LP_RING();

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

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

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

	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 已提交
395
		return -EINVAL;
L
Linus Torvalds 已提交
396 397
	}

398 399 400 401
	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 已提交
402
		OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
403 404 405 406 407 408 409 410 411 412 413 414
		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 已提交
415 416 417 418

	return 0;
}

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

423
static void i915_emit_breadcrumb(struct drm_device *dev)
424 425 426 427
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	RING_LOCALS;

428
	dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
429

430 431
	if (dev_priv->counter > 0x7FFFFFFFUL)
		dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
432 433

	BEGIN_LP_RING(4);
434 435
	OUT_RING(MI_STORE_DWORD_INDEX);
	OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
436 437 438 439 440
	OUT_RING(dev_priv->counter);
	OUT_RING(0);
	ADVANCE_LP_RING();
}

441
static int i915_dispatch_cmdbuffer(struct drm_device * dev,
L
Linus Torvalds 已提交
442 443 444 445 446 447 448
				   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 已提交
449
		return -EINVAL;
L
Linus Torvalds 已提交
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
	}

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

469
	i915_emit_breadcrumb(dev);
L
Linus Torvalds 已提交
470 471 472
	return 0;
}

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

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

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

499
		if (!IS_I830(dev) && !IS_845G(dev)) {
L
Linus Torvalds 已提交
500
			BEGIN_LP_RING(2);
501 502 503 504 505 506 507
			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 已提交
508 509 510 511 512 513 514 515 516 517 518
			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();
		}
	}

519
	i915_emit_breadcrumb(dev);
L
Linus Torvalds 已提交
520 521 522 523

	return 0;
}

524
static int i915_dispatch_flip(struct drm_device * dev)
L
Linus Torvalds 已提交
525 526 527 528
{
	drm_i915_private_t *dev_priv = dev->dev_private;
	RING_LOCALS;

529
	DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
530
		  __func__,
531 532
		  dev_priv->current_page,
		  dev_priv->sarea_priv->pf_current_page);
L
Linus Torvalds 已提交
533

534 535 536
	i915_kernel_lost_context(dev);

	BEGIN_LP_RING(2);
537
	OUT_RING(MI_FLUSH | MI_READ_FLUSH);
538 539
	OUT_RING(0);
	ADVANCE_LP_RING();
L
Linus Torvalds 已提交
540

541 542 543 544 545 546
	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 已提交
547
	} else {
548 549
		OUT_RING(dev_priv->front_offset);
		dev_priv->current_page = 0;
L
Linus Torvalds 已提交
550
	}
551 552
	OUT_RING(0);
	ADVANCE_LP_RING();
L
Linus Torvalds 已提交
553

554 555 556 557
	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 已提交
558

559
	dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
L
Linus Torvalds 已提交
560 561

	BEGIN_LP_RING(4);
562 563
	OUT_RING(MI_STORE_DWORD_INDEX);
	OUT_RING(5 << MI_STORE_DWORD_INDEX_SHIFT);
564 565
	OUT_RING(dev_priv->counter);
	OUT_RING(0);
L
Linus Torvalds 已提交
566 567
	ADVANCE_LP_RING();

568 569
	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
	return 0;
L
Linus Torvalds 已提交
570 571
}

572
static int i915_quiescent(struct drm_device * dev)
L
Linus Torvalds 已提交
573 574 575 576
{
	drm_i915_private_t *dev_priv = dev->dev_private;

	i915_kernel_lost_context(dev);
577
	return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
L
Linus Torvalds 已提交
578 579
}

580 581
static int i915_flush_ioctl(struct drm_device *dev, void *data,
			    struct drm_file *file_priv)
L
Linus Torvalds 已提交
582
{
583
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
584 585 586 587

	return i915_quiescent(dev);
}

588 589
static int i915_batchbuffer(struct drm_device *dev, void *data,
			    struct drm_file *file_priv)
L
Linus Torvalds 已提交
590 591
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
592
	u32 *hw_status = dev_priv->hw_status_page;
L
Linus Torvalds 已提交
593 594
	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
	    dev_priv->sarea_priv;
595
	drm_i915_batchbuffer_t *batch = data;
L
Linus Torvalds 已提交
596 597 598 599
	int ret;

	if (!dev_priv->allow_batchbuffer) {
		DRM_ERROR("Batchbuffer ioctl disabled\n");
E
Eric Anholt 已提交
600
		return -EINVAL;
L
Linus Torvalds 已提交
601 602 603
	}

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

606
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
607

608 609
	if (batch->num_cliprects && DRM_VERIFYAREA_READ(batch->cliprects,
						       batch->num_cliprects *
610
						       sizeof(struct drm_clip_rect)))
E
Eric Anholt 已提交
611
		return -EFAULT;
L
Linus Torvalds 已提交
612

613
	ret = i915_dispatch_batchbuffer(dev, batch);
L
Linus Torvalds 已提交
614

615
	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
616 617 618
	return ret;
}

619 620
static int i915_cmdbuffer(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
621 622
{
	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
623
	u32 *hw_status = dev_priv->hw_status_page;
L
Linus Torvalds 已提交
624 625
	drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
	    dev_priv->sarea_priv;
626
	drm_i915_cmdbuffer_t *cmdbuf = data;
L
Linus Torvalds 已提交
627 628 629
	int ret;

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

632
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
633

634 635 636
	if (cmdbuf->num_cliprects &&
	    DRM_VERIFYAREA_READ(cmdbuf->cliprects,
				cmdbuf->num_cliprects *
637
				sizeof(struct drm_clip_rect))) {
L
Linus Torvalds 已提交
638
		DRM_ERROR("Fault accessing cliprects\n");
E
Eric Anholt 已提交
639
		return -EFAULT;
L
Linus Torvalds 已提交
640 641
	}

642
	ret = i915_dispatch_cmdbuffer(dev, cmdbuf);
L
Linus Torvalds 已提交
643 644 645 646 647
	if (ret) {
		DRM_ERROR("i915_dispatch_cmdbuffer failed\n");
		return ret;
	}

648
	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
649 650 651
	return 0;
}

652 653
static int i915_flip_bufs(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
654
{
655
	DRM_DEBUG("%s\n", __func__);
L
Linus Torvalds 已提交
656

657
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
658

659
	return i915_dispatch_flip(dev);
L
Linus Torvalds 已提交
660 661
}

662 663
static int i915_getparam(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
664 665
{
	drm_i915_private_t *dev_priv = dev->dev_private;
666
	drm_i915_getparam_t *param = data;
L
Linus Torvalds 已提交
667 668 669
	int value;

	if (!dev_priv) {
670
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
671
		return -EINVAL;
L
Linus Torvalds 已提交
672 673
	}

674
	switch (param->param) {
L
Linus Torvalds 已提交
675
	case I915_PARAM_IRQ_ACTIVE:
676
		value = dev->pdev->irq ? 1 : 0;
L
Linus Torvalds 已提交
677 678 679 680
		break;
	case I915_PARAM_ALLOW_BATCHBUFFER:
		value = dev_priv->allow_batchbuffer ? 1 : 0;
		break;
D
Dave Airlie 已提交
681 682 683
	case I915_PARAM_LAST_DISPATCH:
		value = READ_BREADCRUMB(dev_priv);
		break;
L
Linus Torvalds 已提交
684
	default:
685
		DRM_ERROR("Unknown parameter %d\n", param->param);
E
Eric Anholt 已提交
686
		return -EINVAL;
L
Linus Torvalds 已提交
687 688
	}

689
	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
L
Linus Torvalds 已提交
690
		DRM_ERROR("DRM_COPY_TO_USER failed\n");
E
Eric Anholt 已提交
691
		return -EFAULT;
L
Linus Torvalds 已提交
692 693 694 695 696
	}

	return 0;
}

697 698
static int i915_setparam(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
699 700
{
	drm_i915_private_t *dev_priv = dev->dev_private;
701
	drm_i915_setparam_t *param = data;
L
Linus Torvalds 已提交
702 703

	if (!dev_priv) {
704
		DRM_ERROR("called with no initialization\n");
E
Eric Anholt 已提交
705
		return -EINVAL;
L
Linus Torvalds 已提交
706 707
	}

708
	switch (param->param) {
L
Linus Torvalds 已提交
709 710 711
	case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
		break;
	case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
712
		dev_priv->tex_lru_log_granularity = param->value;
L
Linus Torvalds 已提交
713 714
		break;
	case I915_SETPARAM_ALLOW_BATCHBUFFER:
715
		dev_priv->allow_batchbuffer = param->value;
L
Linus Torvalds 已提交
716 717
		break;
	default:
718
		DRM_ERROR("unknown parameter %d\n", param->param);
E
Eric Anholt 已提交
719
		return -EINVAL;
L
Linus Torvalds 已提交
720 721 722 723 724
	}

	return 0;
}

725 726
static int i915_set_status_page(struct drm_device *dev, void *data,
				struct drm_file *file_priv)
727 728
{
	drm_i915_private_t *dev_priv = dev->dev_private;
729
	drm_i915_hws_addr_t *hws = data;
730 731 732

	if (!I915_NEED_GFX_HWS(dev))
		return -EINVAL;
733 734

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

739 740 741
	printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr);

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

743
	dev_priv->hws_map.offset = dev->agp->base + hws->addr;
744 745 746 747 748 749 750 751 752 753 754
	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 已提交
755
		return -ENOMEM;
756 757 758 759
	}
	dev_priv->hw_status_page = dev_priv->hws_map.handle;

	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
760 761
	I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
	DRM_DEBUG("load hws HWS_PGA with gfx mem 0x%x\n",
762 763 764 765 766
			dev_priv->status_gfx_addr);
	DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
	return 0;
}

767
int i915_driver_load(struct drm_device *dev, unsigned long flags)
768
{
J
Jesse Barnes 已提交
769 770 771 772
	struct drm_i915_private *dev_priv = dev->dev_private;
	unsigned long base, size;
	int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;

773 774 775 776 777 778 779
	/* 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 已提交
780 781 782 783 784 785 786 787 788 789 790 791
	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;

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

792 793
	ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
			 _DRM_KERNEL | _DRM_DRIVER,
J
Jesse Barnes 已提交
794
			 &dev_priv->mmio_map);
795

796 797 798 799 800 801
	/* Init HWS */
	if (!I915_NEED_GFX_HWS(dev)) {
		ret = i915_init_phys_hws(dev);
		if (ret != 0)
			return ret;
	}
802 803 804 805 806 807 808 809 810

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

814 815
	intel_opregion_init(dev);

816 817
	spin_lock_init(&dev_priv->user_irq_lock);

J
Jesse Barnes 已提交
818 819 820 821 822 823 824
	return ret;
}

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

825 826 827
	if (dev->pdev->msi_enabled)
		pci_disable_msi(dev->pdev);

828 829
	i915_free_hws(dev);

J
Jesse Barnes 已提交
830 831 832
	if (dev_priv->mmio_map)
		drm_rmmap(dev, dev_priv->mmio_map);

833 834
	intel_opregion_free(dev);

J
Jesse Barnes 已提交
835 836 837
	drm_free(dev->dev_private, sizeof(drm_i915_private_t),
		 DRM_MEM_DRIVER);

838 839 840
	return 0;
}

841
void i915_driver_lastclose(struct drm_device * dev)
L
Linus Torvalds 已提交
842
{
J
Jesse Barnes 已提交
843 844
	drm_i915_private_t *dev_priv = dev->dev_private;

D
Dave Airlie 已提交
845 846 847
	if (!dev_priv)
		return;

J
Jesse Barnes 已提交
848
	if (dev_priv->agp_heap)
D
Dave Airlie 已提交
849
		i915_mem_takedown(&(dev_priv->agp_heap));
J
Jesse Barnes 已提交
850

D
Dave Airlie 已提交
851
	i915_dma_cleanup(dev);
L
Linus Torvalds 已提交
852 853
}

854
void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
L
Linus Torvalds 已提交
855
{
J
Jesse Barnes 已提交
856 857
	drm_i915_private_t *dev_priv = dev->dev_private;
	i915_mem_release(dev, file_priv, dev_priv->agp_heap);
L
Linus Torvalds 已提交
858 859
}

860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
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),
D
Dave Airlie 已提交
878 879 880
};

int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
881 882 883 884 885 886 887 888 889 890 891 892

/**
 * 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.
 */
893
int i915_driver_device_is_agp(struct drm_device * dev)
894 895 896
{
	return 1;
}