1/* i810_dma.c -- DMA support for the i810 -*- linux-c -*-
2 * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
3 *
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
28 *	    Jeff Hartmann <jhartmann@valinux.com>
29 *          Keith Whitwell <keith@tungstengraphics.com>
30 *
31 */
32
33#include <linux/delay.h>
34#include <linux/mman.h>
35#include <linux/pci.h>
36
37#include <drm/drm_agpsupport.h>
38#include <drm/drm_device.h>
39#include <drm/drm_drv.h>
40#include <drm/drm_file.h>
41#include <drm/drm_ioctl.h>
42#include <drm/drm_irq.h>
43#include <drm/drm_print.h>
44#include <drm/i810_drm.h>
45
46#include "i810_drv.h"
47
48#define I810_BUF_FREE		2
49#define I810_BUF_CLIENT		1
50#define I810_BUF_HARDWARE	0
51
52#define I810_BUF_UNMAPPED 0
53#define I810_BUF_MAPPED   1
54
55static struct drm_buf *i810_freelist_get(struct drm_device * dev)
56{
57	struct drm_device_dma *dma = dev->dma;
58	int i;
59	int used;
60
61	/* Linear search might not be the best solution */
62
63	for (i = 0; i < dma->buf_count; i++) {
64		struct drm_buf *buf = dma->buflist[i];
65		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
66		/* In use is already a pointer */
67		used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
68			       I810_BUF_CLIENT);
69		if (used == I810_BUF_FREE)
70			return buf;
71	}
72	return NULL;
73}
74
75/* This should only be called if the buffer is not sent to the hardware
76 * yet, the hardware updates in use for us once its on the ring buffer.
77 */
78
79static int i810_freelist_put(struct drm_device *dev, struct drm_buf *buf)
80{
81	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
82	int used;
83
84	/* In use is already a pointer */
85	used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);
86	if (used != I810_BUF_CLIENT) {
87		DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
88		return -EINVAL;
89	}
90
91	return 0;
92}
93
94static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
95{
96	struct drm_file *priv = filp->private_data;
97	struct drm_device *dev;
98	drm_i810_private_t *dev_priv;
99	struct drm_buf *buf;
100	drm_i810_buf_priv_t *buf_priv;
101
102	dev = priv->minor->dev;
103	dev_priv = dev->dev_private;
104	buf = dev_priv->mmap_buffer;
105	buf_priv = buf->dev_private;
106
107	vma->vm_flags |= VM_DONTCOPY;
108
109	buf_priv->currently_mapped = I810_BUF_MAPPED;
110
111	if (io_remap_pfn_range(vma, vma->vm_start,
112			       vma->vm_pgoff,
113			       vma->vm_end - vma->vm_start, vma->vm_page_prot))
114		return -EAGAIN;
115	return 0;
116}
117
118static const struct file_operations i810_buffer_fops = {
119	.open = drm_open,
120	.release = drm_release,
121	.unlocked_ioctl = drm_ioctl,
122	.mmap = i810_mmap_buffers,
123	.compat_ioctl = drm_compat_ioctl,
124	.llseek = noop_llseek,
125};
126
127static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv)
128{
129	struct drm_device *dev = file_priv->minor->dev;
130	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
131	drm_i810_private_t *dev_priv = dev->dev_private;
132	const struct file_operations *old_fops;
133	int retcode = 0;
134
135	if (buf_priv->currently_mapped == I810_BUF_MAPPED)
136		return -EINVAL;
137
138	/* This is all entirely broken */
139	old_fops = file_priv->filp->f_op;
140	file_priv->filp->f_op = &i810_buffer_fops;
141	dev_priv->mmap_buffer = buf;
142	buf_priv->virtual = (void *)vm_mmap(file_priv->filp, 0, buf->total,
143					    PROT_READ | PROT_WRITE,
144					    MAP_SHARED, buf->bus_address);
145	dev_priv->mmap_buffer = NULL;
146	file_priv->filp->f_op = old_fops;
147	if (IS_ERR(buf_priv->virtual)) {
148		/* Real error */
149		DRM_ERROR("mmap error\n");
150		retcode = PTR_ERR(buf_priv->virtual);
151		buf_priv->virtual = NULL;
152	}
153
154	return retcode;
155}
156
157static int i810_unmap_buffer(struct drm_buf *buf)
158{
159	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
160	int retcode = 0;
161
162	if (buf_priv->currently_mapped != I810_BUF_MAPPED)
163		return -EINVAL;
164
165	retcode = vm_munmap((unsigned long)buf_priv->virtual,
166			    (size_t) buf->total);
167
168	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
169	buf_priv->virtual = NULL;
170
171	return retcode;
172}
173
174static int i810_dma_get_buffer(struct drm_device *dev, drm_i810_dma_t *d,
175			       struct drm_file *file_priv)
176{
177	struct drm_buf *buf;
178	drm_i810_buf_priv_t *buf_priv;
179	int retcode = 0;
180
181	buf = i810_freelist_get(dev);
182	if (!buf) {
183		retcode = -ENOMEM;
184		DRM_DEBUG("retcode=%d\n", retcode);
185		return retcode;
186	}
187
188	retcode = i810_map_buffer(buf, file_priv);
189	if (retcode) {
190		i810_freelist_put(dev, buf);
191		DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
192		return retcode;
193	}
194	buf->file_priv = file_priv;
195	buf_priv = buf->dev_private;
196	d->granted = 1;
197	d->request_idx = buf->idx;
198	d->request_size = buf->total;
199	d->virtual = buf_priv->virtual;
200
201	return retcode;
202}
203
204static int i810_dma_cleanup(struct drm_device *dev)
205{
206	struct drm_device_dma *dma = dev->dma;
207
208	/* Make sure interrupts are disabled here because the uninstall ioctl
209	 * may not have been called from userspace and after dev_private
210	 * is freed, it's too late.
211	 */
212	if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ) && dev->irq_enabled)
213		drm_irq_uninstall(dev);
214
215	if (dev->dev_private) {
216		int i;
217		drm_i810_private_t *dev_priv =
218		    (drm_i810_private_t *) dev->dev_private;
219
220		if (dev_priv->ring.virtual_start)
221			drm_legacy_ioremapfree(&dev_priv->ring.map, dev);
222		if (dev_priv->hw_status_page) {
223			dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
224					  dev_priv->hw_status_page,
225					  dev_priv->dma_status_page);
226		}
227		kfree(dev->dev_private);
228		dev->dev_private = NULL;
229
230		for (i = 0; i < dma->buf_count; i++) {
231			struct drm_buf *buf = dma->buflist[i];
232			drm_i810_buf_priv_t *buf_priv = buf->dev_private;
233
234			if (buf_priv->kernel_virtual && buf->total)
235				drm_legacy_ioremapfree(&buf_priv->map, dev);
236		}
237	}
238	return 0;
239}
240
241static int i810_wait_ring(struct drm_device *dev, int n)
242{
243	drm_i810_private_t *dev_priv = dev->dev_private;
244	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
245	int iters = 0;
246	unsigned long end;
247	unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
248
249	end = jiffies + (HZ * 3);
250	while (ring->space < n) {
251		ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
252		ring->space = ring->head - (ring->tail + 8);
253		if (ring->space < 0)
254			ring->space += ring->Size;
255
256		if (ring->head != last_head) {
257			end = jiffies + (HZ * 3);
258			last_head = ring->head;
259		}
260
261		iters++;
262		if (time_before(end, jiffies)) {
263			DRM_ERROR("space: %d wanted %d\n", ring->space, n);
264			DRM_ERROR("lockup\n");
265			goto out_wait_ring;
266		}
267		udelay(1);
268	}
269
270out_wait_ring:
271	return iters;
272}
273
274static void i810_kernel_lost_context(struct drm_device *dev)
275{
276	drm_i810_private_t *dev_priv = dev->dev_private;
277	drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
278
279	ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
280	ring->tail = I810_READ(LP_RING + RING_TAIL);
281	ring->space = ring->head - (ring->tail + 8);
282	if (ring->space < 0)
283		ring->space += ring->Size;
284}
285
286static int i810_freelist_init(struct drm_device *dev, drm_i810_private_t *dev_priv)
287{
288	struct drm_device_dma *dma = dev->dma;
289	int my_idx = 24;
290	u32 *hw_status = (u32 *) (dev_priv->hw_status_page + my_idx);
291	int i;
292
293	if (dma->buf_count > 1019) {
294		/* Not enough space in the status page for the freelist */
295		return -EINVAL;
296	}
297
298	for (i = 0; i < dma->buf_count; i++) {
299		struct drm_buf *buf = dma->buflist[i];
300		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
301
302		buf_priv->in_use = hw_status++;
303		buf_priv->my_use_idx = my_idx;
304		my_idx += 4;
305
306		*buf_priv->in_use = I810_BUF_FREE;
307
308		buf_priv->map.offset = buf->bus_address;
309		buf_priv->map.size = buf->total;
310		buf_priv->map.type = _DRM_AGP;
311		buf_priv->map.flags = 0;
312		buf_priv->map.mtrr = 0;
313
314		drm_legacy_ioremap(&buf_priv->map, dev);
315		buf_priv->kernel_virtual = buf_priv->map.handle;
316
317	}
318	return 0;
319}
320
321static int i810_dma_initialize(struct drm_device *dev,
322			       drm_i810_private_t *dev_priv,
323			       drm_i810_init_t *init)
324{
325	struct drm_map_list *r_list;
326	memset(dev_priv, 0, sizeof(drm_i810_private_t));
327
328	list_for_each_entry(r_list, &dev->maplist, head) {
329		if (r_list->map &&
330		    r_list->map->type == _DRM_SHM &&
331		    r_list->map->flags & _DRM_CONTAINS_LOCK) {
332			dev_priv->sarea_map = r_list->map;
333			break;
334		}
335	}
336	if (!dev_priv->sarea_map) {
337		dev->dev_private = (void *)dev_priv;
338		i810_dma_cleanup(dev);
339		DRM_ERROR("can not find sarea!\n");
340		return -EINVAL;
341	}
342	dev_priv->mmio_map = drm_legacy_findmap(dev, init->mmio_offset);
343	if (!dev_priv->mmio_map) {
344		dev->dev_private = (void *)dev_priv;
345		i810_dma_cleanup(dev);
346		DRM_ERROR("can not find mmio map!\n");
347		return -EINVAL;
348	}
349	dev->agp_buffer_token = init->buffers_offset;
350	dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
351	if (!dev->agp_buffer_map) {
352		dev->dev_private = (void *)dev_priv;
353		i810_dma_cleanup(dev);
354		DRM_ERROR("can not find dma buffer map!\n");
355		return -EINVAL;
356	}
357
358	dev_priv->sarea_priv = (drm_i810_sarea_t *)
359	    ((u8 *) dev_priv->sarea_map->handle + init->sarea_priv_offset);
360
361	dev_priv->ring.Start = init->ring_start;
362	dev_priv->ring.End = init->ring_end;
363	dev_priv->ring.Size = init->ring_size;
364
365	dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
366	dev_priv->ring.map.size = init->ring_size;
367	dev_priv->ring.map.type = _DRM_AGP;
368	dev_priv->ring.map.flags = 0;
369	dev_priv->ring.map.mtrr = 0;
370
371	drm_legacy_ioremap(&dev_priv->ring.map, dev);
372
373	if (dev_priv->ring.map.handle == NULL) {
374		dev->dev_private = (void *)dev_priv;
375		i810_dma_cleanup(dev);
376		DRM_ERROR("can not ioremap virtual address for"
377			  " ring buffer\n");
378		return -ENOMEM;
379	}
380
381	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
382
383	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
384
385	dev_priv->w = init->w;
386	dev_priv->h = init->h;
387	dev_priv->pitch = init->pitch;
388	dev_priv->back_offset = init->back_offset;
389	dev_priv->depth_offset = init->depth_offset;
390	dev_priv->front_offset = init->front_offset;
391
392	dev_priv->overlay_offset = init->overlay_offset;
393	dev_priv->overlay_physical = init->overlay_physical;
394
395	dev_priv->front_di1 = init->front_offset | init->pitch_bits;
396	dev_priv->back_di1 = init->back_offset | init->pitch_bits;
397	dev_priv->zi1 = init->depth_offset | init->pitch_bits;
398
399	/* Program Hardware Status Page */
400	dev_priv->hw_status_page =
401		dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
402				   &dev_priv->dma_status_page, GFP_KERNEL);
403	if (!dev_priv->hw_status_page) {
404		dev->dev_private = (void *)dev_priv;
405		i810_dma_cleanup(dev);
406		DRM_ERROR("Can not allocate hardware status page\n");
407		return -ENOMEM;
408	}
409	DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
410
411	I810_WRITE(0x02080, dev_priv->dma_status_page);
412	DRM_DEBUG("Enabled hardware status page\n");
413
414	/* Now we need to init our freelist */
415	if (i810_freelist_init(dev, dev_priv) != 0) {
416		dev->dev_private = (void *)dev_priv;
417		i810_dma_cleanup(dev);
418		DRM_ERROR("Not enough space in the status page for"
419			  " the freelist\n");
420		return -ENOMEM;
421	}
422	dev->dev_private = (void *)dev_priv;
423
424	return 0;
425}
426
427static int i810_dma_init(struct drm_device *dev, void *data,
428			 struct drm_file *file_priv)
429{
430	drm_i810_private_t *dev_priv;
431	drm_i810_init_t *init = data;
432	int retcode = 0;
433
434	switch (init->func) {
435	case I810_INIT_DMA_1_4:
436		DRM_INFO("Using v1.4 init.\n");
437		dev_priv = kmalloc(sizeof(drm_i810_private_t), GFP_KERNEL);
438		if (dev_priv == NULL)
439			return -ENOMEM;
440		retcode = i810_dma_initialize(dev, dev_priv, init);
441		break;
442
443	case I810_CLEANUP_DMA:
444		DRM_INFO("DMA Cleanup\n");
445		retcode = i810_dma_cleanup(dev);
446		break;
447	default:
448		return -EINVAL;
449	}
450
451	return retcode;
452}
453
454/* Most efficient way to verify state for the i810 is as it is
455 * emitted.  Non-conformant state is silently dropped.
456 *
457 * Use 'volatile' & local var tmp to force the emitted values to be
458 * identical to the verified ones.
459 */
460static void i810EmitContextVerified(struct drm_device *dev,
461				    volatile unsigned int *code)
462{
463	drm_i810_private_t *dev_priv = dev->dev_private;
464	int i, j = 0;
465	unsigned int tmp;
466	RING_LOCALS;
467
468	BEGIN_LP_RING(I810_CTX_SETUP_SIZE);
469
470	OUT_RING(GFX_OP_COLOR_FACTOR);
471	OUT_RING(code[I810_CTXREG_CF1]);
472
473	OUT_RING(GFX_OP_STIPPLE);
474	OUT_RING(code[I810_CTXREG_ST1]);
475
476	for (i = 4; i < I810_CTX_SETUP_SIZE; i++) {
477		tmp = code[i];
478
479		if ((tmp & (7 << 29)) == (3 << 29) &&
480		    (tmp & (0x1f << 24)) < (0x1d << 24)) {
481			OUT_RING(tmp);
482			j++;
483		} else
484			printk("constext state dropped!!!\n");
485	}
486
487	if (j & 1)
488		OUT_RING(0);
489
490	ADVANCE_LP_RING();
491}
492
493static void i810EmitTexVerified(struct drm_device *dev, volatile unsigned int *code)
494{
495	drm_i810_private_t *dev_priv = dev->dev_private;
496	int i, j = 0;
497	unsigned int tmp;
498	RING_LOCALS;
499
500	BEGIN_LP_RING(I810_TEX_SETUP_SIZE);
501
502	OUT_RING(GFX_OP_MAP_INFO);
503	OUT_RING(code[I810_TEXREG_MI1]);
504	OUT_RING(code[I810_TEXREG_MI2]);
505	OUT_RING(code[I810_TEXREG_MI3]);
506
507	for (i = 4; i < I810_TEX_SETUP_SIZE; i++) {
508		tmp = code[i];
509
510		if ((tmp & (7 << 29)) == (3 << 29) &&
511		    (tmp & (0x1f << 24)) < (0x1d << 24)) {
512			OUT_RING(tmp);
513			j++;
514		} else
515			printk("texture state dropped!!!\n");
516	}
517
518	if (j & 1)
519		OUT_RING(0);
520
521	ADVANCE_LP_RING();
522}
523
524/* Need to do some additional checking when setting the dest buffer.
525 */
526static void i810EmitDestVerified(struct drm_device *dev,
527				 volatile unsigned int *code)
528{
529	drm_i810_private_t *dev_priv = dev->dev_private;
530	unsigned int tmp;
531	RING_LOCALS;
532
533	BEGIN_LP_RING(I810_DEST_SETUP_SIZE + 2);
534
535	tmp = code[I810_DESTREG_DI1];
536	if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
537		OUT_RING(CMD_OP_DESTBUFFER_INFO);
538		OUT_RING(tmp);
539	} else
540		DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
541			  tmp, dev_priv->front_di1, dev_priv->back_di1);
542
543	/* invarient:
544	 */
545	OUT_RING(CMD_OP_Z_BUFFER_INFO);
546	OUT_RING(dev_priv->zi1);
547
548	OUT_RING(GFX_OP_DESTBUFFER_VARS);
549	OUT_RING(code[I810_DESTREG_DV1]);
550
551	OUT_RING(GFX_OP_DRAWRECT_INFO);
552	OUT_RING(code[I810_DESTREG_DR1]);
553	OUT_RING(code[I810_DESTREG_DR2]);
554	OUT_RING(code[I810_DESTREG_DR3]);
555	OUT_RING(code[I810_DESTREG_DR4]);
556	OUT_RING(0);
557
558	ADVANCE_LP_RING();
559}
560
561static void i810EmitState(struct drm_device *dev)
562{
563	drm_i810_private_t *dev_priv = dev->dev_private;
564	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
565	unsigned int dirty = sarea_priv->dirty;
566
567	DRM_DEBUG("%x\n", dirty);
568
569	if (dirty & I810_UPLOAD_BUFFERS) {
570		i810EmitDestVerified(dev, sarea_priv->BufferState);
571		sarea_priv->dirty &= ~I810_UPLOAD_BUFFERS;
572	}
573
574	if (dirty & I810_UPLOAD_CTX) {
575		i810EmitContextVerified(dev, sarea_priv->ContextState);
576		sarea_priv->dirty &= ~I810_UPLOAD_CTX;
577	}
578
579	if (dirty & I810_UPLOAD_TEX0) {
580		i810EmitTexVerified(dev, sarea_priv->TexState[0]);
581		sarea_priv->dirty &= ~I810_UPLOAD_TEX0;
582	}
583
584	if (dirty & I810_UPLOAD_TEX1) {
585		i810EmitTexVerified(dev, sarea_priv->TexState[1]);
586		sarea_priv->dirty &= ~I810_UPLOAD_TEX1;
587	}
588}
589
590/* need to verify
591 */
592static void i810_dma_dispatch_clear(struct drm_device *dev, int flags,
593				    unsigned int clear_color,
594				    unsigned int clear_zval)
595{
596	drm_i810_private_t *dev_priv = dev->dev_private;
597	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
598	int nbox = sarea_priv->nbox;
599	struct drm_clip_rect *pbox = sarea_priv->boxes;
600	int pitch = dev_priv->pitch;
601	int cpp = 2;
602	int i;
603	RING_LOCALS;
604
605	if (dev_priv->current_page == 1) {
606		unsigned int tmp = flags;
607
608		flags &= ~(I810_FRONT | I810_BACK);
609		if (tmp & I810_FRONT)
610			flags |= I810_BACK;
611		if (tmp & I810_BACK)
612			flags |= I810_FRONT;
613	}
614
615	i810_kernel_lost_context(dev);
616
617	if (nbox > I810_NR_SAREA_CLIPRECTS)
618		nbox = I810_NR_SAREA_CLIPRECTS;
619
620	for (i = 0; i < nbox; i++, pbox++) {
621		unsigned int x = pbox->x1;
622		unsigned int y = pbox->y1;
623		unsigned int width = (pbox->x2 - x) * cpp;
624		unsigned int height = pbox->y2 - y;
625		unsigned int start = y * pitch + x * cpp;
626
627		if (pbox->x1 > pbox->x2 ||
628		    pbox->y1 > pbox->y2 ||
629		    pbox->x2 > dev_priv->w || pbox->y2 > dev_priv->h)
630			continue;
631
632		if (flags & I810_FRONT) {
633			BEGIN_LP_RING(6);
634			OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3);
635			OUT_RING(BR13_SOLID_PATTERN | (0xF0 << 16) | pitch);
636			OUT_RING((height << 16) | width);
637			OUT_RING(start);
638			OUT_RING(clear_color);
639			OUT_RING(0);
640			ADVANCE_LP_RING();
641		}
642
643		if (flags & I810_BACK) {
644			BEGIN_LP_RING(6);
645			OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3);
646			OUT_RING(BR13_SOLID_PATTERN | (0xF0 << 16) | pitch);
647			OUT_RING((height << 16) | width);
648			OUT_RING(dev_priv->back_offset + start);
649			OUT_RING(clear_color);
650			OUT_RING(0);
651			ADVANCE_LP_RING();
652		}
653
654		if (flags & I810_DEPTH) {
655			BEGIN_LP_RING(6);
656			OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_COLOR_BLT | 0x3);
657			OUT_RING(BR13_SOLID_PATTERN | (0xF0 << 16) | pitch);
658			OUT_RING((height << 16) | width);
659			OUT_RING(dev_priv->depth_offset + start);
660			OUT_RING(clear_zval);
661			OUT_RING(0);
662			ADVANCE_LP_RING();
663		}
664	}
665}
666
667static void i810_dma_dispatch_swap(struct drm_device *dev)
668{
669	drm_i810_private_t *dev_priv = dev->dev_private;
670	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
671	int nbox = sarea_priv->nbox;
672	struct drm_clip_rect *pbox = sarea_priv->boxes;
673	int pitch = dev_priv->pitch;
674	int cpp = 2;
675	int i;
676	RING_LOCALS;
677
678	DRM_DEBUG("swapbuffers\n");
679
680	i810_kernel_lost_context(dev);
681
682	if (nbox > I810_NR_SAREA_CLIPRECTS)
683		nbox = I810_NR_SAREA_CLIPRECTS;
684
685	for (i = 0; i < nbox; i++, pbox++) {
686		unsigned int w = pbox->x2 - pbox->x1;
687		unsigned int h = pbox->y2 - pbox->y1;
688		unsigned int dst = pbox->x1 * cpp + pbox->y1 * pitch;
689		unsigned int start = dst;
690
691		if (pbox->x1 > pbox->x2 ||
692		    pbox->y1 > pbox->y2 ||
693		    pbox->x2 > dev_priv->w || pbox->y2 > dev_priv->h)
694			continue;
695
696		BEGIN_LP_RING(6);
697		OUT_RING(BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4);
698		OUT_RING(pitch | (0xCC << 16));
699		OUT_RING((h << 16) | (w * cpp));
700		if (dev_priv->current_page == 0)
701			OUT_RING(dev_priv->front_offset + start);
702		else
703			OUT_RING(dev_priv->back_offset + start);
704		OUT_RING(pitch);
705		if (dev_priv->current_page == 0)
706			OUT_RING(dev_priv->back_offset + start);
707		else
708			OUT_RING(dev_priv->front_offset + start);
709		ADVANCE_LP_RING();
710	}
711}
712
713static void i810_dma_dispatch_vertex(struct drm_device *dev,
714				     struct drm_buf *buf, int discard, int used)
715{
716	drm_i810_private_t *dev_priv = dev->dev_private;
717	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
718	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
719	struct drm_clip_rect *box = sarea_priv->boxes;
720	int nbox = sarea_priv->nbox;
721	unsigned long address = (unsigned long)buf->bus_address;
722	unsigned long start = address - dev->agp->base;
723	int i = 0;
724	RING_LOCALS;
725
726	i810_kernel_lost_context(dev);
727
728	if (nbox > I810_NR_SAREA_CLIPRECTS)
729		nbox = I810_NR_SAREA_CLIPRECTS;
730
731	if (used < 0 || used > 4 * 1024)
732		used = 0;
733
734	if (sarea_priv->dirty)
735		i810EmitState(dev);
736
737	if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
738		unsigned int prim = (sarea_priv->vertex_prim & PR_MASK);
739
740		*(u32 *) buf_priv->kernel_virtual =
741		    ((GFX_OP_PRIMITIVE | prim | ((used / 4) - 2)));
742
743		if (used & 4) {
744			*(u32 *) ((char *) buf_priv->kernel_virtual + used) = 0;
745			used += 4;
746		}
747
748		i810_unmap_buffer(buf);
749	}
750
751	if (used) {
752		do {
753			if (i < nbox) {
754				BEGIN_LP_RING(4);
755				OUT_RING(GFX_OP_SCISSOR | SC_UPDATE_SCISSOR |
756					 SC_ENABLE);
757				OUT_RING(GFX_OP_SCISSOR_INFO);
758				OUT_RING(box[i].x1 | (box[i].y1 << 16));
759				OUT_RING((box[i].x2 -
760					  1) | ((box[i].y2 - 1) << 16));
761				ADVANCE_LP_RING();
762			}
763
764			BEGIN_LP_RING(4);
765			OUT_RING(CMD_OP_BATCH_BUFFER);
766			OUT_RING(start | BB1_PROTECTED);
767			OUT_RING(start + used - 4);
768			OUT_RING(0);
769			ADVANCE_LP_RING();
770
771		} while (++i < nbox);
772	}
773
774	if (discard) {
775		dev_priv->counter++;
776
777		(void)cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
778			      I810_BUF_HARDWARE);
779
780		BEGIN_LP_RING(8);
781		OUT_RING(CMD_STORE_DWORD_IDX);
782		OUT_RING(20);
783		OUT_RING(dev_priv->counter);
784		OUT_RING(CMD_STORE_DWORD_IDX);
785		OUT_RING(buf_priv->my_use_idx);
786		OUT_RING(I810_BUF_FREE);
787		OUT_RING(CMD_REPORT_HEAD);
788		OUT_RING(0);
789		ADVANCE_LP_RING();
790	}
791}
792
793static void i810_dma_dispatch_flip(struct drm_device *dev)
794{
795	drm_i810_private_t *dev_priv = dev->dev_private;
796	int pitch = dev_priv->pitch;
797	RING_LOCALS;
798
799	DRM_DEBUG("page=%d pfCurrentPage=%d\n",
800		  dev_priv->current_page,
801		  dev_priv->sarea_priv->pf_current_page);
802
803	i810_kernel_lost_context(dev);
804
805	BEGIN_LP_RING(2);
806	OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
807	OUT_RING(0);
808	ADVANCE_LP_RING();
809
810	BEGIN_LP_RING(I810_DEST_SETUP_SIZE + 2);
811	/* On i815 at least ASYNC is buggy */
812	/* pitch<<5 is from 11.2.8 p158,
813	   its the pitch / 8 then left shifted 8,
814	   so (pitch >> 3) << 8 */
815	OUT_RING(CMD_OP_FRONTBUFFER_INFO | (pitch << 5) /*| ASYNC_FLIP */ );
816	if (dev_priv->current_page == 0) {
817		OUT_RING(dev_priv->back_offset);
818		dev_priv->current_page = 1;
819	} else {
820		OUT_RING(dev_priv->front_offset);
821		dev_priv->current_page = 0;
822	}
823	OUT_RING(0);
824	ADVANCE_LP_RING();
825
826	BEGIN_LP_RING(2);
827	OUT_RING(CMD_OP_WAIT_FOR_EVENT | WAIT_FOR_PLANE_A_FLIP);
828	OUT_RING(0);
829	ADVANCE_LP_RING();
830
831	/* Increment the frame counter.  The client-side 3D driver must
832	 * throttle the framerate by waiting for this value before
833	 * performing the swapbuffer ioctl.
834	 */
835	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
836
837}
838
839static void i810_dma_quiescent(struct drm_device *dev)
840{
841	drm_i810_private_t *dev_priv = dev->dev_private;
842	RING_LOCALS;
843
844	i810_kernel_lost_context(dev);
845
846	BEGIN_LP_RING(4);
847	OUT_RING(INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE);
848	OUT_RING(CMD_REPORT_HEAD);
849	OUT_RING(0);
850	OUT_RING(0);
851	ADVANCE_LP_RING();
852
853	i810_wait_ring(dev, dev_priv->ring.Size - 8);
854}
855
856static void i810_flush_queue(struct drm_device *dev)
857{
858	drm_i810_private_t *dev_priv = dev->dev_private;
859	struct drm_device_dma *dma = dev->dma;
860	int i;
861	RING_LOCALS;
862
863	i810_kernel_lost_context(dev);
864
865	BEGIN_LP_RING(2);
866	OUT_RING(CMD_REPORT_HEAD);
867	OUT_RING(0);
868	ADVANCE_LP_RING();
869
870	i810_wait_ring(dev, dev_priv->ring.Size - 8);
871
872	for (i = 0; i < dma->buf_count; i++) {
873		struct drm_buf *buf = dma->buflist[i];
874		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
875
876		int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE,
877				   I810_BUF_FREE);
878
879		if (used == I810_BUF_HARDWARE)
880			DRM_DEBUG("reclaimed from HARDWARE\n");
881		if (used == I810_BUF_CLIENT)
882			DRM_DEBUG("still on client\n");
883	}
884
885	return;
886}
887
888/* Must be called with the lock held */
889void i810_driver_reclaim_buffers(struct drm_device *dev,
890				 struct drm_file *file_priv)
891{
892	struct drm_device_dma *dma = dev->dma;
893	int i;
894
895	if (!dma)
896		return;
897	if (!dev->dev_private)
898		return;
899	if (!dma->buflist)
900		return;
901
902	i810_flush_queue(dev);
903
904	for (i = 0; i < dma->buf_count; i++) {
905		struct drm_buf *buf = dma->buflist[i];
906		drm_i810_buf_priv_t *buf_priv = buf->dev_private;
907
908		if (buf->file_priv == file_priv && buf_priv) {
909			int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
910					   I810_BUF_FREE);
911
912			if (used == I810_BUF_CLIENT)
913				DRM_DEBUG("reclaimed from client\n");
914			if (buf_priv->currently_mapped == I810_BUF_MAPPED)
915				buf_priv->currently_mapped = I810_BUF_UNMAPPED;
916		}
917	}
918}
919
920static int i810_flush_ioctl(struct drm_device *dev, void *data,
921			    struct drm_file *file_priv)
922{
923	LOCK_TEST_WITH_RETURN(dev, file_priv);
924
925	i810_flush_queue(dev);
926	return 0;
927}
928
929static int i810_dma_vertex(struct drm_device *dev, void *data,
930			   struct drm_file *file_priv)
931{
932	struct drm_device_dma *dma = dev->dma;
933	drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
934	u32 *hw_status = dev_priv->hw_status_page;
935	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
936	    dev_priv->sarea_priv;
937	drm_i810_vertex_t *vertex = data;
938
939	LOCK_TEST_WITH_RETURN(dev, file_priv);
940
941	DRM_DEBUG("idx %d used %d discard %d\n",
942		  vertex->idx, vertex->used, vertex->discard);
943
944	if (vertex->idx < 0 || vertex->idx >= dma->buf_count)
945		return -EINVAL;
946
947	i810_dma_dispatch_vertex(dev,
948				 dma->buflist[vertex->idx],
949				 vertex->discard, vertex->used);
950
951	sarea_priv->last_enqueue = dev_priv->counter - 1;
952	sarea_priv->last_dispatch = (int)hw_status[5];
953
954	return 0;
955}
956
957static int i810_clear_bufs(struct drm_device *dev, void *data,
958			   struct drm_file *file_priv)
959{
960	drm_i810_clear_t *clear = data;
961
962	LOCK_TEST_WITH_RETURN(dev, file_priv);
963
964	/* GH: Someone's doing nasty things... */
965	if (!dev->dev_private)
966		return -EINVAL;
967
968	i810_dma_dispatch_clear(dev, clear->flags,
969				clear->clear_color, clear->clear_depth);
970	return 0;
971}
972
973static int i810_swap_bufs(struct drm_device *dev, void *data,
974			  struct drm_file *file_priv)
975{
976	DRM_DEBUG("\n");
977
978	LOCK_TEST_WITH_RETURN(dev, file_priv);
979
980	i810_dma_dispatch_swap(dev);
981	return 0;
982}
983
984static int i810_getage(struct drm_device *dev, void *data,
985		       struct drm_file *file_priv)
986{
987	drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
988	u32 *hw_status = dev_priv->hw_status_page;
989	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
990	    dev_priv->sarea_priv;
991
992	sarea_priv->last_dispatch = (int)hw_status[5];
993	return 0;
994}
995
996static int i810_getbuf(struct drm_device *dev, void *data,
997		       struct drm_file *file_priv)
998{
999	int retcode = 0;
1000	drm_i810_dma_t *d = data;
1001	drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
1002	u32 *hw_status = dev_priv->hw_status_page;
1003	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
1004	    dev_priv->sarea_priv;
1005
1006	LOCK_TEST_WITH_RETURN(dev, file_priv);
1007
1008	d->granted = 0;
1009
1010	retcode = i810_dma_get_buffer(dev, d, file_priv);
1011
1012	DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
1013		  task_pid_nr(current), retcode, d->granted);
1014
1015	sarea_priv->last_dispatch = (int)hw_status[5];
1016
1017	return retcode;
1018}
1019
1020static int i810_copybuf(struct drm_device *dev, void *data,
1021			struct drm_file *file_priv)
1022{
1023	/* Never copy - 2.4.x doesn't need it */
1024	return 0;
1025}
1026
1027static int i810_docopy(struct drm_device *dev, void *data,
1028			struct drm_file *file_priv)
1029{
1030	/* Never copy - 2.4.x doesn't need it */
1031	return 0;
1032}
1033
1034static void i810_dma_dispatch_mc(struct drm_device *dev, struct drm_buf *buf, int used,
1035				 unsigned int last_render)
1036{
1037	drm_i810_private_t *dev_priv = dev->dev_private;
1038	drm_i810_buf_priv_t *buf_priv = buf->dev_private;
1039	drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
1040	unsigned long address = (unsigned long)buf->bus_address;
1041	unsigned long start = address - dev->agp->base;
1042	int u;
1043	RING_LOCALS;
1044
1045	i810_kernel_lost_context(dev);
1046
1047	u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_HARDWARE);
1048	if (u != I810_BUF_CLIENT)
1049		DRM_DEBUG("MC found buffer that isn't mine!\n");
1050
1051	if (used < 0 || used > 4 * 1024)
1052		used = 0;
1053
1054	sarea_priv->dirty = 0x7f;
1055
1056	DRM_DEBUG("addr 0x%lx, used 0x%x\n", address, used);
1057
1058	dev_priv->counter++;
1059	DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter);
1060	DRM_DEBUG("start : %lx\n", start);
1061	DRM_DEBUG("used : %d\n", used);
1062	DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4);
1063
1064	if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
1065		if (used & 4) {
1066			*(u32 *) ((char *) buf_priv->virtual + used) = 0;
1067			used += 4;
1068		}
1069
1070		i810_unmap_buffer(buf);
1071	}
1072	BEGIN_LP_RING(4);
1073	OUT_RING(CMD_OP_BATCH_BUFFER);
1074	OUT_RING(start | BB1_PROTECTED);
1075	OUT_RING(start + used - 4);
1076	OUT_RING(0);
1077	ADVANCE_LP_RING();
1078
1079	BEGIN_LP_RING(8);
1080	OUT_RING(CMD_STORE_DWORD_IDX);
1081	OUT_RING(buf_priv->my_use_idx);
1082	OUT_RING(I810_BUF_FREE);
1083	OUT_RING(0);
1084
1085	OUT_RING(CMD_STORE_DWORD_IDX);
1086	OUT_RING(16);
1087	OUT_RING(last_render);
1088	OUT_RING(0);
1089	ADVANCE_LP_RING();
1090}
1091
1092static int i810_dma_mc(struct drm_device *dev, void *data,
1093		       struct drm_file *file_priv)
1094{
1095	struct drm_device_dma *dma = dev->dma;
1096	drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
1097	u32 *hw_status = dev_priv->hw_status_page;
1098	drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
1099	    dev_priv->sarea_priv;
1100	drm_i810_mc_t *mc = data;
1101
1102	LOCK_TEST_WITH_RETURN(dev, file_priv);
1103
1104	if (mc->idx >= dma->buf_count || mc->idx < 0)
1105		return -EINVAL;
1106
1107	i810_dma_dispatch_mc(dev, dma->buflist[mc->idx], mc->used,
1108			     mc->last_render);
1109
1110	sarea_priv->last_enqueue = dev_priv->counter - 1;
1111	sarea_priv->last_dispatch = (int)hw_status[5];
1112
1113	return 0;
1114}
1115
1116static int i810_rstatus(struct drm_device *dev, void *data,
1117			struct drm_file *file_priv)
1118{
1119	drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
1120
1121	return (int)(((u32 *) (dev_priv->hw_status_page))[4]);
1122}
1123
1124static int i810_ov0_info(struct drm_device *dev, void *data,
1125			 struct drm_file *file_priv)
1126{
1127	drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
1128	drm_i810_overlay_t *ov = data;
1129
1130	ov->offset = dev_priv->overlay_offset;
1131	ov->physical = dev_priv->overlay_physical;
1132
1133	return 0;
1134}
1135
1136static int i810_fstatus(struct drm_device *dev, void *data,
1137			struct drm_file *file_priv)
1138{
1139	drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
1140
1141	LOCK_TEST_WITH_RETURN(dev, file_priv);
1142	return I810_READ(0x30008);
1143}
1144
1145static int i810_ov0_flip(struct drm_device *dev, void *data,
1146			 struct drm_file *file_priv)
1147{
1148	drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
1149
1150	LOCK_TEST_WITH_RETURN(dev, file_priv);
1151
1152	/* Tell the overlay to update */
1153	I810_WRITE(0x30000, dev_priv->overlay_physical | 0x80000000);
1154
1155	return 0;
1156}
1157
1158/* Not sure why this isn't set all the time:
1159 */
1160static void i810_do_init_pageflip(struct drm_device *dev)
1161{
1162	drm_i810_private_t *dev_priv = dev->dev_private;
1163
1164	DRM_DEBUG("\n");
1165	dev_priv->page_flipping = 1;
1166	dev_priv->current_page = 0;
1167	dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
1168}
1169
1170static int i810_do_cleanup_pageflip(struct drm_device *dev)
1171{
1172	drm_i810_private_t *dev_priv = dev->dev_private;
1173
1174	DRM_DEBUG("\n");
1175	if (dev_priv->current_page != 0)
1176		i810_dma_dispatch_flip(dev);
1177
1178	dev_priv->page_flipping = 0;
1179	return 0;
1180}
1181
1182static int i810_flip_bufs(struct drm_device *dev, void *data,
1183			  struct drm_file *file_priv)
1184{
1185	drm_i810_private_t *dev_priv = dev->dev_private;
1186
1187	DRM_DEBUG("\n");
1188
1189	LOCK_TEST_WITH_RETURN(dev, file_priv);
1190
1191	if (!dev_priv->page_flipping)
1192		i810_do_init_pageflip(dev);
1193
1194	i810_dma_dispatch_flip(dev);
1195	return 0;
1196}
1197
1198int i810_driver_load(struct drm_device *dev, unsigned long flags)
1199{
1200	dev->agp = drm_agp_init(dev);
1201	if (dev->agp) {
1202		dev->agp->agp_mtrr = arch_phys_wc_add(
1203			dev->agp->agp_info.aper_base,
1204			dev->agp->agp_info.aper_size *
1205			1024 * 1024);
1206	}
1207
1208	/* Our userspace depends upon the agp mapping support. */
1209	if (!dev->agp)
1210		return -EINVAL;
1211
1212	pci_set_master(dev->pdev);
1213
1214	return 0;
1215}
1216
1217void i810_driver_lastclose(struct drm_device *dev)
1218{
1219	i810_dma_cleanup(dev);
1220}
1221
1222void i810_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
1223{
1224	if (dev->dev_private) {
1225		drm_i810_private_t *dev_priv = dev->dev_private;
1226		if (dev_priv->page_flipping)
1227			i810_do_cleanup_pageflip(dev);
1228	}
1229
1230	if (file_priv->master && file_priv->master->lock.hw_lock) {
1231		drm_legacy_idlelock_take(&file_priv->master->lock);
1232		i810_driver_reclaim_buffers(dev, file_priv);
1233		drm_legacy_idlelock_release(&file_priv->master->lock);
1234	} else {
1235		/* master disappeared, clean up stuff anyway and hope nothing
1236		 * goes wrong */
1237		i810_driver_reclaim_buffers(dev, file_priv);
1238	}
1239
1240}
1241
1242int i810_driver_dma_quiescent(struct drm_device *dev)
1243{
1244	i810_dma_quiescent(dev);
1245	return 0;
1246}
1247
1248const struct drm_ioctl_desc i810_ioctls[] = {
1249	DRM_IOCTL_DEF_DRV(I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
1250	DRM_IOCTL_DEF_DRV(I810_VERTEX, i810_dma_vertex, DRM_AUTH|DRM_UNLOCKED),
1251	DRM_IOCTL_DEF_DRV(I810_CLEAR, i810_clear_bufs, DRM_AUTH|DRM_UNLOCKED),
1252	DRM_IOCTL_DEF_DRV(I810_FLUSH, i810_flush_ioctl, DRM_AUTH|DRM_UNLOCKED),
1253	DRM_IOCTL_DEF_DRV(I810_GETAGE, i810_getage, DRM_AUTH|DRM_UNLOCKED),
1254	DRM_IOCTL_DEF_DRV(I810_GETBUF, i810_getbuf, DRM_AUTH|DRM_UNLOCKED),
1255	DRM_IOCTL_DEF_DRV(I810_SWAP, i810_swap_bufs, DRM_AUTH|DRM_UNLOCKED),
1256	DRM_IOCTL_DEF_DRV(I810_COPY, i810_copybuf, DRM_AUTH|DRM_UNLOCKED),
1257	DRM_IOCTL_DEF_DRV(I810_DOCOPY, i810_docopy, DRM_AUTH|DRM_UNLOCKED),
1258	DRM_IOCTL_DEF_DRV(I810_OV0INFO, i810_ov0_info, DRM_AUTH|DRM_UNLOCKED),
1259	DRM_IOCTL_DEF_DRV(I810_FSTATUS, i810_fstatus, DRM_AUTH|DRM_UNLOCKED),
1260	DRM_IOCTL_DEF_DRV(I810_OV0FLIP, i810_ov0_flip, DRM_AUTH|DRM_UNLOCKED),
1261	DRM_IOCTL_DEF_DRV(I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
1262	DRM_IOCTL_DEF_DRV(I810_RSTATUS, i810_rstatus, DRM_AUTH|DRM_UNLOCKED),
1263	DRM_IOCTL_DEF_DRV(I810_FLIP, i810_flip_bufs, DRM_AUTH|DRM_UNLOCKED),
1264};
1265
1266int i810_max_ioctl = ARRAY_SIZE(i810_ioctls);
1267