i830_dma.c 38.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
 * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
 *
 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
 * All Rights Reserved.
 *
 * 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, sublicense,
 * 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:
D
Dave Airlie 已提交
14
 *
L
Linus Torvalds 已提交
15 16 17
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
D
Dave Airlie 已提交
18
 *
L
Linus Torvalds 已提交
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
 * PRECISION INSIGHT 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.
 *
 * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
 *	    Jeff Hartmann <jhartmann@valinux.com>
 *	    Keith Whitwell <keith@tungstengraphics.com>
 *	    Abraham vd Merwe <abraham@2d3d.co.za>
 *
 */

#include "drmP.h"
#include "drm.h"
#include "i830_drm.h"
#include "i830_drv.h"
#include <linux/interrupt.h>	/* For task queue support */
39
#include <linux/pagemap.h>
L
Linus Torvalds 已提交
40 41 42 43 44
#include <linux/delay.h>
#include <asm/uaccess.h>

#define I830_BUF_FREE		2
#define I830_BUF_CLIENT		1
D
Dave Airlie 已提交
45
#define I830_BUF_HARDWARE	0
L
Linus Torvalds 已提交
46 47 48 49

#define I830_BUF_UNMAPPED 0
#define I830_BUF_MAPPED   1

D
Dave Airlie 已提交
50
static struct drm_buf *i830_freelist_get(struct drm_device * dev)
L
Linus Torvalds 已提交
51
{
52
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
53 54 55
	int i;
	int used;

L
Linus Torvalds 已提交
56 57
	/* Linear search might not be the best solution */

D
Dave Airlie 已提交
58
	for (i = 0; i < dma->buf_count; i++) {
D
Dave Airlie 已提交
59
		struct drm_buf *buf = dma->buflist[i];
D
Dave Airlie 已提交
60
		drm_i830_buf_priv_t *buf_priv = buf->dev_private;
L
Linus Torvalds 已提交
61
		/* In use is already a pointer */
D
Dave Airlie 已提交
62
		used = cmpxchg(buf_priv->in_use, I830_BUF_FREE,
L
Linus Torvalds 已提交
63
			       I830_BUF_CLIENT);
D
Dave Airlie 已提交
64
		if (used == I830_BUF_FREE) {
L
Linus Torvalds 已提交
65 66 67
			return buf;
		}
	}
D
Dave Airlie 已提交
68
	return NULL;
L
Linus Torvalds 已提交
69 70 71 72 73 74
}

/* This should only be called if the buffer is not sent to the hardware
 * yet, the hardware updates in use for us once its on the ring buffer.
 */

D
Dave Airlie 已提交
75
static int i830_freelist_put(struct drm_device * dev, struct drm_buf * buf)
L
Linus Torvalds 已提交
76
{
D
Dave Airlie 已提交
77 78 79 80 81 82 83 84
	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
	int used;

	/* In use is already a pointer */
	used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE);
	if (used != I830_BUF_CLIENT) {
		DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
		return -EINVAL;
L
Linus Torvalds 已提交
85
	}
D
Dave Airlie 已提交
86 87

	return 0;
L
Linus Torvalds 已提交
88 89
}

D
Dave Airlie 已提交
90
static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
L
Linus Torvalds 已提交
91
{
92 93
	struct drm_file *priv = filp->private_data;
	struct drm_device *dev;
D
Dave Airlie 已提交
94
	drm_i830_private_t *dev_priv;
D
Dave Airlie 已提交
95
	struct drm_buf *buf;
L
Linus Torvalds 已提交
96 97 98
	drm_i830_buf_priv_t *buf_priv;

	lock_kernel();
99
	dev = priv->minor->dev;
L
Linus Torvalds 已提交
100
	dev_priv = dev->dev_private;
D
Dave Airlie 已提交
101
	buf = dev_priv->mmap_buffer;
L
Linus Torvalds 已提交
102
	buf_priv = buf->dev_private;
D
Dave Airlie 已提交
103

L
Linus Torvalds 已提交
104 105
	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
	vma->vm_file = filp;
D
Dave Airlie 已提交
106 107

	buf_priv->currently_mapped = I830_BUF_MAPPED;
L
Linus Torvalds 已提交
108 109 110
	unlock_kernel();

	if (io_remap_pfn_range(vma, vma->vm_start,
111
			       vma->vm_pgoff,
D
Dave Airlie 已提交
112 113
			       vma->vm_end - vma->vm_start, vma->vm_page_prot))
		return -EAGAIN;
L
Linus Torvalds 已提交
114 115 116
	return 0;
}

117
static const struct file_operations i830_buffer_fops = {
D
Dave Airlie 已提交
118
	.open = drm_open,
D
Dave Airlie 已提交
119
	.release = drm_release,
D
Dave Airlie 已提交
120 121 122
	.ioctl = drm_ioctl,
	.mmap = i830_mmap_buffers,
	.fasync = drm_fasync,
D
Dave Airlie 已提交
123 124
};

125
static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv)
L
Linus Torvalds 已提交
126
{
127
	struct drm_device *dev = file_priv->minor->dev;
L
Linus Torvalds 已提交
128
	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
D
Dave Airlie 已提交
129
	drm_i830_private_t *dev_priv = dev->dev_private;
130
	const struct file_operations *old_fops;
L
Linus Torvalds 已提交
131 132 133
	unsigned long virtual;
	int retcode = 0;

D
Dave Airlie 已提交
134 135
	if (buf_priv->currently_mapped == I830_BUF_MAPPED)
		return -EINVAL;
L
Linus Torvalds 已提交
136

D
Dave Airlie 已提交
137
	down_write(&current->mm->mmap_sem);
138 139
	old_fops = file_priv->filp->f_op;
	file_priv->filp->f_op = &i830_buffer_fops;
L
Linus Torvalds 已提交
140
	dev_priv->mmap_buffer = buf;
141
	virtual = do_mmap(file_priv->filp, 0, buf->total, PROT_READ | PROT_WRITE,
D
Dave Airlie 已提交
142
			  MAP_SHARED, buf->bus_address);
L
Linus Torvalds 已提交
143
	dev_priv->mmap_buffer = NULL;
144
	file_priv->filp->f_op = old_fops;
D
Dave Airlie 已提交
145
	if (IS_ERR((void *)virtual)) {	/* ugh */
L
Linus Torvalds 已提交
146 147
		/* Real error */
		DRM_ERROR("mmap error\n");
148
		retcode = PTR_ERR((void *)virtual);
L
Linus Torvalds 已提交
149 150 151 152
		buf_priv->virtual = NULL;
	} else {
		buf_priv->virtual = (void __user *)virtual;
	}
D
Dave Airlie 已提交
153
	up_write(&current->mm->mmap_sem);
L
Linus Torvalds 已提交
154 155 156 157

	return retcode;
}

D
Dave Airlie 已提交
158
static int i830_unmap_buffer(struct drm_buf * buf)
L
Linus Torvalds 已提交
159 160 161 162
{
	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
	int retcode = 0;

D
Dave Airlie 已提交
163
	if (buf_priv->currently_mapped != I830_BUF_MAPPED)
L
Linus Torvalds 已提交
164 165 166 167 168 169 170 171
		return -EINVAL;

	down_write(&current->mm->mmap_sem);
	retcode = do_munmap(current->mm,
			    (unsigned long)buf_priv->virtual,
			    (size_t) buf->total);
	up_write(&current->mm->mmap_sem);

D
Dave Airlie 已提交
172 173
	buf_priv->currently_mapped = I830_BUF_UNMAPPED;
	buf_priv->virtual = NULL;
L
Linus Torvalds 已提交
174 175 176 177

	return retcode;
}

178
static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
179
			       struct drm_file *file_priv)
L
Linus Torvalds 已提交
180
{
D
Dave Airlie 已提交
181
	struct drm_buf *buf;
L
Linus Torvalds 已提交
182 183 184 185 186 187
	drm_i830_buf_priv_t *buf_priv;
	int retcode = 0;

	buf = i830_freelist_get(dev);
	if (!buf) {
		retcode = -ENOMEM;
D
Dave Airlie 已提交
188
		DRM_DEBUG("retcode=%d\n", retcode);
L
Linus Torvalds 已提交
189 190
		return retcode;
	}
D
Dave Airlie 已提交
191

192
	retcode = i830_map_buffer(buf, file_priv);
D
Dave Airlie 已提交
193
	if (retcode) {
L
Linus Torvalds 已提交
194
		i830_freelist_put(dev, buf);
D
Dave Airlie 已提交
195
		DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
L
Linus Torvalds 已提交
196 197
		return retcode;
	}
198
	buf->file_priv = file_priv;
D
Dave Airlie 已提交
199
	buf_priv = buf->dev_private;
L
Linus Torvalds 已提交
200
	d->granted = 1;
D
Dave Airlie 已提交
201 202 203
	d->request_idx = buf->idx;
	d->request_size = buf->total;
	d->virtual = buf_priv->virtual;
L
Linus Torvalds 已提交
204 205 206 207

	return retcode;
}

208
static int i830_dma_cleanup(struct drm_device * dev)
L
Linus Torvalds 已提交
209
{
210
	struct drm_device_dma *dma = dev->dma;
L
Linus Torvalds 已提交
211 212 213 214 215

	/* 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.
	 */
D
Dave Airlie 已提交
216 217
	if (dev->irq_enabled)
		drm_irq_uninstall(dev);
L
Linus Torvalds 已提交
218 219 220

	if (dev->dev_private) {
		int i;
D
Dave Airlie 已提交
221 222 223 224
		drm_i830_private_t *dev_priv =
		    (drm_i830_private_t *) dev->dev_private;

		if (dev_priv->ring.virtual_start) {
225
			drm_core_ioremapfree(&dev_priv->ring.map, dev);
L
Linus Torvalds 已提交
226
		}
D
Dave Airlie 已提交
227
		if (dev_priv->hw_status_page) {
L
Linus Torvalds 已提交
228 229 230
			pci_free_consistent(dev->pdev, PAGE_SIZE,
					    dev_priv->hw_status_page,
					    dev_priv->dma_status_page);
D
Dave Airlie 已提交
231 232
			/* Need to rewrite hardware status page */
			I830_WRITE(0x02080, 0x1ffff000);
L
Linus Torvalds 已提交
233 234
		}

D
Dave Airlie 已提交
235
		drm_free(dev->dev_private, sizeof(drm_i830_private_t),
L
Linus Torvalds 已提交
236
			 DRM_MEM_DRIVER);
D
Dave Airlie 已提交
237
		dev->dev_private = NULL;
L
Linus Torvalds 已提交
238 239

		for (i = 0; i < dma->buf_count; i++) {
D
Dave Airlie 已提交
240
			struct drm_buf *buf = dma->buflist[i];
L
Linus Torvalds 已提交
241
			drm_i830_buf_priv_t *buf_priv = buf->dev_private;
D
Dave Airlie 已提交
242
			if (buf_priv->kernel_virtual && buf->total)
243
				drm_core_ioremapfree(&buf_priv->map, dev);
L
Linus Torvalds 已提交
244 245
		}
	}
D
Dave Airlie 已提交
246
	return 0;
L
Linus Torvalds 已提交
247 248
}

249
int i830_wait_ring(struct drm_device * dev, int n, const char *caller)
L
Linus Torvalds 已提交
250
{
D
Dave Airlie 已提交
251 252 253 254
	drm_i830_private_t *dev_priv = dev->dev_private;
	drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
	int iters = 0;
	unsigned long end;
L
Linus Torvalds 已提交
255 256
	unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;

D
Dave Airlie 已提交
257 258 259 260 261 262 263
	end = jiffies + (HZ * 3);
	while (ring->space < n) {
		ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
		ring->space = ring->head - (ring->tail + 8);
		if (ring->space < 0)
			ring->space += ring->Size;

L
Linus Torvalds 已提交
264
		if (ring->head != last_head) {
D
Dave Airlie 已提交
265
			end = jiffies + (HZ * 3);
L
Linus Torvalds 已提交
266 267
			last_head = ring->head;
		}
D
Dave Airlie 已提交
268 269 270 271 272 273

		iters++;
		if (time_before(end, jiffies)) {
			DRM_ERROR("space: %d wanted %d\n", ring->space, n);
			DRM_ERROR("lockup\n");
			goto out_wait_ring;
L
Linus Torvalds 已提交
274 275 276 277 278
		}
		udelay(1);
		dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
	}

D
Dave Airlie 已提交
279 280
      out_wait_ring:
	return iters;
L
Linus Torvalds 已提交
281 282
}

283
static void i830_kernel_lost_context(struct drm_device * dev)
L
Linus Torvalds 已提交
284
{
D
Dave Airlie 已提交
285 286 287 288 289 290 291 292
	drm_i830_private_t *dev_priv = dev->dev_private;
	drm_i830_ring_buffer_t *ring = &(dev_priv->ring);

	ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
	ring->tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
	ring->space = ring->head - (ring->tail + 8);
	if (ring->space < 0)
		ring->space += ring->Size;
L
Linus Torvalds 已提交
293 294 295 296 297

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

298
static int i830_freelist_init(struct drm_device * dev, drm_i830_private_t * dev_priv)
L
Linus Torvalds 已提交
299
{
300
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
301 302 303 304 305 306 307
	int my_idx = 36;
	u32 *hw_status = (u32 *) (dev_priv->hw_status_page + my_idx);
	int i;

	if (dma->buf_count > 1019) {
		/* Not enough space in the status page for the freelist */
		return -EINVAL;
L
Linus Torvalds 已提交
308 309
	}

D
Dave Airlie 已提交
310
	for (i = 0; i < dma->buf_count; i++) {
D
Dave Airlie 已提交
311
		struct drm_buf *buf = dma->buflist[i];
D
Dave Airlie 已提交
312
		drm_i830_buf_priv_t *buf_priv = buf->dev_private;
L
Linus Torvalds 已提交
313

D
Dave Airlie 已提交
314 315 316
		buf_priv->in_use = hw_status++;
		buf_priv->my_use_idx = my_idx;
		my_idx += 4;
L
Linus Torvalds 已提交
317

D
Dave Airlie 已提交
318
		*buf_priv->in_use = I830_BUF_FREE;
L
Linus Torvalds 已提交
319

320 321 322 323 324 325 326 327
		buf_priv->map.offset = buf->bus_address;
		buf_priv->map.size = buf->total;
		buf_priv->map.type = _DRM_AGP;
		buf_priv->map.flags = 0;
		buf_priv->map.mtrr = 0;

		drm_core_ioremap(&buf_priv->map, dev);
		buf_priv->kernel_virtual = buf_priv->map.handle;
L
Linus Torvalds 已提交
328 329 330 331
	}
	return 0;
}

332
static int i830_dma_initialize(struct drm_device * dev,
D
Dave Airlie 已提交
333 334
			       drm_i830_private_t * dev_priv,
			       drm_i830_init_t * init)
L
Linus Torvalds 已提交
335
{
D
Dave Airlie 已提交
336
	struct drm_map_list *r_list;
L
Linus Torvalds 已提交
337

D
Dave Airlie 已提交
338
	memset(dev_priv, 0, sizeof(drm_i830_private_t));
L
Linus Torvalds 已提交
339

340
	list_for_each_entry(r_list, &dev->maplist, head) {
D
Dave Airlie 已提交
341
		if (r_list->map &&
L
Linus Torvalds 已提交
342
		    r_list->map->type == _DRM_SHM &&
D
Dave Airlie 已提交
343
		    r_list->map->flags & _DRM_CONTAINS_LOCK) {
L
Linus Torvalds 已提交
344
			dev_priv->sarea_map = r_list->map;
D
Dave Airlie 已提交
345 346 347
			break;
		}
	}
L
Linus Torvalds 已提交
348

D
Dave Airlie 已提交
349
	if (!dev_priv->sarea_map) {
L
Linus Torvalds 已提交
350 351 352 353 354 355
		dev->dev_private = (void *)dev_priv;
		i830_dma_cleanup(dev);
		DRM_ERROR("can not find sarea!\n");
		return -EINVAL;
	}
	dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
D
Dave Airlie 已提交
356
	if (!dev_priv->mmio_map) {
L
Linus Torvalds 已提交
357 358 359 360 361
		dev->dev_private = (void *)dev_priv;
		i830_dma_cleanup(dev);
		DRM_ERROR("can not find mmio map!\n");
		return -EINVAL;
	}
362
	dev->agp_buffer_token = init->buffers_offset;
L
Linus Torvalds 已提交
363
	dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
D
Dave Airlie 已提交
364
	if (!dev->agp_buffer_map) {
L
Linus Torvalds 已提交
365 366 367 368 369 370 371
		dev->dev_private = (void *)dev_priv;
		i830_dma_cleanup(dev);
		DRM_ERROR("can not find dma buffer map!\n");
		return -EINVAL;
	}

	dev_priv->sarea_priv = (drm_i830_sarea_t *)
D
Dave Airlie 已提交
372
	    ((u8 *) dev_priv->sarea_map->handle + init->sarea_priv_offset);
L
Linus Torvalds 已提交
373

D
Dave Airlie 已提交
374 375 376
	dev_priv->ring.Start = init->ring_start;
	dev_priv->ring.End = init->ring_end;
	dev_priv->ring.Size = init->ring_size;
L
Linus Torvalds 已提交
377

378 379 380 381 382 383 384
	dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
	dev_priv->ring.map.size = init->ring_size;
	dev_priv->ring.map.type = _DRM_AGP;
	dev_priv->ring.map.flags = 0;
	dev_priv->ring.map.mtrr = 0;

	drm_core_ioremap(&dev_priv->ring.map, dev);
L
Linus Torvalds 已提交
385

386
	if (dev_priv->ring.map.handle == NULL) {
D
Dave Airlie 已提交
387 388 389
		dev->dev_private = (void *)dev_priv;
		i830_dma_cleanup(dev);
		DRM_ERROR("can not ioremap virtual address for"
L
Linus Torvalds 已提交
390
			  " ring buffer\n");
E
Eric Anholt 已提交
391
		return -ENOMEM;
L
Linus Torvalds 已提交
392 393
	}

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

D
Dave Airlie 已提交
396 397
	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;

L
Linus Torvalds 已提交
398 399 400 401 402 403 404 405 406 407 408
	dev_priv->w = init->w;
	dev_priv->h = init->h;
	dev_priv->pitch = init->pitch;
	dev_priv->back_offset = init->back_offset;
	dev_priv->depth_offset = init->depth_offset;
	dev_priv->front_offset = init->front_offset;

	dev_priv->front_di1 = init->front_offset | init->pitch_bits;
	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
	dev_priv->zi1 = init->depth_offset | init->pitch_bits;

D
Dave Airlie 已提交
409
	DRM_DEBUG("front_di1 %x\n", dev_priv->front_di1);
L
Linus Torvalds 已提交
410
	DRM_DEBUG("back_offset %x\n", dev_priv->back_offset);
D
Dave Airlie 已提交
411 412
	DRM_DEBUG("back_di1 %x\n", dev_priv->back_di1);
	DRM_DEBUG("pitch_bits %x\n", init->pitch_bits);
L
Linus Torvalds 已提交
413 414 415 416 417 418 419 420 421 422 423

	dev_priv->cpp = init->cpp;
	/* We are using separate values as placeholders for mechanisms for
	 * private backbuffer/depthbuffer usage.
	 */

	dev_priv->back_pitch = init->back_pitch;
	dev_priv->depth_pitch = init->depth_pitch;
	dev_priv->do_boxes = 0;
	dev_priv->use_mi_batchbuffer_start = 0;

D
Dave Airlie 已提交
424 425 426 427 428
	/* Program Hardware Status Page */
	dev_priv->hw_status_page =
	    pci_alloc_consistent(dev->pdev, PAGE_SIZE,
				 &dev_priv->dma_status_page);
	if (!dev_priv->hw_status_page) {
L
Linus Torvalds 已提交
429 430 431 432 433
		dev->dev_private = (void *)dev_priv;
		i830_dma_cleanup(dev);
		DRM_ERROR("Can not allocate hardware status page\n");
		return -ENOMEM;
	}
D
Dave Airlie 已提交
434
	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
L
Linus Torvalds 已提交
435
	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
D
Dave Airlie 已提交
436 437

	I830_WRITE(0x02080, dev_priv->dma_status_page);
L
Linus Torvalds 已提交
438
	DRM_DEBUG("Enabled hardware status page\n");
D
Dave Airlie 已提交
439 440 441

	/* Now we need to init our freelist */
	if (i830_freelist_init(dev, dev_priv) != 0) {
L
Linus Torvalds 已提交
442
		dev->dev_private = (void *)dev_priv;
D
Dave Airlie 已提交
443 444
		i830_dma_cleanup(dev);
		DRM_ERROR("Not enough space in the status page for"
L
Linus Torvalds 已提交
445
			  " the freelist\n");
D
Dave Airlie 已提交
446
		return -ENOMEM;
L
Linus Torvalds 已提交
447 448 449
	}
	dev->dev_private = (void *)dev_priv;

D
Dave Airlie 已提交
450
	return 0;
L
Linus Torvalds 已提交
451 452
}

453 454
static int i830_dma_init(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
455
{
D
Dave Airlie 已提交
456
	drm_i830_private_t *dev_priv;
457
	drm_i830_init_t *init = data;
D
Dave Airlie 已提交
458 459
	int retcode = 0;

460
	switch (init->func) {
D
Dave Airlie 已提交
461 462 463 464 465
	case I830_INIT_DMA:
		dev_priv = drm_alloc(sizeof(drm_i830_private_t),
				     DRM_MEM_DRIVER);
		if (dev_priv == NULL)
			return -ENOMEM;
466
		retcode = i830_dma_initialize(dev, dev_priv, init);
D
Dave Airlie 已提交
467 468 469 470 471 472 473
		break;
	case I830_CLEANUP_DMA:
		retcode = i830_dma_cleanup(dev);
		break;
	default:
		retcode = -EINVAL;
		break;
L
Linus Torvalds 已提交
474
	}
D
Dave Airlie 已提交
475 476

	return retcode;
L
Linus Torvalds 已提交
477 478 479 480 481 482 483 484 485
}

#define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
#define ST1_ENABLE               (1<<16)
#define ST1_MASK                 (0xffff)

/* Most efficient way to verify state for the i830 is as it is
 * emitted.  Non-conformant state is silently dropped.
 */
486
static void i830EmitContextVerified(struct drm_device * dev, unsigned int *code)
L
Linus Torvalds 已提交
487
{
D
Dave Airlie 已提交
488
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
489 490 491 492
	int i, j = 0;
	unsigned int tmp;
	RING_LOCALS;

D
Dave Airlie 已提交
493
	BEGIN_LP_RING(I830_CTX_SETUP_SIZE + 4);
L
Linus Torvalds 已提交
494

D
Dave Airlie 已提交
495
	for (i = 0; i < I830_CTXREG_BLENDCOLR0; i++) {
L
Linus Torvalds 已提交
496
		tmp = code[i];
D
Dave Airlie 已提交
497 498 499
		if ((tmp & (7 << 29)) == CMD_3D &&
		    (tmp & (0x1f << 24)) < (0x1d << 24)) {
			OUT_RING(tmp);
L
Linus Torvalds 已提交
500 501 502 503 504 505
			j++;
		} else {
			DRM_ERROR("Skipping %d\n", i);
		}
	}

D
Dave Airlie 已提交
506 507
	OUT_RING(STATE3D_CONST_BLEND_COLOR_CMD);
	OUT_RING(code[I830_CTXREG_BLENDCOLR]);
L
Linus Torvalds 已提交
508 509
	j += 2;

D
Dave Airlie 已提交
510
	for (i = I830_CTXREG_VF; i < I830_CTXREG_MCSB0; i++) {
L
Linus Torvalds 已提交
511
		tmp = code[i];
D
Dave Airlie 已提交
512 513 514
		if ((tmp & (7 << 29)) == CMD_3D &&
		    (tmp & (0x1f << 24)) < (0x1d << 24)) {
			OUT_RING(tmp);
L
Linus Torvalds 已提交
515 516 517 518 519 520
			j++;
		} else {
			DRM_ERROR("Skipping %d\n", i);
		}
	}

D
Dave Airlie 已提交
521 522
	OUT_RING(STATE3D_MAP_COORD_SETBIND_CMD);
	OUT_RING(code[I830_CTXREG_MCSB1]);
L
Linus Torvalds 已提交
523 524
	j += 2;

D
Dave Airlie 已提交
525 526
	if (j & 1)
		OUT_RING(0);
L
Linus Torvalds 已提交
527 528 529 530

	ADVANCE_LP_RING();
}

531
static void i830EmitTexVerified(struct drm_device * dev, unsigned int *code)
L
Linus Torvalds 已提交
532
{
D
Dave Airlie 已提交
533
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
534 535 536 537 538
	int i, j = 0;
	unsigned int tmp;
	RING_LOCALS;

	if (code[I830_TEXREG_MI0] == GFX_OP_MAP_INFO ||
D
Dave Airlie 已提交
539 540 541 542 543 544 545 546 547 548 549 550 551
	    (code[I830_TEXREG_MI0] & ~(0xf * LOAD_TEXTURE_MAP0)) ==
	    (STATE3D_LOAD_STATE_IMMEDIATE_2 | 4)) {

		BEGIN_LP_RING(I830_TEX_SETUP_SIZE);

		OUT_RING(code[I830_TEXREG_MI0]);	/* TM0LI */
		OUT_RING(code[I830_TEXREG_MI1]);	/* TM0S0 */
		OUT_RING(code[I830_TEXREG_MI2]);	/* TM0S1 */
		OUT_RING(code[I830_TEXREG_MI3]);	/* TM0S2 */
		OUT_RING(code[I830_TEXREG_MI4]);	/* TM0S3 */
		OUT_RING(code[I830_TEXREG_MI5]);	/* TM0S4 */

		for (i = 6; i < I830_TEX_SETUP_SIZE; i++) {
L
Linus Torvalds 已提交
552
			tmp = code[i];
D
Dave Airlie 已提交
553
			OUT_RING(tmp);
L
Linus Torvalds 已提交
554
			j++;
D
Dave Airlie 已提交
555
		}
L
Linus Torvalds 已提交
556

D
Dave Airlie 已提交
557 558
		if (j & 1)
			OUT_RING(0);
L
Linus Torvalds 已提交
559 560

		ADVANCE_LP_RING();
D
Dave Airlie 已提交
561
	} else
L
Linus Torvalds 已提交
562 563 564
		printk("rejected packet %x\n", code[0]);
}

565
static void i830EmitTexBlendVerified(struct drm_device * dev,
D
Dave Airlie 已提交
566
				     unsigned int *code, unsigned int num)
L
Linus Torvalds 已提交
567
{
D
Dave Airlie 已提交
568
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
569 570 571 572 573 574 575
	int i, j = 0;
	unsigned int tmp;
	RING_LOCALS;

	if (!num)
		return;

D
Dave Airlie 已提交
576
	BEGIN_LP_RING(num + 1);
L
Linus Torvalds 已提交
577

D
Dave Airlie 已提交
578
	for (i = 0; i < num; i++) {
L
Linus Torvalds 已提交
579
		tmp = code[i];
D
Dave Airlie 已提交
580
		OUT_RING(tmp);
L
Linus Torvalds 已提交
581 582 583
		j++;
	}

D
Dave Airlie 已提交
584 585
	if (j & 1)
		OUT_RING(0);
L
Linus Torvalds 已提交
586 587 588 589

	ADVANCE_LP_RING();
}

590
static void i830EmitTexPalette(struct drm_device * dev,
D
Dave Airlie 已提交
591
			       unsigned int *palette, int number, int is_shared)
L
Linus Torvalds 已提交
592
{
D
Dave Airlie 已提交
593
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
594 595 596 597 598
	int i;
	RING_LOCALS;

	return;

D
Dave Airlie 已提交
599
	BEGIN_LP_RING(258);
L
Linus Torvalds 已提交
600

D
Dave Airlie 已提交
601
	if (is_shared == 1) {
L
Linus Torvalds 已提交
602
		OUT_RING(CMD_OP_MAP_PALETTE_LOAD |
D
Dave Airlie 已提交
603
			 MAP_PALETTE_NUM(0) | MAP_PALETTE_BOTH);
L
Linus Torvalds 已提交
604 605 606
	} else {
		OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number));
	}
D
Dave Airlie 已提交
607
	for (i = 0; i < 256; i++) {
L
Linus Torvalds 已提交
608 609 610
		OUT_RING(palette[i]);
	}
	OUT_RING(0);
D
Dave Airlie 已提交
611
	/* KW:  WHERE IS THE ADVANCE_LP_RING?  This is effectively a noop!
L
Linus Torvalds 已提交
612 613 614 615 616
	 */
}

/* Need to do some additional checking when setting the dest buffer.
 */
617
static void i830EmitDestVerified(struct drm_device * dev, unsigned int *code)
D
Dave Airlie 已提交
618 619
{
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
620 621 622
	unsigned int tmp;
	RING_LOCALS;

D
Dave Airlie 已提交
623
	BEGIN_LP_RING(I830_DEST_SETUP_SIZE + 10);
L
Linus Torvalds 已提交
624 625 626 627 628 629 630 631

	tmp = code[I830_DESTREG_CBUFADDR];
	if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
		if (((int)outring) & 8) {
			OUT_RING(0);
			OUT_RING(0);
		}

D
Dave Airlie 已提交
632 633 634 635 636 637 638 639 640 641 642 643
		OUT_RING(CMD_OP_DESTBUFFER_INFO);
		OUT_RING(BUF_3D_ID_COLOR_BACK |
			 BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) |
			 BUF_3D_USE_FENCE);
		OUT_RING(tmp);
		OUT_RING(0);

		OUT_RING(CMD_OP_DESTBUFFER_INFO);
		OUT_RING(BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE |
			 BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
		OUT_RING(dev_priv->zi1);
		OUT_RING(0);
L
Linus Torvalds 已提交
644 645 646 647 648 649 650 651
	} else {
		DRM_ERROR("bad di1 %x (allow %x or %x)\n",
			  tmp, dev_priv->front_di1, dev_priv->back_di1);
	}

	/* invarient:
	 */

D
Dave Airlie 已提交
652 653
	OUT_RING(GFX_OP_DESTBUFFER_VARS);
	OUT_RING(code[I830_DESTREG_DV1]);
L
Linus Torvalds 已提交
654

D
Dave Airlie 已提交
655 656 657 658 659
	OUT_RING(GFX_OP_DRAWRECT_INFO);
	OUT_RING(code[I830_DESTREG_DR1]);
	OUT_RING(code[I830_DESTREG_DR2]);
	OUT_RING(code[I830_DESTREG_DR3]);
	OUT_RING(code[I830_DESTREG_DR4]);
L
Linus Torvalds 已提交
660 661 662

	/* Need to verify this */
	tmp = code[I830_DESTREG_SENABLE];
D
Dave Airlie 已提交
663 664
	if ((tmp & ~0x3) == GFX_OP_SCISSOR_ENABLE) {
		OUT_RING(tmp);
L
Linus Torvalds 已提交
665 666
	} else {
		DRM_ERROR("bad scissor enable\n");
D
Dave Airlie 已提交
667
		OUT_RING(0);
L
Linus Torvalds 已提交
668 669
	}

D
Dave Airlie 已提交
670 671 672 673
	OUT_RING(GFX_OP_SCISSOR_RECT);
	OUT_RING(code[I830_DESTREG_SR1]);
	OUT_RING(code[I830_DESTREG_SR2]);
	OUT_RING(0);
L
Linus Torvalds 已提交
674 675 676 677

	ADVANCE_LP_RING();
}

678
static void i830EmitStippleVerified(struct drm_device * dev, unsigned int *code)
L
Linus Torvalds 已提交
679
{
D
Dave Airlie 已提交
680
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
681 682
	RING_LOCALS;

D
Dave Airlie 已提交
683 684 685 686
	BEGIN_LP_RING(2);
	OUT_RING(GFX_OP_STIPPLE);
	OUT_RING(code[1]);
	ADVANCE_LP_RING();
L
Linus Torvalds 已提交
687 688
}

689
static void i830EmitState(struct drm_device * dev)
L
Linus Torvalds 已提交
690
{
D
Dave Airlie 已提交
691 692
	drm_i830_private_t *dev_priv = dev->dev_private;
	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
L
Linus Torvalds 已提交
693 694
	unsigned int dirty = sarea_priv->dirty;

695
	DRM_DEBUG("%s %x\n", __func__, dirty);
L
Linus Torvalds 已提交
696 697

	if (dirty & I830_UPLOAD_BUFFERS) {
D
Dave Airlie 已提交
698
		i830EmitDestVerified(dev, sarea_priv->BufferState);
L
Linus Torvalds 已提交
699 700 701 702
		sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS;
	}

	if (dirty & I830_UPLOAD_CTX) {
D
Dave Airlie 已提交
703
		i830EmitContextVerified(dev, sarea_priv->ContextState);
L
Linus Torvalds 已提交
704 705 706 707
		sarea_priv->dirty &= ~I830_UPLOAD_CTX;
	}

	if (dirty & I830_UPLOAD_TEX0) {
D
Dave Airlie 已提交
708
		i830EmitTexVerified(dev, sarea_priv->TexState[0]);
L
Linus Torvalds 已提交
709 710 711 712
		sarea_priv->dirty &= ~I830_UPLOAD_TEX0;
	}

	if (dirty & I830_UPLOAD_TEX1) {
D
Dave Airlie 已提交
713
		i830EmitTexVerified(dev, sarea_priv->TexState[1]);
L
Linus Torvalds 已提交
714 715 716 717
		sarea_priv->dirty &= ~I830_UPLOAD_TEX1;
	}

	if (dirty & I830_UPLOAD_TEXBLEND0) {
D
Dave Airlie 已提交
718 719
		i830EmitTexBlendVerified(dev, sarea_priv->TexBlendState[0],
					 sarea_priv->TexBlendStateWordsUsed[0]);
L
Linus Torvalds 已提交
720 721 722 723
		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND0;
	}

	if (dirty & I830_UPLOAD_TEXBLEND1) {
D
Dave Airlie 已提交
724 725
		i830EmitTexBlendVerified(dev, sarea_priv->TexBlendState[1],
					 sarea_priv->TexBlendStateWordsUsed[1]);
L
Linus Torvalds 已提交
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND1;
	}

	if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) {
		i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
	} else {
		if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
			i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
		}
		if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
			i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
		}

		/* 1.3:
		 */
#if 0
		if (dirty & I830_UPLOAD_TEX_PALETTE_N(2)) {
			i830EmitTexPalette(dev, sarea_priv->Palette2[0], 0, 0);
			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
		}
		if (dirty & I830_UPLOAD_TEX_PALETTE_N(3)) {
			i830EmitTexPalette(dev, sarea_priv->Palette2[1], 1, 0);
			sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
		}
#endif
	}

	/* 1.3:
	 */
	if (dirty & I830_UPLOAD_STIPPLE) {
D
Dave Airlie 已提交
758
		i830EmitStippleVerified(dev, sarea_priv->StippleState);
L
Linus Torvalds 已提交
759 760 761 762
		sarea_priv->dirty &= ~I830_UPLOAD_STIPPLE;
	}

	if (dirty & I830_UPLOAD_TEX2) {
D
Dave Airlie 已提交
763
		i830EmitTexVerified(dev, sarea_priv->TexState2);
L
Linus Torvalds 已提交
764 765 766 767
		sarea_priv->dirty &= ~I830_UPLOAD_TEX2;
	}

	if (dirty & I830_UPLOAD_TEX3) {
D
Dave Airlie 已提交
768
		i830EmitTexVerified(dev, sarea_priv->TexState3);
L
Linus Torvalds 已提交
769 770 771 772
		sarea_priv->dirty &= ~I830_UPLOAD_TEX3;
	}

	if (dirty & I830_UPLOAD_TEXBLEND2) {
D
Dave Airlie 已提交
773 774 775
		i830EmitTexBlendVerified(dev,
					 sarea_priv->TexBlendState2,
					 sarea_priv->TexBlendStateWordsUsed2);
L
Linus Torvalds 已提交
776 777 778 779 780

		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND2;
	}

	if (dirty & I830_UPLOAD_TEXBLEND3) {
D
Dave Airlie 已提交
781 782 783
		i830EmitTexBlendVerified(dev,
					 sarea_priv->TexBlendState3,
					 sarea_priv->TexBlendStateWordsUsed3);
L
Linus Torvalds 已提交
784 785 786 787 788 789 790 791
		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND3;
	}
}

/* ================================================================
 * Performance monitoring functions
 */

792
static void i830_fill_box(struct drm_device * dev,
D
Dave Airlie 已提交
793
			  int x, int y, int w, int h, int r, int g, int b)
L
Linus Torvalds 已提交
794
{
D
Dave Airlie 已提交
795
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
796 797 798 799
	u32 color;
	unsigned int BR13, CMD;
	RING_LOCALS;

D
Dave Airlie 已提交
800
	BR13 = (0xF0 << 16) | (dev_priv->pitch * dev_priv->cpp) | (1 << 24);
L
Linus Torvalds 已提交
801 802 803 804 805
	CMD = XY_COLOR_BLT_CMD;
	x += dev_priv->sarea_priv->boxes[0].x1;
	y += dev_priv->sarea_priv->boxes[0].y1;

	if (dev_priv->cpp == 4) {
D
Dave Airlie 已提交
806
		BR13 |= (1 << 25);
L
Linus Torvalds 已提交
807
		CMD |= (XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
D
Dave Airlie 已提交
808
		color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
L
Linus Torvalds 已提交
809 810
	} else {
		color = (((r & 0xf8) << 8) |
D
Dave Airlie 已提交
811
			 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
L
Linus Torvalds 已提交
812 813
	}

D
Dave Airlie 已提交
814 815 816 817 818
	BEGIN_LP_RING(6);
	OUT_RING(CMD);
	OUT_RING(BR13);
	OUT_RING((y << 16) | x);
	OUT_RING(((y + h) << 16) | (x + w));
L
Linus Torvalds 已提交
819

D
Dave Airlie 已提交
820 821 822 823 824
	if (dev_priv->current_page == 1) {
		OUT_RING(dev_priv->front_offset);
	} else {
		OUT_RING(dev_priv->back_offset);
	}
L
Linus Torvalds 已提交
825

D
Dave Airlie 已提交
826
	OUT_RING(color);
L
Linus Torvalds 已提交
827 828 829
	ADVANCE_LP_RING();
}

830
static void i830_cp_performance_boxes(struct drm_device * dev)
L
Linus Torvalds 已提交
831
{
D
Dave Airlie 已提交
832
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
833 834 835

	/* Purple box for page flipping
	 */
D
Dave Airlie 已提交
836 837
	if (dev_priv->sarea_priv->perf_boxes & I830_BOX_FLIP)
		i830_fill_box(dev, 4, 4, 8, 8, 255, 0, 255);
L
Linus Torvalds 已提交
838 839 840

	/* Red box if we have to wait for idle at any point
	 */
D
Dave Airlie 已提交
841 842
	if (dev_priv->sarea_priv->perf_boxes & I830_BOX_WAIT)
		i830_fill_box(dev, 16, 4, 8, 8, 255, 0, 0);
L
Linus Torvalds 已提交
843 844 845

	/* Blue box: lost context?
	 */
D
Dave Airlie 已提交
846 847
	if (dev_priv->sarea_priv->perf_boxes & I830_BOX_LOST_CONTEXT)
		i830_fill_box(dev, 28, 4, 8, 8, 0, 0, 255);
L
Linus Torvalds 已提交
848 849 850

	/* Yellow box for texture swaps
	 */
D
Dave Airlie 已提交
851 852
	if (dev_priv->sarea_priv->perf_boxes & I830_BOX_TEXTURE_LOAD)
		i830_fill_box(dev, 40, 4, 8, 8, 255, 255, 0);
L
Linus Torvalds 已提交
853 854 855

	/* Green box if hardware never idles (as far as we can tell)
	 */
D
Dave Airlie 已提交
856 857
	if (!(dev_priv->sarea_priv->perf_boxes & I830_BOX_RING_EMPTY))
		i830_fill_box(dev, 64, 4, 8, 8, 0, 255, 0);
L
Linus Torvalds 已提交
858

D
Dave Airlie 已提交
859
	/* Draw bars indicating number of buffers allocated
L
Linus Torvalds 已提交
860 861 862 863
	 * (not a great measure, easily confused)
	 */
	if (dev_priv->dma_used) {
		int bar = dev_priv->dma_used / 10240;
D
Dave Airlie 已提交
864 865 866 867 868
		if (bar > 100)
			bar = 100;
		if (bar < 1)
			bar = 1;
		i830_fill_box(dev, 4, 16, bar, 4, 196, 128, 128);
L
Linus Torvalds 已提交
869 870 871 872 873 874
		dev_priv->dma_used = 0;
	}

	dev_priv->sarea_priv->perf_boxes = 0;
}

875
static void i830_dma_dispatch_clear(struct drm_device * dev, int flags,
L
Linus Torvalds 已提交
876 877 878 879
				    unsigned int clear_color,
				    unsigned int clear_zval,
				    unsigned int clear_depthmask)
{
D
Dave Airlie 已提交
880 881
	drm_i830_private_t *dev_priv = dev->dev_private;
	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
L
Linus Torvalds 已提交
882
	int nbox = sarea_priv->nbox;
883
	struct drm_clip_rect *pbox = sarea_priv->boxes;
L
Linus Torvalds 已提交
884 885 886 887 888 889
	int pitch = dev_priv->pitch;
	int cpp = dev_priv->cpp;
	int i;
	unsigned int BR13, CMD, D_CMD;
	RING_LOCALS;

D
Dave Airlie 已提交
890
	if (dev_priv->current_page == 1) {
L
Linus Torvalds 已提交
891 892 893
		unsigned int tmp = flags;

		flags &= ~(I830_FRONT | I830_BACK);
D
Dave Airlie 已提交
894 895 896 897
		if (tmp & I830_FRONT)
			flags |= I830_BACK;
		if (tmp & I830_BACK)
			flags |= I830_FRONT;
L
Linus Torvalds 已提交
898 899
	}

D
Dave Airlie 已提交
900
	i830_kernel_lost_context(dev);
L
Linus Torvalds 已提交
901

D
Dave Airlie 已提交
902 903 904
	switch (cpp) {
	case 2:
		BR13 = (0xF0 << 16) | (pitch * cpp) | (1 << 24);
L
Linus Torvalds 已提交
905 906 907
		D_CMD = CMD = XY_COLOR_BLT_CMD;
		break;
	case 4:
D
Dave Airlie 已提交
908 909
		BR13 = (0xF0 << 16) | (pitch * cpp) | (1 << 24) | (1 << 25);
		CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA |
L
Linus Torvalds 已提交
910 911
		       XY_COLOR_BLT_WRITE_RGB);
		D_CMD = XY_COLOR_BLT_CMD;
D
Dave Airlie 已提交
912
		if (clear_depthmask & 0x00ffffff)
L
Linus Torvalds 已提交
913
			D_CMD |= XY_COLOR_BLT_WRITE_RGB;
D
Dave Airlie 已提交
914
		if (clear_depthmask & 0xff000000)
L
Linus Torvalds 已提交
915 916 917
			D_CMD |= XY_COLOR_BLT_WRITE_ALPHA;
		break;
	default:
D
Dave Airlie 已提交
918
		BR13 = (0xF0 << 16) | (pitch * cpp) | (1 << 24);
L
Linus Torvalds 已提交
919 920 921 922
		D_CMD = CMD = XY_COLOR_BLT_CMD;
		break;
	}

D
Dave Airlie 已提交
923 924
	if (nbox > I830_NR_SAREA_CLIPRECTS)
		nbox = I830_NR_SAREA_CLIPRECTS;
L
Linus Torvalds 已提交
925

D
Dave Airlie 已提交
926
	for (i = 0; i < nbox; i++, pbox++) {
L
Linus Torvalds 已提交
927 928
		if (pbox->x1 > pbox->x2 ||
		    pbox->y1 > pbox->y2 ||
D
Dave Airlie 已提交
929
		    pbox->x2 > dev_priv->w || pbox->y2 > dev_priv->h)
L
Linus Torvalds 已提交
930 931
			continue;

D
Dave Airlie 已提交
932 933 934 935 936 937 938 939 940
		if (flags & I830_FRONT) {
			DRM_DEBUG("clear front\n");
			BEGIN_LP_RING(6);
			OUT_RING(CMD);
			OUT_RING(BR13);
			OUT_RING((pbox->y1 << 16) | pbox->x1);
			OUT_RING((pbox->y2 << 16) | pbox->x2);
			OUT_RING(dev_priv->front_offset);
			OUT_RING(clear_color);
L
Linus Torvalds 已提交
941 942 943
			ADVANCE_LP_RING();
		}

D
Dave Airlie 已提交
944
		if (flags & I830_BACK) {
L
Linus Torvalds 已提交
945
			DRM_DEBUG("clear back\n");
D
Dave Airlie 已提交
946 947 948 949 950 951 952
			BEGIN_LP_RING(6);
			OUT_RING(CMD);
			OUT_RING(BR13);
			OUT_RING((pbox->y1 << 16) | pbox->x1);
			OUT_RING((pbox->y2 << 16) | pbox->x2);
			OUT_RING(dev_priv->back_offset);
			OUT_RING(clear_color);
L
Linus Torvalds 已提交
953 954 955
			ADVANCE_LP_RING();
		}

D
Dave Airlie 已提交
956
		if (flags & I830_DEPTH) {
L
Linus Torvalds 已提交
957
			DRM_DEBUG("clear depth\n");
D
Dave Airlie 已提交
958 959 960 961 962 963 964
			BEGIN_LP_RING(6);
			OUT_RING(D_CMD);
			OUT_RING(BR13);
			OUT_RING((pbox->y1 << 16) | pbox->x1);
			OUT_RING((pbox->y2 << 16) | pbox->x2);
			OUT_RING(dev_priv->depth_offset);
			OUT_RING(clear_zval);
L
Linus Torvalds 已提交
965 966 967 968 969
			ADVANCE_LP_RING();
		}
	}
}

970
static void i830_dma_dispatch_swap(struct drm_device * dev)
L
Linus Torvalds 已提交
971
{
D
Dave Airlie 已提交
972 973
	drm_i830_private_t *dev_priv = dev->dev_private;
	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
L
Linus Torvalds 已提交
974
	int nbox = sarea_priv->nbox;
975
	struct drm_clip_rect *pbox = sarea_priv->boxes;
L
Linus Torvalds 已提交
976 977 978 979 980 981 982 983
	int pitch = dev_priv->pitch;
	int cpp = dev_priv->cpp;
	int i;
	unsigned int CMD, BR13;
	RING_LOCALS;

	DRM_DEBUG("swapbuffers\n");

D
Dave Airlie 已提交
984
	i830_kernel_lost_context(dev);
L
Linus Torvalds 已提交
985 986

	if (dev_priv->do_boxes)
D
Dave Airlie 已提交
987
		i830_cp_performance_boxes(dev);
L
Linus Torvalds 已提交
988

D
Dave Airlie 已提交
989 990 991
	switch (cpp) {
	case 2:
		BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24);
L
Linus Torvalds 已提交
992 993 994
		CMD = XY_SRC_COPY_BLT_CMD;
		break;
	case 4:
D
Dave Airlie 已提交
995
		BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24) | (1 << 25);
L
Linus Torvalds 已提交
996 997 998 999
		CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
		       XY_SRC_COPY_BLT_WRITE_RGB);
		break;
	default:
D
Dave Airlie 已提交
1000
		BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24);
L
Linus Torvalds 已提交
1001 1002 1003 1004
		CMD = XY_SRC_COPY_BLT_CMD;
		break;
	}

D
Dave Airlie 已提交
1005 1006
	if (nbox > I830_NR_SAREA_CLIPRECTS)
		nbox = I830_NR_SAREA_CLIPRECTS;
L
Linus Torvalds 已提交
1007

D
Dave Airlie 已提交
1008
	for (i = 0; i < nbox; i++, pbox++) {
L
Linus Torvalds 已提交
1009 1010
		if (pbox->x1 > pbox->x2 ||
		    pbox->y1 > pbox->y2 ||
D
Dave Airlie 已提交
1011
		    pbox->x2 > dev_priv->w || pbox->y2 > dev_priv->h)
L
Linus Torvalds 已提交
1012
			continue;
D
Dave Airlie 已提交
1013

L
Linus Torvalds 已提交
1014
		DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
D
Dave Airlie 已提交
1015
			  pbox->x1, pbox->y1, pbox->x2, pbox->y2);
L
Linus Torvalds 已提交
1016

D
Dave Airlie 已提交
1017 1018 1019 1020 1021
		BEGIN_LP_RING(8);
		OUT_RING(CMD);
		OUT_RING(BR13);
		OUT_RING((pbox->y1 << 16) | pbox->x1);
		OUT_RING((pbox->y2 << 16) | pbox->x2);
L
Linus Torvalds 已提交
1022

D
Dave Airlie 已提交
1023 1024
		if (dev_priv->current_page == 0)
			OUT_RING(dev_priv->front_offset);
L
Linus Torvalds 已提交
1025
		else
D
Dave Airlie 已提交
1026
			OUT_RING(dev_priv->back_offset);
L
Linus Torvalds 已提交
1027

D
Dave Airlie 已提交
1028 1029
		OUT_RING((pbox->y1 << 16) | pbox->x1);
		OUT_RING(BR13 & 0xffff);
L
Linus Torvalds 已提交
1030

D
Dave Airlie 已提交
1031 1032
		if (dev_priv->current_page == 0)
			OUT_RING(dev_priv->back_offset);
L
Linus Torvalds 已提交
1033
		else
D
Dave Airlie 已提交
1034
			OUT_RING(dev_priv->front_offset);
L
Linus Torvalds 已提交
1035 1036 1037 1038 1039

		ADVANCE_LP_RING();
	}
}

1040
static void i830_dma_dispatch_flip(struct drm_device * dev)
L
Linus Torvalds 已提交
1041
{
D
Dave Airlie 已提交
1042
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
1043 1044
	RING_LOCALS;

D
Dave Airlie 已提交
1045
	DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
1046
		  __func__,
D
Dave Airlie 已提交
1047 1048
		  dev_priv->current_page,
		  dev_priv->sarea_priv->pf_current_page);
L
Linus Torvalds 已提交
1049

D
Dave Airlie 已提交
1050
	i830_kernel_lost_context(dev);
L
Linus Torvalds 已提交
1051 1052 1053

	if (dev_priv->do_boxes) {
		dev_priv->sarea_priv->perf_boxes |= I830_BOX_FLIP;
D
Dave Airlie 已提交
1054
		i830_cp_performance_boxes(dev);
L
Linus Torvalds 已提交
1055 1056
	}

D
Dave Airlie 已提交
1057 1058 1059
	BEGIN_LP_RING(2);
	OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
	OUT_RING(0);
L
Linus Torvalds 已提交
1060 1061
	ADVANCE_LP_RING();

D
Dave Airlie 已提交
1062 1063 1064 1065 1066
	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);
L
Linus Torvalds 已提交
1067 1068
		dev_priv->current_page = 1;
	} else {
D
Dave Airlie 已提交
1069
		OUT_RING(dev_priv->front_offset);
L
Linus Torvalds 已提交
1070 1071 1072 1073 1074
		dev_priv->current_page = 0;
	}
	OUT_RING(0);
	ADVANCE_LP_RING();

D
Dave Airlie 已提交
1075 1076 1077
	BEGIN_LP_RING(2);
	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
	OUT_RING(0);
L
Linus Torvalds 已提交
1078 1079 1080 1081 1082
	ADVANCE_LP_RING();

	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
}

1083
static void i830_dma_dispatch_vertex(struct drm_device * dev,
D
Dave Airlie 已提交
1084
				     struct drm_buf * buf, int discard, int used)
L
Linus Torvalds 已提交
1085
{
D
Dave Airlie 已提交
1086
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
1087
	drm_i830_buf_priv_t *buf_priv = buf->dev_private;
D
Dave Airlie 已提交
1088
	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
1089
	struct drm_clip_rect *box = sarea_priv->boxes;
D
Dave Airlie 已提交
1090
	int nbox = sarea_priv->nbox;
L
Linus Torvalds 已提交
1091
	unsigned long address = (unsigned long)buf->bus_address;
D
Dave Airlie 已提交
1092
	unsigned long start = address - dev->agp->base;
L
Linus Torvalds 已提交
1093
	int i = 0, u;
D
Dave Airlie 已提交
1094
	RING_LOCALS;
L
Linus Torvalds 已提交
1095

D
Dave Airlie 已提交
1096
	i830_kernel_lost_context(dev);
L
Linus Torvalds 已提交
1097

D
Dave Airlie 已提交
1098
	if (nbox > I830_NR_SAREA_CLIPRECTS)
L
Linus Torvalds 已提交
1099 1100 1101
		nbox = I830_NR_SAREA_CLIPRECTS;

	if (discard) {
D
Dave Airlie 已提交
1102
		u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
L
Linus Torvalds 已提交
1103
			    I830_BUF_HARDWARE);
D
Dave Airlie 已提交
1104
		if (u != I830_BUF_CLIENT) {
L
Linus Torvalds 已提交
1105 1106 1107 1108
			DRM_DEBUG("xxxx 2\n");
		}
	}

D
Dave Airlie 已提交
1109
	if (used > 4 * 1023)
L
Linus Torvalds 已提交
1110 1111 1112
		used = 0;

	if (sarea_priv->dirty)
D
Dave Airlie 已提交
1113
		i830EmitState(dev);
L
Linus Torvalds 已提交
1114

D
Dave Airlie 已提交
1115
	DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",
L
Linus Torvalds 已提交
1116 1117
		  address, used, nbox);

D
Dave Airlie 已提交
1118 1119 1120 1121 1122 1123
	dev_priv->counter++;
	DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter);
	DRM_DEBUG("i830_dma_dispatch\n");
	DRM_DEBUG("start : %lx\n", start);
	DRM_DEBUG("used : %d\n", used);
	DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4);
L
Linus Torvalds 已提交
1124 1125 1126 1127 1128

	if (buf_priv->currently_mapped == I830_BUF_MAPPED) {
		u32 *vp = buf_priv->kernel_virtual;

		vp[0] = (GFX_OP_PRIMITIVE |
D
Dave Airlie 已提交
1129
			 sarea_priv->vertex_prim | ((used / 4) - 2));
L
Linus Torvalds 已提交
1130 1131

		if (dev_priv->use_mi_batchbuffer_start) {
D
Dave Airlie 已提交
1132 1133
			vp[used / 4] = MI_BATCH_BUFFER_END;
			used += 4;
L
Linus Torvalds 已提交
1134
		}
D
Dave Airlie 已提交
1135

L
Linus Torvalds 已提交
1136
		if (used & 4) {
D
Dave Airlie 已提交
1137
			vp[used / 4] = 0;
L
Linus Torvalds 已提交
1138 1139 1140 1141 1142
			used += 4;
		}

		i830_unmap_buffer(buf);
	}
D
Dave Airlie 已提交
1143

L
Linus Torvalds 已提交
1144 1145 1146 1147
	if (used) {
		do {
			if (i < nbox) {
				BEGIN_LP_RING(6);
D
Dave Airlie 已提交
1148 1149 1150 1151 1152 1153 1154 1155
				OUT_RING(GFX_OP_DRAWRECT_INFO);
				OUT_RING(sarea_priv->
					 BufferState[I830_DESTREG_DR1]);
				OUT_RING(box[i].x1 | (box[i].y1 << 16));
				OUT_RING(box[i].x2 | (box[i].y2 << 16));
				OUT_RING(sarea_priv->
					 BufferState[I830_DESTREG_DR4]);
				OUT_RING(0);
L
Linus Torvalds 已提交
1156 1157 1158 1159 1160
				ADVANCE_LP_RING();
			}

			if (dev_priv->use_mi_batchbuffer_start) {
				BEGIN_LP_RING(2);
D
Dave Airlie 已提交
1161 1162
				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
				OUT_RING(start | MI_BATCH_NON_SECURE);
L
Linus Torvalds 已提交
1163
				ADVANCE_LP_RING();
D
Dave Airlie 已提交
1164
			} else {
L
Linus Torvalds 已提交
1165
				BEGIN_LP_RING(4);
D
Dave Airlie 已提交
1166 1167 1168 1169
				OUT_RING(MI_BATCH_BUFFER);
				OUT_RING(start | MI_BATCH_NON_SECURE);
				OUT_RING(start + used - 4);
				OUT_RING(0);
L
Linus Torvalds 已提交
1170 1171 1172 1173 1174 1175 1176 1177 1178
				ADVANCE_LP_RING();
			}

		} while (++i < nbox);
	}

	if (discard) {
		dev_priv->counter++;

D
Dave Airlie 已提交
1179 1180
		(void)cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
			      I830_BUF_HARDWARE);
L
Linus Torvalds 已提交
1181 1182

		BEGIN_LP_RING(8);
D
Dave Airlie 已提交
1183 1184 1185 1186 1187 1188 1189 1190
		OUT_RING(CMD_STORE_DWORD_IDX);
		OUT_RING(20);
		OUT_RING(dev_priv->counter);
		OUT_RING(CMD_STORE_DWORD_IDX);
		OUT_RING(buf_priv->my_use_idx);
		OUT_RING(I830_BUF_FREE);
		OUT_RING(CMD_REPORT_HEAD);
		OUT_RING(0);
L
Linus Torvalds 已提交
1191 1192 1193 1194
		ADVANCE_LP_RING();
	}
}

1195
static void i830_dma_quiescent(struct drm_device * dev)
L
Linus Torvalds 已提交
1196
{
D
Dave Airlie 已提交
1197 1198
	drm_i830_private_t *dev_priv = dev->dev_private;
	RING_LOCALS;
L
Linus Torvalds 已提交
1199

D
Dave Airlie 已提交
1200
	i830_kernel_lost_context(dev);
L
Linus Torvalds 已提交
1201

D
Dave Airlie 已提交
1202 1203 1204 1205 1206 1207
	BEGIN_LP_RING(4);
	OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
	OUT_RING(CMD_REPORT_HEAD);
	OUT_RING(0);
	OUT_RING(0);
	ADVANCE_LP_RING();
L
Linus Torvalds 已提交
1208

1209
	i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
L
Linus Torvalds 已提交
1210 1211
}

1212
static int i830_flush_queue(struct drm_device * dev)
L
Linus Torvalds 已提交
1213
{
D
Dave Airlie 已提交
1214
	drm_i830_private_t *dev_priv = dev->dev_private;
1215
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
	int i, ret = 0;
	RING_LOCALS;

	i830_kernel_lost_context(dev);

	BEGIN_LP_RING(2);
	OUT_RING(CMD_REPORT_HEAD);
	OUT_RING(0);
	ADVANCE_LP_RING();

1226
	i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
D
Dave Airlie 已提交
1227 1228

	for (i = 0; i < dma->buf_count; i++) {
D
Dave Airlie 已提交
1229
		struct drm_buf *buf = dma->buflist[i];
D
Dave Airlie 已提交
1230 1231 1232
		drm_i830_buf_priv_t *buf_priv = buf->dev_private;

		int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE,
L
Linus Torvalds 已提交
1233 1234 1235 1236 1237 1238 1239 1240
				   I830_BUF_FREE);

		if (used == I830_BUF_HARDWARE)
			DRM_DEBUG("reclaimed from HARDWARE\n");
		if (used == I830_BUF_CLIENT)
			DRM_DEBUG("still on client\n");
	}

D
Dave Airlie 已提交
1241
	return ret;
L
Linus Torvalds 已提交
1242 1243 1244
}

/* Must be called with the lock held */
1245
static void i830_reclaim_buffers(struct drm_device * dev, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1246
{
1247
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
1248
	int i;
L
Linus Torvalds 已提交
1249

D
Dave Airlie 已提交
1250 1251 1252 1253 1254 1255
	if (!dma)
		return;
	if (!dev->dev_private)
		return;
	if (!dma->buflist)
		return;
L
Linus Torvalds 已提交
1256

D
Dave Airlie 已提交
1257
	i830_flush_queue(dev);
L
Linus Torvalds 已提交
1258 1259

	for (i = 0; i < dma->buf_count; i++) {
D
Dave Airlie 已提交
1260
		struct drm_buf *buf = dma->buflist[i];
D
Dave Airlie 已提交
1261 1262
		drm_i830_buf_priv_t *buf_priv = buf->dev_private;

1263
		if (buf->file_priv == file_priv && buf_priv) {
D
Dave Airlie 已提交
1264
			int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
L
Linus Torvalds 已提交
1265 1266 1267 1268
					   I830_BUF_FREE);

			if (used == I830_BUF_CLIENT)
				DRM_DEBUG("reclaimed from client\n");
D
Dave Airlie 已提交
1269 1270
			if (buf_priv->currently_mapped == I830_BUF_MAPPED)
				buf_priv->currently_mapped = I830_BUF_UNMAPPED;
L
Linus Torvalds 已提交
1271 1272 1273 1274
		}
	}
}

1275 1276
static int i830_flush_ioctl(struct drm_device *dev, void *data,
			    struct drm_file *file_priv)
L
Linus Torvalds 已提交
1277
{
1278
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1279

D
Dave Airlie 已提交
1280 1281
	i830_flush_queue(dev);
	return 0;
L
Linus Torvalds 已提交
1282 1283
}

1284 1285
static int i830_dma_vertex(struct drm_device *dev, void *data,
			   struct drm_file *file_priv)
L
Linus Torvalds 已提交
1286
{
1287
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
1288 1289 1290 1291
	drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
	u32 *hw_status = dev_priv->hw_status_page;
	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
	    dev_priv->sarea_priv;
1292
	drm_i830_vertex_t *vertex = data;
L
Linus Torvalds 已提交
1293

1294
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1295 1296

	DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n",
1297
		  vertex->idx, vertex->used, vertex->discard);
L
Linus Torvalds 已提交
1298

1299
	if (vertex->idx < 0 || vertex->idx > dma->buf_count)
D
Dave Airlie 已提交
1300
		return -EINVAL;
L
Linus Torvalds 已提交
1301

D
Dave Airlie 已提交
1302
	i830_dma_dispatch_vertex(dev,
1303 1304
				 dma->buflist[vertex->idx],
				 vertex->discard, vertex->used);
D
Dave Airlie 已提交
1305 1306 1307

	sarea_priv->last_enqueue = dev_priv->counter - 1;
	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
1308 1309 1310 1311

	return 0;
}

1312 1313
static int i830_clear_bufs(struct drm_device *dev, void *data,
			   struct drm_file *file_priv)
L
Linus Torvalds 已提交
1314
{
1315
	drm_i830_clear_t *clear = data;
D
Dave Airlie 已提交
1316

1317
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1318 1319 1320 1321 1322 1323

	/* GH: Someone's doing nasty things... */
	if (!dev->dev_private) {
		return -EINVAL;
	}

1324 1325 1326
	i830_dma_dispatch_clear(dev, clear->flags,
				clear->clear_color,
				clear->clear_depth, clear->clear_depthmask);
D
Dave Airlie 已提交
1327
	return 0;
L
Linus Torvalds 已提交
1328 1329
}

1330 1331
static int i830_swap_bufs(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
1332 1333 1334
{
	DRM_DEBUG("i830_swap_bufs\n");

1335
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1336

D
Dave Airlie 已提交
1337 1338
	i830_dma_dispatch_swap(dev);
	return 0;
L
Linus Torvalds 已提交
1339 1340 1341
}

/* Not sure why this isn't set all the time:
D
Dave Airlie 已提交
1342
 */
1343
static void i830_do_init_pageflip(struct drm_device * dev)
L
Linus Torvalds 已提交
1344 1345 1346
{
	drm_i830_private_t *dev_priv = dev->dev_private;

1347
	DRM_DEBUG("%s\n", __func__);
L
Linus Torvalds 已提交
1348 1349 1350 1351 1352
	dev_priv->page_flipping = 1;
	dev_priv->current_page = 0;
	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
}

1353
static int i830_do_cleanup_pageflip(struct drm_device * dev)
L
Linus Torvalds 已提交
1354 1355 1356
{
	drm_i830_private_t *dev_priv = dev->dev_private;

1357
	DRM_DEBUG("%s\n", __func__);
L
Linus Torvalds 已提交
1358
	if (dev_priv->current_page != 0)
D
Dave Airlie 已提交
1359
		i830_dma_dispatch_flip(dev);
L
Linus Torvalds 已提交
1360 1361 1362 1363 1364

	dev_priv->page_flipping = 0;
	return 0;
}

1365 1366
static int i830_flip_bufs(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
1367 1368 1369
{
	drm_i830_private_t *dev_priv = dev->dev_private;

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

1372
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1373

D
Dave Airlie 已提交
1374 1375
	if (!dev_priv->page_flipping)
		i830_do_init_pageflip(dev);
L
Linus Torvalds 已提交
1376

D
Dave Airlie 已提交
1377 1378
	i830_dma_dispatch_flip(dev);
	return 0;
L
Linus Torvalds 已提交
1379 1380
}

1381 1382
static int i830_getage(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
L
Linus Torvalds 已提交
1383
{
D
Dave Airlie 已提交
1384 1385 1386 1387 1388 1389
	drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
	u32 *hw_status = dev_priv->hw_status_page;
	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
	    dev_priv->sarea_priv;

	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
1390 1391 1392
	return 0;
}

1393 1394
static int i830_getbuf(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
L
Linus Torvalds 已提交
1395
{
D
Dave Airlie 已提交
1396
	int retcode = 0;
1397
	drm_i830_dma_t *d = data;
D
Dave Airlie 已提交
1398 1399 1400 1401
	drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
	u32 *hw_status = dev_priv->hw_status_page;
	drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
	    dev_priv->sarea_priv;
L
Linus Torvalds 已提交
1402 1403

	DRM_DEBUG("getbuf\n");
D
Dave Airlie 已提交
1404

1405
	LOCK_TEST_WITH_RETURN(dev, file_priv);
D
Dave Airlie 已提交
1406

1407
	d->granted = 0;
L
Linus Torvalds 已提交
1408

1409
	retcode = i830_dma_get_buffer(dev, d, file_priv);
L
Linus Torvalds 已提交
1410 1411

	DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
1412
		  task_pid_nr(current), retcode, d->granted);
L
Linus Torvalds 已提交
1413

D
Dave Airlie 已提交
1414
	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
1415 1416 1417 1418

	return retcode;
}

1419 1420
static int i830_copybuf(struct drm_device *dev, void *data,
			struct drm_file *file_priv)
L
Linus Torvalds 已提交
1421 1422 1423 1424 1425
{
	/* Never copy - 2.4.x doesn't need it */
	return 0;
}

1426 1427
static int i830_docopy(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
L
Linus Torvalds 已提交
1428 1429 1430 1431
{
	return 0;
}

1432 1433
static int i830_getparam(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
1434 1435
{
	drm_i830_private_t *dev_priv = dev->dev_private;
1436
	drm_i830_getparam_t *param = data;
L
Linus Torvalds 已提交
1437 1438
	int value;

D
Dave Airlie 已提交
1439
	if (!dev_priv) {
1440
		DRM_ERROR("%s called with no initialization\n", __func__);
L
Linus Torvalds 已提交
1441 1442 1443
		return -EINVAL;
	}

1444
	switch (param->param) {
L
Linus Torvalds 已提交
1445 1446 1447 1448 1449 1450 1451
	case I830_PARAM_IRQ_ACTIVE:
		value = dev->irq_enabled;
		break;
	default:
		return -EINVAL;
	}

1452
	if (copy_to_user(param->value, &value, sizeof(int))) {
D
Dave Airlie 已提交
1453
		DRM_ERROR("copy_to_user\n");
L
Linus Torvalds 已提交
1454 1455
		return -EFAULT;
	}
D
Dave Airlie 已提交
1456

L
Linus Torvalds 已提交
1457 1458 1459
	return 0;
}

1460 1461
static int i830_setparam(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
1462 1463
{
	drm_i830_private_t *dev_priv = dev->dev_private;
1464
	drm_i830_setparam_t *param = data;
L
Linus Torvalds 已提交
1465

D
Dave Airlie 已提交
1466
	if (!dev_priv) {
1467
		DRM_ERROR("%s called with no initialization\n", __func__);
L
Linus Torvalds 已提交
1468 1469 1470
		return -EINVAL;
	}

1471
	switch (param->param) {
L
Linus Torvalds 已提交
1472
	case I830_SETPARAM_USE_MI_BATCHBUFFER_START:
1473
		dev_priv->use_mi_batchbuffer_start = param->value;
L
Linus Torvalds 已提交
1474 1475 1476 1477 1478 1479 1480 1481
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

1482
int i830_driver_load(struct drm_device *dev, unsigned long flags)
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
{
	/* i830 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;

	return 0;
}

1494
void i830_driver_lastclose(struct drm_device * dev)
L
Linus Torvalds 已提交
1495
{
D
Dave Airlie 已提交
1496
	i830_dma_cleanup(dev);
L
Linus Torvalds 已提交
1497 1498
}

1499
void i830_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1500 1501 1502 1503 1504 1505 1506 1507 1508
{
	if (dev->dev_private) {
		drm_i830_private_t *dev_priv = dev->dev_private;
		if (dev_priv->page_flipping) {
			i830_do_cleanup_pageflip(dev);
		}
	}
}

1509
void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1510
{
1511
	i830_reclaim_buffers(dev, file_priv);
L
Linus Torvalds 已提交
1512 1513
}

1514
int i830_driver_dma_quiescent(struct drm_device * dev)
L
Linus Torvalds 已提交
1515
{
D
Dave Airlie 已提交
1516
	i830_dma_quiescent(dev);
L
Linus Torvalds 已提交
1517 1518 1519
	return 0;
}

1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534
struct drm_ioctl_desc i830_ioctls[] = {
	DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
	DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH),
	DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH)
L
Linus Torvalds 已提交
1535 1536 1537
};

int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549

/**
 * 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 i8xx is AGP.
 */
1550
int i830_driver_device_is_agp(struct drm_device * dev)
1551 1552 1553
{
	return 1;
}