i830_dma.c 38.6 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
#include <linux/delay.h>
41
#include <linux/slab.h>
L
Linus Torvalds 已提交
42 43 44 45
#include <asm/uaccess.h>

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

#define I830_BUF_UNMAPPED 0
#define I830_BUF_MAPPED   1

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

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

D
Dave Airlie 已提交
59
	for (i = 0; i < dma->buf_count; i++) {
D
Dave Airlie 已提交
60
		struct drm_buf *buf = dma->buflist[i];
D
Dave Airlie 已提交
61
		drm_i830_buf_priv_t *buf_priv = buf->dev_private;
L
Linus Torvalds 已提交
62
		/* In use is already a pointer */
D
Dave Airlie 已提交
63
		used = cmpxchg(buf_priv->in_use, I830_BUF_FREE,
L
Linus Torvalds 已提交
64
			       I830_BUF_CLIENT);
65
		if (used == I830_BUF_FREE)
L
Linus Torvalds 已提交
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.
 */

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,
120
	.unlocked_ioctl = drm_ioctl,
D
Dave Airlie 已提交
121 122
	.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;
}

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
		drm_i830_private_t *dev_priv =
		    (drm_i830_private_t *) dev->dev_private;

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

234
		kfree(dev->dev_private);
D
Dave Airlie 已提交
235
		dev->dev_private = NULL;
L
Linus Torvalds 已提交
236 237

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

247
int i830_wait_ring(struct drm_device *dev, int n, const char *caller)
L
Linus Torvalds 已提交
248
{
D
Dave Airlie 已提交
249 250 251 252
	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 已提交
253 254
	unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;

D
Dave Airlie 已提交
255 256 257 258 259 260 261
	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 已提交
262
		if (ring->head != last_head) {
D
Dave Airlie 已提交
263
			end = jiffies + (HZ * 3);
L
Linus Torvalds 已提交
264 265
			last_head = ring->head;
		}
D
Dave Airlie 已提交
266 267 268 269 270 271

		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 已提交
272 273 274 275 276
		}
		udelay(1);
		dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
	}

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

281
static void i830_kernel_lost_context(struct drm_device *dev)
L
Linus Torvalds 已提交
282
{
D
Dave Airlie 已提交
283 284 285 286 287 288 289 290
	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 已提交
291 292 293 294 295

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

296
static int i830_freelist_init(struct drm_device *dev, drm_i830_private_t *dev_priv)
L
Linus Torvalds 已提交
297
{
298
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
299 300 301 302 303 304 305
	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 已提交
306 307
	}

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

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

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

318 319 320 321 322 323 324 325
		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 已提交
326 327 328 329
	}
	return 0;
}

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

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

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

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

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

376 377 378 379 380 381 382
	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 已提交
383

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

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

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

L
Linus Torvalds 已提交
396 397 398 399 400 401 402 403 404 405 406
	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 已提交
407
	DRM_DEBUG("front_di1 %x\n", dev_priv->front_di1);
L
Linus Torvalds 已提交
408
	DRM_DEBUG("back_offset %x\n", dev_priv->back_offset);
D
Dave Airlie 已提交
409 410
	DRM_DEBUG("back_di1 %x\n", dev_priv->back_di1);
	DRM_DEBUG("pitch_bits %x\n", init->pitch_bits);
L
Linus Torvalds 已提交
411 412 413 414 415 416 417 418 419 420 421

	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 已提交
422 423 424 425 426
	/* 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 已提交
427 428 429 430 431
		dev->dev_private = (void *)dev_priv;
		i830_dma_cleanup(dev);
		DRM_ERROR("Can not allocate hardware status page\n");
		return -ENOMEM;
	}
D
Dave Airlie 已提交
432
	memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
L
Linus Torvalds 已提交
433
	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
D
Dave Airlie 已提交
434 435

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

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

D
Dave Airlie 已提交
448
	return 0;
L
Linus Torvalds 已提交
449 450
}

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

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

	return retcode;
L
Linus Torvalds 已提交
474 475 476 477 478 479 480 481 482
}

#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.
 */
483
static void i830EmitContextVerified(struct drm_device *dev, unsigned int *code)
L
Linus Torvalds 已提交
484
{
D
Dave Airlie 已提交
485
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
486 487 488 489
	int i, j = 0;
	unsigned int tmp;
	RING_LOCALS;

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

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

D
Dave Airlie 已提交
503 504
	OUT_RING(STATE3D_CONST_BLEND_COLOR_CMD);
	OUT_RING(code[I830_CTXREG_BLENDCOLR]);
L
Linus Torvalds 已提交
505 506
	j += 2;

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

D
Dave Airlie 已提交
518 519
	OUT_RING(STATE3D_MAP_COORD_SETBIND_CMD);
	OUT_RING(code[I830_CTXREG_MCSB1]);
L
Linus Torvalds 已提交
520 521
	j += 2;

D
Dave Airlie 已提交
522 523
	if (j & 1)
		OUT_RING(0);
L
Linus Torvalds 已提交
524 525 526 527

	ADVANCE_LP_RING();
}

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

	if (code[I830_TEXREG_MI0] == GFX_OP_MAP_INFO ||
D
Dave Airlie 已提交
536 537 538 539 540 541 542 543 544 545 546 547 548
	    (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 已提交
549
			tmp = code[i];
D
Dave Airlie 已提交
550
			OUT_RING(tmp);
L
Linus Torvalds 已提交
551
			j++;
D
Dave Airlie 已提交
552
		}
L
Linus Torvalds 已提交
553

D
Dave Airlie 已提交
554 555
		if (j & 1)
			OUT_RING(0);
L
Linus Torvalds 已提交
556 557

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

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

	if (!num)
		return;

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

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

D
Dave Airlie 已提交
581 582
	if (j & 1)
		OUT_RING(0);
L
Linus Torvalds 已提交
583 584 585 586

	ADVANCE_LP_RING();
}

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

	return;

D
Dave Airlie 已提交
596
	BEGIN_LP_RING(258);
L
Linus Torvalds 已提交
597

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

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

D
Dave Airlie 已提交
619
	BEGIN_LP_RING(I830_DEST_SETUP_SIZE + 10);
L
Linus Torvalds 已提交
620 621 622 623 624 625 626 627

	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 已提交
628 629 630 631 632 633 634 635 636 637 638 639
		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 已提交
640 641 642 643 644 645 646 647
	} else {
		DRM_ERROR("bad di1 %x (allow %x or %x)\n",
			  tmp, dev_priv->front_di1, dev_priv->back_di1);
	}

	/* invarient:
	 */

D
Dave Airlie 已提交
648 649
	OUT_RING(GFX_OP_DESTBUFFER_VARS);
	OUT_RING(code[I830_DESTREG_DV1]);
L
Linus Torvalds 已提交
650

D
Dave Airlie 已提交
651 652 653 654 655
	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 已提交
656 657 658

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

D
Dave Airlie 已提交
666 667 668 669
	OUT_RING(GFX_OP_SCISSOR_RECT);
	OUT_RING(code[I830_DESTREG_SR1]);
	OUT_RING(code[I830_DESTREG_SR2]);
	OUT_RING(0);
L
Linus Torvalds 已提交
670 671 672 673

	ADVANCE_LP_RING();
}

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

D
Dave Airlie 已提交
679 680 681 682
	BEGIN_LP_RING(2);
	OUT_RING(GFX_OP_STIPPLE);
	OUT_RING(code[1]);
	ADVANCE_LP_RING();
L
Linus Torvalds 已提交
683 684
}

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

691
	DRM_DEBUG("%s %x\n", __func__, dirty);
L
Linus Torvalds 已提交
692 693

	if (dirty & I830_UPLOAD_BUFFERS) {
D
Dave Airlie 已提交
694
		i830EmitDestVerified(dev, sarea_priv->BufferState);
L
Linus Torvalds 已提交
695 696 697 698
		sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS;
	}

	if (dirty & I830_UPLOAD_CTX) {
D
Dave Airlie 已提交
699
		i830EmitContextVerified(dev, sarea_priv->ContextState);
L
Linus Torvalds 已提交
700 701 702 703
		sarea_priv->dirty &= ~I830_UPLOAD_CTX;
	}

	if (dirty & I830_UPLOAD_TEX0) {
D
Dave Airlie 已提交
704
		i830EmitTexVerified(dev, sarea_priv->TexState[0]);
L
Linus Torvalds 已提交
705 706 707 708
		sarea_priv->dirty &= ~I830_UPLOAD_TEX0;
	}

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

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

	if (dirty & I830_UPLOAD_TEXBLEND1) {
D
Dave Airlie 已提交
720 721
		i830EmitTexBlendVerified(dev, sarea_priv->TexBlendState[1],
					 sarea_priv->TexBlendStateWordsUsed[1]);
L
Linus Torvalds 已提交
722 723 724 725 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
		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 已提交
754
		i830EmitStippleVerified(dev, sarea_priv->StippleState);
L
Linus Torvalds 已提交
755 756 757 758
		sarea_priv->dirty &= ~I830_UPLOAD_STIPPLE;
	}

	if (dirty & I830_UPLOAD_TEX2) {
D
Dave Airlie 已提交
759
		i830EmitTexVerified(dev, sarea_priv->TexState2);
L
Linus Torvalds 已提交
760 761 762 763
		sarea_priv->dirty &= ~I830_UPLOAD_TEX2;
	}

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

	if (dirty & I830_UPLOAD_TEXBLEND2) {
D
Dave Airlie 已提交
769 770 771
		i830EmitTexBlendVerified(dev,
					 sarea_priv->TexBlendState2,
					 sarea_priv->TexBlendStateWordsUsed2);
L
Linus Torvalds 已提交
772 773 774 775 776

		sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND2;
	}

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

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

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

D
Dave Airlie 已提交
796
	BR13 = (0xF0 << 16) | (dev_priv->pitch * dev_priv->cpp) | (1 << 24);
L
Linus Torvalds 已提交
797 798 799 800 801
	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 已提交
802
		BR13 |= (1 << 25);
L
Linus Torvalds 已提交
803
		CMD |= (XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
D
Dave Airlie 已提交
804
		color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
L
Linus Torvalds 已提交
805 806
	} else {
		color = (((r & 0xf8) << 8) |
D
Dave Airlie 已提交
807
			 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
L
Linus Torvalds 已提交
808 809
	}

D
Dave Airlie 已提交
810 811 812 813 814
	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 已提交
815

816
	if (dev_priv->current_page == 1)
D
Dave Airlie 已提交
817
		OUT_RING(dev_priv->front_offset);
818
	else
D
Dave Airlie 已提交
819
		OUT_RING(dev_priv->back_offset);
L
Linus Torvalds 已提交
820

D
Dave Airlie 已提交
821
	OUT_RING(color);
L
Linus Torvalds 已提交
822 823 824
	ADVANCE_LP_RING();
}

825
static void i830_cp_performance_boxes(struct drm_device *dev)
L
Linus Torvalds 已提交
826
{
D
Dave Airlie 已提交
827
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
828 829 830

	/* Purple box for page flipping
	 */
D
Dave Airlie 已提交
831 832
	if (dev_priv->sarea_priv->perf_boxes & I830_BOX_FLIP)
		i830_fill_box(dev, 4, 4, 8, 8, 255, 0, 255);
L
Linus Torvalds 已提交
833 834 835

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

	/* Blue box: lost context?
	 */
D
Dave Airlie 已提交
841 842
	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 已提交
843 844 845

	/* Yellow box for texture swaps
	 */
D
Dave Airlie 已提交
846 847
	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 已提交
848 849 850

	/* Green box if hardware never idles (as far as we can tell)
	 */
D
Dave Airlie 已提交
851 852
	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 已提交
853

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

	dev_priv->sarea_priv->perf_boxes = 0;
}

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

D
Dave Airlie 已提交
885
	if (dev_priv->current_page == 1) {
L
Linus Torvalds 已提交
886 887 888
		unsigned int tmp = flags;

		flags &= ~(I830_FRONT | I830_BACK);
D
Dave Airlie 已提交
889 890 891 892
		if (tmp & I830_FRONT)
			flags |= I830_BACK;
		if (tmp & I830_BACK)
			flags |= I830_FRONT;
L
Linus Torvalds 已提交
893 894
	}

D
Dave Airlie 已提交
895
	i830_kernel_lost_context(dev);
L
Linus Torvalds 已提交
896

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

D
Dave Airlie 已提交
918 919
	if (nbox > I830_NR_SAREA_CLIPRECTS)
		nbox = I830_NR_SAREA_CLIPRECTS;
L
Linus Torvalds 已提交
920

D
Dave Airlie 已提交
921
	for (i = 0; i < nbox; i++, pbox++) {
L
Linus Torvalds 已提交
922 923
		if (pbox->x1 > pbox->x2 ||
		    pbox->y1 > pbox->y2 ||
D
Dave Airlie 已提交
924
		    pbox->x2 > dev_priv->w || pbox->y2 > dev_priv->h)
L
Linus Torvalds 已提交
925 926
			continue;

D
Dave Airlie 已提交
927 928 929 930 931 932 933 934 935
		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 已提交
936 937 938
			ADVANCE_LP_RING();
		}

D
Dave Airlie 已提交
939
		if (flags & I830_BACK) {
L
Linus Torvalds 已提交
940
			DRM_DEBUG("clear back\n");
D
Dave Airlie 已提交
941 942 943 944 945 946 947
			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 已提交
948 949 950
			ADVANCE_LP_RING();
		}

D
Dave Airlie 已提交
951
		if (flags & I830_DEPTH) {
L
Linus Torvalds 已提交
952
			DRM_DEBUG("clear depth\n");
D
Dave Airlie 已提交
953 954 955 956 957 958 959
			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 已提交
960 961 962 963 964
			ADVANCE_LP_RING();
		}
	}
}

965
static void i830_dma_dispatch_swap(struct drm_device *dev)
L
Linus Torvalds 已提交
966
{
D
Dave Airlie 已提交
967 968
	drm_i830_private_t *dev_priv = dev->dev_private;
	drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
L
Linus Torvalds 已提交
969
	int nbox = sarea_priv->nbox;
970
	struct drm_clip_rect *pbox = sarea_priv->boxes;
L
Linus Torvalds 已提交
971 972 973 974 975 976 977 978
	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 已提交
979
	i830_kernel_lost_context(dev);
L
Linus Torvalds 已提交
980 981

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

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

D
Dave Airlie 已提交
1000 1001
	if (nbox > I830_NR_SAREA_CLIPRECTS)
		nbox = I830_NR_SAREA_CLIPRECTS;
L
Linus Torvalds 已提交
1002

D
Dave Airlie 已提交
1003
	for (i = 0; i < nbox; i++, pbox++) {
L
Linus Torvalds 已提交
1004 1005
		if (pbox->x1 > pbox->x2 ||
		    pbox->y1 > pbox->y2 ||
D
Dave Airlie 已提交
1006
		    pbox->x2 > dev_priv->w || pbox->y2 > dev_priv->h)
L
Linus Torvalds 已提交
1007
			continue;
D
Dave Airlie 已提交
1008

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

D
Dave Airlie 已提交
1012 1013 1014 1015 1016
		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 已提交
1017

D
Dave Airlie 已提交
1018 1019
		if (dev_priv->current_page == 0)
			OUT_RING(dev_priv->front_offset);
L
Linus Torvalds 已提交
1020
		else
D
Dave Airlie 已提交
1021
			OUT_RING(dev_priv->back_offset);
L
Linus Torvalds 已提交
1022

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

D
Dave Airlie 已提交
1026 1027
		if (dev_priv->current_page == 0)
			OUT_RING(dev_priv->back_offset);
L
Linus Torvalds 已提交
1028
		else
D
Dave Airlie 已提交
1029
			OUT_RING(dev_priv->front_offset);
L
Linus Torvalds 已提交
1030 1031 1032 1033 1034

		ADVANCE_LP_RING();
	}
}

1035
static void i830_dma_dispatch_flip(struct drm_device *dev)
L
Linus Torvalds 已提交
1036
{
D
Dave Airlie 已提交
1037
	drm_i830_private_t *dev_priv = dev->dev_private;
L
Linus Torvalds 已提交
1038 1039
	RING_LOCALS;

D
Dave Airlie 已提交
1040
	DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
1041
		  __func__,
D
Dave Airlie 已提交
1042 1043
		  dev_priv->current_page,
		  dev_priv->sarea_priv->pf_current_page);
L
Linus Torvalds 已提交
1044

D
Dave Airlie 已提交
1045
	i830_kernel_lost_context(dev);
L
Linus Torvalds 已提交
1046 1047 1048

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

D
Dave Airlie 已提交
1052 1053 1054
	BEGIN_LP_RING(2);
	OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
	OUT_RING(0);
L
Linus Torvalds 已提交
1055 1056
	ADVANCE_LP_RING();

D
Dave Airlie 已提交
1057 1058 1059 1060 1061
	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 已提交
1062 1063
		dev_priv->current_page = 1;
	} else {
D
Dave Airlie 已提交
1064
		OUT_RING(dev_priv->front_offset);
L
Linus Torvalds 已提交
1065 1066 1067 1068 1069
		dev_priv->current_page = 0;
	}
	OUT_RING(0);
	ADVANCE_LP_RING();

D
Dave Airlie 已提交
1070 1071 1072
	BEGIN_LP_RING(2);
	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_PLANE_A_FLIP);
	OUT_RING(0);
L
Linus Torvalds 已提交
1073 1074 1075 1076 1077
	ADVANCE_LP_RING();

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

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

D
Dave Airlie 已提交
1091
	i830_kernel_lost_context(dev);
L
Linus Torvalds 已提交
1092

D
Dave Airlie 已提交
1093
	if (nbox > I830_NR_SAREA_CLIPRECTS)
L
Linus Torvalds 已提交
1094 1095 1096
		nbox = I830_NR_SAREA_CLIPRECTS;

	if (discard) {
D
Dave Airlie 已提交
1097
		u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
L
Linus Torvalds 已提交
1098
			    I830_BUF_HARDWARE);
1099
		if (u != I830_BUF_CLIENT)
L
Linus Torvalds 已提交
1100 1101 1102
			DRM_DEBUG("xxxx 2\n");
	}

D
Dave Airlie 已提交
1103
	if (used > 4 * 1023)
L
Linus Torvalds 已提交
1104 1105 1106
		used = 0;

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

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

D
Dave Airlie 已提交
1112 1113 1114 1115 1116 1117
	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 已提交
1118 1119 1120 1121 1122

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

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

		if (dev_priv->use_mi_batchbuffer_start) {
D
Dave Airlie 已提交
1126 1127
			vp[used / 4] = MI_BATCH_BUFFER_END;
			used += 4;
L
Linus Torvalds 已提交
1128
		}
D
Dave Airlie 已提交
1129

L
Linus Torvalds 已提交
1130
		if (used & 4) {
D
Dave Airlie 已提交
1131
			vp[used / 4] = 0;
L
Linus Torvalds 已提交
1132 1133 1134 1135 1136
			used += 4;
		}

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

L
Linus Torvalds 已提交
1138 1139 1140 1141
	if (used) {
		do {
			if (i < nbox) {
				BEGIN_LP_RING(6);
D
Dave Airlie 已提交
1142 1143 1144 1145 1146 1147 1148 1149
				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 已提交
1150 1151 1152 1153 1154
				ADVANCE_LP_RING();
			}

			if (dev_priv->use_mi_batchbuffer_start) {
				BEGIN_LP_RING(2);
D
Dave Airlie 已提交
1155 1156
				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
				OUT_RING(start | MI_BATCH_NON_SECURE);
L
Linus Torvalds 已提交
1157
				ADVANCE_LP_RING();
D
Dave Airlie 已提交
1158
			} else {
L
Linus Torvalds 已提交
1159
				BEGIN_LP_RING(4);
D
Dave Airlie 已提交
1160 1161 1162 1163
				OUT_RING(MI_BATCH_BUFFER);
				OUT_RING(start | MI_BATCH_NON_SECURE);
				OUT_RING(start + used - 4);
				OUT_RING(0);
L
Linus Torvalds 已提交
1164 1165 1166 1167 1168 1169 1170 1171 1172
				ADVANCE_LP_RING();
			}

		} while (++i < nbox);
	}

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

D
Dave Airlie 已提交
1173 1174
		(void)cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
			      I830_BUF_HARDWARE);
L
Linus Torvalds 已提交
1175 1176

		BEGIN_LP_RING(8);
D
Dave Airlie 已提交
1177 1178 1179 1180 1181 1182 1183 1184
		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 已提交
1185 1186 1187 1188
		ADVANCE_LP_RING();
	}
}

1189
static void i830_dma_quiescent(struct drm_device *dev)
L
Linus Torvalds 已提交
1190
{
D
Dave Airlie 已提交
1191 1192
	drm_i830_private_t *dev_priv = dev->dev_private;
	RING_LOCALS;
L
Linus Torvalds 已提交
1193

D
Dave Airlie 已提交
1194
	i830_kernel_lost_context(dev);
L
Linus Torvalds 已提交
1195

D
Dave Airlie 已提交
1196 1197 1198 1199 1200 1201
	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 已提交
1202

1203
	i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
L
Linus Torvalds 已提交
1204 1205
}

1206
static int i830_flush_queue(struct drm_device *dev)
L
Linus Torvalds 已提交
1207
{
D
Dave Airlie 已提交
1208
	drm_i830_private_t *dev_priv = dev->dev_private;
1209
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
	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();

1220
	i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
D
Dave Airlie 已提交
1221 1222

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

		int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE,
L
Linus Torvalds 已提交
1227 1228 1229 1230 1231 1232 1233 1234
				   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 已提交
1235
	return ret;
L
Linus Torvalds 已提交
1236 1237 1238
}

/* Must be called with the lock held */
1239
static void i830_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1240
{
1241
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
1242
	int i;
L
Linus Torvalds 已提交
1243

D
Dave Airlie 已提交
1244 1245 1246 1247 1248 1249
	if (!dma)
		return;
	if (!dev->dev_private)
		return;
	if (!dma->buflist)
		return;
L
Linus Torvalds 已提交
1250

D
Dave Airlie 已提交
1251
	i830_flush_queue(dev);
L
Linus Torvalds 已提交
1252 1253

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

1257
		if (buf->file_priv == file_priv && buf_priv) {
D
Dave Airlie 已提交
1258
			int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
L
Linus Torvalds 已提交
1259 1260 1261 1262
					   I830_BUF_FREE);

			if (used == I830_BUF_CLIENT)
				DRM_DEBUG("reclaimed from client\n");
D
Dave Airlie 已提交
1263 1264
			if (buf_priv->currently_mapped == I830_BUF_MAPPED)
				buf_priv->currently_mapped = I830_BUF_UNMAPPED;
L
Linus Torvalds 已提交
1265 1266 1267 1268
		}
	}
}

1269 1270
static int i830_flush_ioctl(struct drm_device *dev, void *data,
			    struct drm_file *file_priv)
L
Linus Torvalds 已提交
1271
{
1272
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1273

D
Dave Airlie 已提交
1274 1275
	i830_flush_queue(dev);
	return 0;
L
Linus Torvalds 已提交
1276 1277
}

1278 1279
static int i830_dma_vertex(struct drm_device *dev, void *data,
			   struct drm_file *file_priv)
L
Linus Torvalds 已提交
1280
{
1281
	struct drm_device_dma *dma = dev->dma;
D
Dave Airlie 已提交
1282 1283 1284 1285
	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;
1286
	drm_i830_vertex_t *vertex = data;
L
Linus Torvalds 已提交
1287

1288
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1289 1290

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

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

D
Dave Airlie 已提交
1296
	i830_dma_dispatch_vertex(dev,
1297 1298
				 dma->buflist[vertex->idx],
				 vertex->discard, vertex->used);
D
Dave Airlie 已提交
1299 1300 1301

	sarea_priv->last_enqueue = dev_priv->counter - 1;
	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
1302 1303 1304 1305

	return 0;
}

1306 1307
static int i830_clear_bufs(struct drm_device *dev, void *data,
			   struct drm_file *file_priv)
L
Linus Torvalds 已提交
1308
{
1309
	drm_i830_clear_t *clear = data;
D
Dave Airlie 已提交
1310

1311
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1312 1313

	/* GH: Someone's doing nasty things... */
1314
	if (!dev->dev_private)
L
Linus Torvalds 已提交
1315 1316
		return -EINVAL;

1317 1318 1319
	i830_dma_dispatch_clear(dev, clear->flags,
				clear->clear_color,
				clear->clear_depth, clear->clear_depthmask);
D
Dave Airlie 已提交
1320
	return 0;
L
Linus Torvalds 已提交
1321 1322
}

1323 1324
static int i830_swap_bufs(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
1325 1326 1327
{
	DRM_DEBUG("i830_swap_bufs\n");

1328
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1329

D
Dave Airlie 已提交
1330 1331
	i830_dma_dispatch_swap(dev);
	return 0;
L
Linus Torvalds 已提交
1332 1333 1334
}

/* Not sure why this isn't set all the time:
D
Dave Airlie 已提交
1335
 */
1336
static void i830_do_init_pageflip(struct drm_device *dev)
L
Linus Torvalds 已提交
1337 1338 1339
{
	drm_i830_private_t *dev_priv = dev->dev_private;

1340
	DRM_DEBUG("%s\n", __func__);
L
Linus Torvalds 已提交
1341 1342 1343 1344 1345
	dev_priv->page_flipping = 1;
	dev_priv->current_page = 0;
	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
}

1346
static int i830_do_cleanup_pageflip(struct drm_device *dev)
L
Linus Torvalds 已提交
1347 1348 1349
{
	drm_i830_private_t *dev_priv = dev->dev_private;

1350
	DRM_DEBUG("%s\n", __func__);
L
Linus Torvalds 已提交
1351
	if (dev_priv->current_page != 0)
D
Dave Airlie 已提交
1352
		i830_dma_dispatch_flip(dev);
L
Linus Torvalds 已提交
1353 1354 1355 1356 1357

	dev_priv->page_flipping = 0;
	return 0;
}

1358 1359
static int i830_flip_bufs(struct drm_device *dev, void *data,
			  struct drm_file *file_priv)
L
Linus Torvalds 已提交
1360 1361 1362
{
	drm_i830_private_t *dev_priv = dev->dev_private;

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

1365
	LOCK_TEST_WITH_RETURN(dev, file_priv);
L
Linus Torvalds 已提交
1366

D
Dave Airlie 已提交
1367 1368
	if (!dev_priv->page_flipping)
		i830_do_init_pageflip(dev);
L
Linus Torvalds 已提交
1369

D
Dave Airlie 已提交
1370 1371
	i830_dma_dispatch_flip(dev);
	return 0;
L
Linus Torvalds 已提交
1372 1373
}

1374 1375
static int i830_getage(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
L
Linus Torvalds 已提交
1376
{
D
Dave Airlie 已提交
1377 1378 1379 1380 1381 1382
	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 已提交
1383 1384 1385
	return 0;
}

1386 1387
static int i830_getbuf(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
L
Linus Torvalds 已提交
1388
{
D
Dave Airlie 已提交
1389
	int retcode = 0;
1390
	drm_i830_dma_t *d = data;
D
Dave Airlie 已提交
1391 1392 1393 1394
	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 已提交
1395 1396

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

1398
	LOCK_TEST_WITH_RETURN(dev, file_priv);
D
Dave Airlie 已提交
1399

1400
	d->granted = 0;
L
Linus Torvalds 已提交
1401

1402
	retcode = i830_dma_get_buffer(dev, d, file_priv);
L
Linus Torvalds 已提交
1403 1404

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

D
Dave Airlie 已提交
1407
	sarea_priv->last_dispatch = (int)hw_status[5];
L
Linus Torvalds 已提交
1408 1409 1410 1411

	return retcode;
}

1412 1413
static int i830_copybuf(struct drm_device *dev, void *data,
			struct drm_file *file_priv)
L
Linus Torvalds 已提交
1414 1415 1416 1417 1418
{
	/* Never copy - 2.4.x doesn't need it */
	return 0;
}

1419 1420
static int i830_docopy(struct drm_device *dev, void *data,
		       struct drm_file *file_priv)
L
Linus Torvalds 已提交
1421 1422 1423 1424
{
	return 0;
}

1425 1426
static int i830_getparam(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
1427 1428
{
	drm_i830_private_t *dev_priv = dev->dev_private;
1429
	drm_i830_getparam_t *param = data;
L
Linus Torvalds 已提交
1430 1431
	int value;

D
Dave Airlie 已提交
1432
	if (!dev_priv) {
1433
		DRM_ERROR("%s called with no initialization\n", __func__);
L
Linus Torvalds 已提交
1434 1435 1436
		return -EINVAL;
	}

1437
	switch (param->param) {
L
Linus Torvalds 已提交
1438 1439 1440 1441 1442 1443 1444
	case I830_PARAM_IRQ_ACTIVE:
		value = dev->irq_enabled;
		break;
	default:
		return -EINVAL;
	}

1445
	if (copy_to_user(param->value, &value, sizeof(int))) {
D
Dave Airlie 已提交
1446
		DRM_ERROR("copy_to_user\n");
L
Linus Torvalds 已提交
1447 1448
		return -EFAULT;
	}
D
Dave Airlie 已提交
1449

L
Linus Torvalds 已提交
1450 1451 1452
	return 0;
}

1453 1454
static int i830_setparam(struct drm_device *dev, void *data,
			 struct drm_file *file_priv)
L
Linus Torvalds 已提交
1455 1456
{
	drm_i830_private_t *dev_priv = dev->dev_private;
1457
	drm_i830_setparam_t *param = data;
L
Linus Torvalds 已提交
1458

D
Dave Airlie 已提交
1459
	if (!dev_priv) {
1460
		DRM_ERROR("%s called with no initialization\n", __func__);
L
Linus Torvalds 已提交
1461 1462 1463
		return -EINVAL;
	}

1464
	switch (param->param) {
L
Linus Torvalds 已提交
1465
	case I830_SETPARAM_USE_MI_BATCHBUFFER_START:
1466
		dev_priv->use_mi_batchbuffer_start = param->value;
L
Linus Torvalds 已提交
1467 1468 1469 1470 1471 1472 1473 1474
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

1475
int i830_driver_load(struct drm_device *dev, unsigned long flags)
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
{
	/* 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;
}

1487
void i830_driver_lastclose(struct drm_device *dev)
L
Linus Torvalds 已提交
1488
{
D
Dave Airlie 已提交
1489
	i830_dma_cleanup(dev);
L
Linus Torvalds 已提交
1490 1491
}

1492
void i830_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1493 1494 1495
{
	if (dev->dev_private) {
		drm_i830_private_t *dev_priv = dev->dev_private;
1496
		if (dev_priv->page_flipping)
L
Linus Torvalds 已提交
1497 1498 1499 1500
			i830_do_cleanup_pageflip(dev);
	}
}

1501
void i830_driver_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv)
L
Linus Torvalds 已提交
1502
{
1503
	i830_reclaim_buffers(dev, file_priv);
L
Linus Torvalds 已提交
1504 1505
}

1506
int i830_driver_dma_quiescent(struct drm_device *dev)
L
Linus Torvalds 已提交
1507
{
D
Dave Airlie 已提交
1508
	i830_dma_quiescent(dev);
L
Linus Torvalds 已提交
1509 1510 1511
	return 0;
}

1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
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 已提交
1527 1528 1529
};

int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541

/**
 * 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.
 */
1542
int i830_driver_device_is_agp(struct drm_device *dev)
1543 1544 1545
{
	return 1;
}