Linux-2.6.12-rc2
[safe/jmp/linux-2.6] / drivers / char / drm / i830_dma.c
1 /* i830_dma.c -- DMA support for the I830 -*- 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  *          Abraham vd Merwe <abraham@2d3d.co.za>
31  *
32  */
33
34 #include "drmP.h"
35 #include "drm.h"
36 #include "i830_drm.h"
37 #include "i830_drv.h"
38 #include <linux/interrupt.h>    /* For task queue support */
39 #include <linux/pagemap.h>      /* For FASTCALL on unlock_page() */
40 #include <linux/delay.h>
41 #include <asm/uaccess.h>
42
43 #define I830_BUF_FREE           2
44 #define I830_BUF_CLIENT         1
45 #define I830_BUF_HARDWARE       0
46
47 #define I830_BUF_UNMAPPED 0
48 #define I830_BUF_MAPPED   1
49
50 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2)
51 #define down_write down
52 #define up_write up
53 #endif
54
55 static drm_buf_t *i830_freelist_get(drm_device_t *dev)
56 {
57         drm_device_dma_t *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                 drm_buf_t *buf = dma->buflist[ i ];
65                 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
66                 /* In use is already a pointer */
67                 used = cmpxchg(buf_priv->in_use, I830_BUF_FREE, 
68                                I830_BUF_CLIENT);
69                 if(used == I830_BUF_FREE) {
70                         return buf;
71                 }
72         }
73         return NULL;
74 }
75
76 /* This should only be called if the buffer is not sent to the hardware
77  * yet, the hardware updates in use for us once its on the ring buffer.
78  */
79
80 static int i830_freelist_put(drm_device_t *dev, drm_buf_t *buf)
81 {
82         drm_i830_buf_priv_t *buf_priv = buf->dev_private;
83         int used;
84    
85         /* In use is already a pointer */
86         used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE);
87         if(used != I830_BUF_CLIENT) {
88                 DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
89                 return -EINVAL;
90         }
91    
92         return 0;
93 }
94
95 static struct file_operations i830_buffer_fops = {
96         .open    = drm_open,
97         .flush   = drm_flush,
98         .release = drm_release,
99         .ioctl   = drm_ioctl,
100         .mmap    = i830_mmap_buffers,
101         .fasync  = drm_fasync,
102 };
103
104 int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
105 {
106         drm_file_t          *priv         = filp->private_data;
107         drm_device_t        *dev;
108         drm_i830_private_t  *dev_priv;
109         drm_buf_t           *buf;
110         drm_i830_buf_priv_t *buf_priv;
111
112         lock_kernel();
113         dev      = priv->head->dev;
114         dev_priv = dev->dev_private;
115         buf      = dev_priv->mmap_buffer;
116         buf_priv = buf->dev_private;
117    
118         vma->vm_flags |= (VM_IO | VM_DONTCOPY);
119         vma->vm_file = filp;
120    
121         buf_priv->currently_mapped = I830_BUF_MAPPED;
122         unlock_kernel();
123
124         if (io_remap_pfn_range(vma, vma->vm_start,
125                              VM_OFFSET(vma) >> PAGE_SHIFT,
126                              vma->vm_end - vma->vm_start,
127                              vma->vm_page_prot)) return -EAGAIN;
128         return 0;
129 }
130
131 static int i830_map_buffer(drm_buf_t *buf, struct file *filp)
132 {
133         drm_file_t        *priv   = filp->private_data;
134         drm_device_t      *dev    = priv->head->dev;
135         drm_i830_buf_priv_t *buf_priv = buf->dev_private;
136         drm_i830_private_t *dev_priv = dev->dev_private;
137         struct file_operations *old_fops;
138         unsigned long virtual;
139         int retcode = 0;
140
141         if(buf_priv->currently_mapped == I830_BUF_MAPPED) return -EINVAL;
142
143         down_write( &current->mm->mmap_sem );
144         old_fops = filp->f_op;
145         filp->f_op = &i830_buffer_fops;
146         dev_priv->mmap_buffer = buf;
147         virtual = do_mmap(filp, 0, buf->total, PROT_READ|PROT_WRITE,
148                             MAP_SHARED, buf->bus_address);
149         dev_priv->mmap_buffer = NULL;
150         filp->f_op = old_fops;
151         if (IS_ERR((void *)virtual)) {          /* ugh */
152                 /* Real error */
153                 DRM_ERROR("mmap error\n");
154                 retcode = virtual;
155                 buf_priv->virtual = NULL;
156         } else {
157                 buf_priv->virtual = (void __user *)virtual;
158         }
159         up_write( &current->mm->mmap_sem );
160
161         return retcode;
162 }
163
164 static int i830_unmap_buffer(drm_buf_t *buf)
165 {
166         drm_i830_buf_priv_t *buf_priv = buf->dev_private;
167         int retcode = 0;
168
169         if(buf_priv->currently_mapped != I830_BUF_MAPPED) 
170                 return -EINVAL;
171
172         down_write(&current->mm->mmap_sem);
173         retcode = do_munmap(current->mm,
174                             (unsigned long)buf_priv->virtual,
175                             (size_t) buf->total);
176         up_write(&current->mm->mmap_sem);
177
178         buf_priv->currently_mapped = I830_BUF_UNMAPPED;
179         buf_priv->virtual = NULL;
180
181         return retcode;
182 }
183
184 static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d, 
185                                struct file *filp)
186 {
187         drm_buf_t         *buf;
188         drm_i830_buf_priv_t *buf_priv;
189         int retcode = 0;
190
191         buf = i830_freelist_get(dev);
192         if (!buf) {
193                 retcode = -ENOMEM;
194                 DRM_DEBUG("retcode=%d\n", retcode);
195                 return retcode;
196         }
197    
198         retcode = i830_map_buffer(buf, filp);
199         if(retcode) {
200                 i830_freelist_put(dev, buf);
201                 DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
202                 return retcode;
203         }
204         buf->filp = filp;
205         buf_priv = buf->dev_private;    
206         d->granted = 1;
207         d->request_idx = buf->idx;
208         d->request_size = buf->total;
209         d->virtual = buf_priv->virtual;
210
211         return retcode;
212 }
213
214 static int i830_dma_cleanup(drm_device_t *dev)
215 {
216         drm_device_dma_t *dma = dev->dma;
217
218         /* Make sure interrupts are disabled here because the uninstall ioctl
219          * may not have been called from userspace and after dev_private
220          * is freed, it's too late.
221          */
222         if ( dev->irq_enabled ) drm_irq_uninstall(dev);
223
224         if (dev->dev_private) {
225                 int i;
226                 drm_i830_private_t *dev_priv = 
227                         (drm_i830_private_t *) dev->dev_private;
228            
229                 if (dev_priv->ring.virtual_start) {
230                         drm_ioremapfree((void *) dev_priv->ring.virtual_start,
231                                          dev_priv->ring.Size, dev);
232                 }
233                 if (dev_priv->hw_status_page) {
234                         pci_free_consistent(dev->pdev, PAGE_SIZE,
235                                             dev_priv->hw_status_page,
236                                             dev_priv->dma_status_page);
237                         /* Need to rewrite hardware status page */
238                         I830_WRITE(0x02080, 0x1ffff000);
239                 }
240
241                 drm_free(dev->dev_private, sizeof(drm_i830_private_t), 
242                          DRM_MEM_DRIVER);
243                 dev->dev_private = NULL;
244
245                 for (i = 0; i < dma->buf_count; i++) {
246                         drm_buf_t *buf = dma->buflist[ i ];
247                         drm_i830_buf_priv_t *buf_priv = buf->dev_private;
248                         if ( buf_priv->kernel_virtual && buf->total )
249                                 drm_ioremapfree(buf_priv->kernel_virtual, buf->total, dev);
250                 }
251         }
252         return 0;
253 }
254
255 int i830_wait_ring(drm_device_t *dev, int n, const char *caller)
256 {
257         drm_i830_private_t *dev_priv = dev->dev_private;
258         drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
259         int iters = 0;
260         unsigned long end;
261         unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
262
263         end = jiffies + (HZ*3);
264         while (ring->space < n) {       
265                 ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
266                 ring->space = ring->head - (ring->tail+8);
267                 if (ring->space < 0) ring->space += ring->Size;
268            
269                 if (ring->head != last_head) {
270                         end = jiffies + (HZ*3);
271                         last_head = ring->head;
272                 }
273           
274                 iters++;
275                 if(time_before(end, jiffies)) {
276                         DRM_ERROR("space: %d wanted %d\n", ring->space, n);
277                         DRM_ERROR("lockup\n");
278                         goto out_wait_ring;
279                 }
280                 udelay(1);
281                 dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
282         }
283
284 out_wait_ring:   
285         return iters;
286 }
287
288 static void i830_kernel_lost_context(drm_device_t *dev)
289 {
290         drm_i830_private_t *dev_priv = dev->dev_private;
291         drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
292       
293         ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
294         ring->tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
295         ring->space = ring->head - (ring->tail+8);
296         if (ring->space < 0) ring->space += ring->Size;
297
298         if (ring->head == ring->tail)
299                 dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY;
300 }
301
302 static int i830_freelist_init(drm_device_t *dev, drm_i830_private_t *dev_priv)
303 {
304         drm_device_dma_t *dma = dev->dma;
305         int my_idx = 36;
306         u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
307         int i;
308
309         if(dma->buf_count > 1019) {
310                 /* Not enough space in the status page for the freelist */
311                 return -EINVAL;
312         }
313
314         for (i = 0; i < dma->buf_count; i++) {
315                 drm_buf_t *buf = dma->buflist[ i ];
316                 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
317
318                 buf_priv->in_use = hw_status++;
319                 buf_priv->my_use_idx = my_idx;
320                 my_idx += 4;
321
322                 *buf_priv->in_use = I830_BUF_FREE;
323
324                 buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, 
325                                                         buf->total, dev);
326         }
327         return 0;
328 }
329
330 static int i830_dma_initialize(drm_device_t *dev, 
331                                drm_i830_private_t *dev_priv,
332                                drm_i830_init_t *init)
333 {
334         struct list_head *list;
335
336         memset(dev_priv, 0, sizeof(drm_i830_private_t));
337
338         list_for_each(list, &dev->maplist->head) {
339                 drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
340                 if( r_list->map &&
341                     r_list->map->type == _DRM_SHM &&
342                     r_list->map->flags & _DRM_CONTAINS_LOCK ) {
343                         dev_priv->sarea_map = r_list->map;
344                         break;
345                 }
346         }
347
348         if(!dev_priv->sarea_map) {
349                 dev->dev_private = (void *)dev_priv;
350                 i830_dma_cleanup(dev);
351                 DRM_ERROR("can not find sarea!\n");
352                 return -EINVAL;
353         }
354         dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
355         if(!dev_priv->mmio_map) {
356                 dev->dev_private = (void *)dev_priv;
357                 i830_dma_cleanup(dev);
358                 DRM_ERROR("can not find mmio map!\n");
359                 return -EINVAL;
360         }
361         dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
362         if(!dev->agp_buffer_map) {
363                 dev->dev_private = (void *)dev_priv;
364                 i830_dma_cleanup(dev);
365                 DRM_ERROR("can not find dma buffer map!\n");
366                 return -EINVAL;
367         }
368
369         dev_priv->sarea_priv = (drm_i830_sarea_t *)
370                 ((u8 *)dev_priv->sarea_map->handle +
371                  init->sarea_priv_offset);
372
373         dev_priv->ring.Start = init->ring_start;
374         dev_priv->ring.End = init->ring_end;
375         dev_priv->ring.Size = init->ring_size;
376
377         dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + 
378                                                     init->ring_start, 
379                                                     init->ring_size, dev);
380
381         if (dev_priv->ring.virtual_start == NULL) {
382                 dev->dev_private = (void *) dev_priv;
383                 i830_dma_cleanup(dev);
384                 DRM_ERROR("can not ioremap virtual address for"
385                           " ring buffer\n");
386                 return -ENOMEM;
387         }
388
389         dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
390    
391         dev_priv->w = init->w;
392         dev_priv->h = init->h;
393         dev_priv->pitch = init->pitch;
394         dev_priv->back_offset = init->back_offset;
395         dev_priv->depth_offset = init->depth_offset;
396         dev_priv->front_offset = init->front_offset;
397
398         dev_priv->front_di1 = init->front_offset | init->pitch_bits;
399         dev_priv->back_di1 = init->back_offset | init->pitch_bits;
400         dev_priv->zi1 = init->depth_offset | init->pitch_bits;
401
402         DRM_DEBUG("front_di1 %x\n",    dev_priv->front_di1);
403         DRM_DEBUG("back_offset %x\n", dev_priv->back_offset);
404         DRM_DEBUG("back_di1 %x\n",    dev_priv->back_di1);
405         DRM_DEBUG("pitch_bits %x\n",    init->pitch_bits);
406
407         dev_priv->cpp = init->cpp;
408         /* We are using separate values as placeholders for mechanisms for
409          * private backbuffer/depthbuffer usage.
410          */
411
412         dev_priv->back_pitch = init->back_pitch;
413         dev_priv->depth_pitch = init->depth_pitch;
414         dev_priv->do_boxes = 0;
415         dev_priv->use_mi_batchbuffer_start = 0;
416
417         /* Program Hardware Status Page */
418         dev_priv->hw_status_page =
419                 pci_alloc_consistent(dev->pdev, PAGE_SIZE,
420                                                 &dev_priv->dma_status_page);
421         if (!dev_priv->hw_status_page) {
422                 dev->dev_private = (void *)dev_priv;
423                 i830_dma_cleanup(dev);
424                 DRM_ERROR("Can not allocate hardware status page\n");
425                 return -ENOMEM;
426         }
427         memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
428         DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
429    
430         I830_WRITE(0x02080, dev_priv->dma_status_page);
431         DRM_DEBUG("Enabled hardware status page\n");
432    
433         /* Now we need to init our freelist */
434         if(i830_freelist_init(dev, dev_priv) != 0) {
435                 dev->dev_private = (void *)dev_priv;
436                 i830_dma_cleanup(dev);
437                 DRM_ERROR("Not enough space in the status page for"
438                           " the freelist\n");
439                 return -ENOMEM;
440         }
441         dev->dev_private = (void *)dev_priv;
442
443         return 0;
444 }
445
446 static int i830_dma_init(struct inode *inode, struct file *filp,
447                   unsigned int cmd, unsigned long arg)
448 {
449         drm_file_t *priv = filp->private_data;
450         drm_device_t *dev = priv->head->dev;
451         drm_i830_private_t *dev_priv;
452         drm_i830_init_t init;
453         int retcode = 0;
454         
455         if (copy_from_user(&init, (void * __user) arg, sizeof(init)))
456                 return -EFAULT;
457         
458         switch(init.func) {
459                 case I830_INIT_DMA:
460                         dev_priv = drm_alloc(sizeof(drm_i830_private_t), 
461                                               DRM_MEM_DRIVER);
462                         if(dev_priv == NULL) return -ENOMEM;
463                         retcode = i830_dma_initialize(dev, dev_priv, &init);
464                 break;
465                 case I830_CLEANUP_DMA:
466                         retcode = i830_dma_cleanup(dev);
467                 break;
468                 default:
469                         retcode = -EINVAL;
470                 break;
471         }
472    
473         return retcode;
474 }
475
476 #define GFX_OP_STIPPLE           ((0x3<<29)|(0x1d<<24)|(0x83<<16))
477 #define ST1_ENABLE               (1<<16)
478 #define ST1_MASK                 (0xffff)
479
480 /* Most efficient way to verify state for the i830 is as it is
481  * emitted.  Non-conformant state is silently dropped.
482  */
483 static void i830EmitContextVerified( drm_device_t *dev,
484                                      unsigned int *code )
485 {
486         drm_i830_private_t *dev_priv = dev->dev_private;
487         int i, j = 0;
488         unsigned int tmp;
489         RING_LOCALS;
490
491         BEGIN_LP_RING( I830_CTX_SETUP_SIZE + 4 );
492
493         for ( i = 0 ; i < I830_CTXREG_BLENDCOLR0 ; i++ ) {
494                 tmp = code[i];
495                 if ((tmp & (7<<29)) == CMD_3D &&
496                     (tmp & (0x1f<<24)) < (0x1d<<24)) {
497                         OUT_RING( tmp ); 
498                         j++;
499                 } else {
500                         DRM_ERROR("Skipping %d\n", i);
501                 }
502         }
503
504         OUT_RING( STATE3D_CONST_BLEND_COLOR_CMD ); 
505         OUT_RING( code[I830_CTXREG_BLENDCOLR] ); 
506         j += 2;
507
508         for ( i = I830_CTXREG_VF ; i < I830_CTXREG_MCSB0 ; i++ ) {
509                 tmp = code[i];
510                 if ((tmp & (7<<29)) == CMD_3D &&
511                     (tmp & (0x1f<<24)) < (0x1d<<24)) {
512                         OUT_RING( tmp ); 
513                         j++;
514                 } else {
515                         DRM_ERROR("Skipping %d\n", i);
516                 }
517         }
518
519         OUT_RING( STATE3D_MAP_COORD_SETBIND_CMD ); 
520         OUT_RING( code[I830_CTXREG_MCSB1] ); 
521         j += 2;
522
523         if (j & 1) 
524                 OUT_RING( 0 ); 
525
526         ADVANCE_LP_RING();
527 }
528
529 static void i830EmitTexVerified( drm_device_t *dev, unsigned int *code ) 
530 {
531         drm_i830_private_t *dev_priv = dev->dev_private;
532         int i, j = 0;
533         unsigned int tmp;
534         RING_LOCALS;
535
536         if (code[I830_TEXREG_MI0] == GFX_OP_MAP_INFO ||
537             (code[I830_TEXREG_MI0] & ~(0xf*LOAD_TEXTURE_MAP0)) == 
538             (STATE3D_LOAD_STATE_IMMEDIATE_2|4)) {
539
540                 BEGIN_LP_RING( I830_TEX_SETUP_SIZE );
541
542                 OUT_RING( code[I830_TEXREG_MI0] ); /* TM0LI */
543                 OUT_RING( code[I830_TEXREG_MI1] ); /* TM0S0 */
544                 OUT_RING( code[I830_TEXREG_MI2] ); /* TM0S1 */
545                 OUT_RING( code[I830_TEXREG_MI3] ); /* TM0S2 */
546                 OUT_RING( code[I830_TEXREG_MI4] ); /* TM0S3 */
547                 OUT_RING( code[I830_TEXREG_MI5] ); /* TM0S4 */
548                 
549                 for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) {
550                         tmp = code[i];
551                         OUT_RING( tmp ); 
552                         j++;
553                 } 
554
555                 if (j & 1) 
556                         OUT_RING( 0 ); 
557
558                 ADVANCE_LP_RING();
559         }
560         else
561                 printk("rejected packet %x\n", code[0]);
562 }
563
564 static void i830EmitTexBlendVerified( drm_device_t *dev, 
565                                       unsigned int *code,
566                                       unsigned int num)
567 {
568         drm_i830_private_t *dev_priv = dev->dev_private;
569         int i, j = 0;
570         unsigned int tmp;
571         RING_LOCALS;
572
573         if (!num)
574                 return;
575
576         BEGIN_LP_RING( num + 1 );
577
578         for ( i = 0 ; i < num ; i++ ) {
579                 tmp = code[i];
580                 OUT_RING( tmp );
581                 j++;
582         }
583
584         if (j & 1) 
585                 OUT_RING( 0 ); 
586
587         ADVANCE_LP_RING();
588 }
589
590 static void i830EmitTexPalette( drm_device_t *dev,
591                                 unsigned int *palette,
592                                 int number,
593                                 int is_shared )
594 {
595         drm_i830_private_t *dev_priv = dev->dev_private;
596         int i;
597         RING_LOCALS;
598
599         return;
600
601         BEGIN_LP_RING( 258 );
602
603         if(is_shared == 1) {
604                 OUT_RING(CMD_OP_MAP_PALETTE_LOAD |
605                          MAP_PALETTE_NUM(0) |
606                          MAP_PALETTE_BOTH);
607         } else {
608                 OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number));
609         }
610         for(i = 0; i < 256; i++) {
611                 OUT_RING(palette[i]);
612         }
613         OUT_RING(0);
614         /* KW:  WHERE IS THE ADVANCE_LP_RING?  This is effectively a noop! 
615          */
616 }
617
618 /* Need to do some additional checking when setting the dest buffer.
619  */
620 static void i830EmitDestVerified( drm_device_t *dev, 
621                                   unsigned int *code ) 
622 {       
623         drm_i830_private_t *dev_priv = dev->dev_private;
624         unsigned int tmp;
625         RING_LOCALS;
626
627         BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 10 );
628
629
630         tmp = code[I830_DESTREG_CBUFADDR];
631         if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
632                 if (((int)outring) & 8) {
633                         OUT_RING(0);
634                         OUT_RING(0);
635                 }
636
637                 OUT_RING( CMD_OP_DESTBUFFER_INFO );
638                 OUT_RING( BUF_3D_ID_COLOR_BACK | 
639                           BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) |
640                           BUF_3D_USE_FENCE);
641                 OUT_RING( tmp );
642                 OUT_RING( 0 );
643
644                 OUT_RING( CMD_OP_DESTBUFFER_INFO );
645                 OUT_RING( BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE | 
646                           BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
647                 OUT_RING( dev_priv->zi1 );
648                 OUT_RING( 0 );
649         } else {
650                 DRM_ERROR("bad di1 %x (allow %x or %x)\n",
651                           tmp, dev_priv->front_di1, dev_priv->back_di1);
652         }
653
654         /* invarient:
655          */
656
657
658         OUT_RING( GFX_OP_DESTBUFFER_VARS );
659         OUT_RING( code[I830_DESTREG_DV1] );
660
661         OUT_RING( GFX_OP_DRAWRECT_INFO );
662         OUT_RING( code[I830_DESTREG_DR1] );
663         OUT_RING( code[I830_DESTREG_DR2] );
664         OUT_RING( code[I830_DESTREG_DR3] );
665         OUT_RING( code[I830_DESTREG_DR4] );
666
667         /* Need to verify this */
668         tmp = code[I830_DESTREG_SENABLE];
669         if((tmp & ~0x3) == GFX_OP_SCISSOR_ENABLE) {
670                 OUT_RING( tmp );
671         } else {
672                 DRM_ERROR("bad scissor enable\n");
673                 OUT_RING( 0 );
674         }
675
676         OUT_RING( GFX_OP_SCISSOR_RECT );
677         OUT_RING( code[I830_DESTREG_SR1] );
678         OUT_RING( code[I830_DESTREG_SR2] );
679         OUT_RING( 0 );
680
681         ADVANCE_LP_RING();
682 }
683
684 static void i830EmitStippleVerified( drm_device_t *dev, 
685                                      unsigned int *code ) 
686 {
687         drm_i830_private_t *dev_priv = dev->dev_private;
688         RING_LOCALS;
689
690         BEGIN_LP_RING( 2 );
691         OUT_RING( GFX_OP_STIPPLE );
692         OUT_RING( code[1] );
693         ADVANCE_LP_RING();      
694 }
695
696
697 static void i830EmitState( drm_device_t *dev )
698 {
699         drm_i830_private_t *dev_priv = dev->dev_private;
700         drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
701         unsigned int dirty = sarea_priv->dirty;
702
703         DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
704
705         if (dirty & I830_UPLOAD_BUFFERS) {
706                 i830EmitDestVerified( dev, sarea_priv->BufferState );
707                 sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS;
708         }
709
710         if (dirty & I830_UPLOAD_CTX) {
711                 i830EmitContextVerified( dev, sarea_priv->ContextState );
712                 sarea_priv->dirty &= ~I830_UPLOAD_CTX;
713         }
714
715         if (dirty & I830_UPLOAD_TEX0) {
716                 i830EmitTexVerified( dev, sarea_priv->TexState[0] );
717                 sarea_priv->dirty &= ~I830_UPLOAD_TEX0;
718         }
719
720         if (dirty & I830_UPLOAD_TEX1) {
721                 i830EmitTexVerified( dev, sarea_priv->TexState[1] );
722                 sarea_priv->dirty &= ~I830_UPLOAD_TEX1;
723         }
724
725         if (dirty & I830_UPLOAD_TEXBLEND0) {
726                 i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[0],
727                                 sarea_priv->TexBlendStateWordsUsed[0]);
728                 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND0;
729         }
730
731         if (dirty & I830_UPLOAD_TEXBLEND1) {
732                 i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[1],
733                                 sarea_priv->TexBlendStateWordsUsed[1]);
734                 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND1;
735         }
736
737         if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) {
738                 i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
739         } else {
740                 if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
741                         i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
742                         sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
743                 }
744                 if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
745                         i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
746                         sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
747                 }
748
749                 /* 1.3:
750                  */
751 #if 0
752                 if (dirty & I830_UPLOAD_TEX_PALETTE_N(2)) {
753                         i830EmitTexPalette(dev, sarea_priv->Palette2[0], 0, 0);
754                         sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
755                 }
756                 if (dirty & I830_UPLOAD_TEX_PALETTE_N(3)) {
757                         i830EmitTexPalette(dev, sarea_priv->Palette2[1], 1, 0);
758                         sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
759                 }
760 #endif
761         }
762
763         /* 1.3:
764          */
765         if (dirty & I830_UPLOAD_STIPPLE) {
766                 i830EmitStippleVerified( dev, 
767                                          sarea_priv->StippleState);
768                 sarea_priv->dirty &= ~I830_UPLOAD_STIPPLE;
769         }
770
771         if (dirty & I830_UPLOAD_TEX2) {
772                 i830EmitTexVerified( dev, sarea_priv->TexState2 );
773                 sarea_priv->dirty &= ~I830_UPLOAD_TEX2;
774         }
775
776         if (dirty & I830_UPLOAD_TEX3) {
777                 i830EmitTexVerified( dev, sarea_priv->TexState3 );
778                 sarea_priv->dirty &= ~I830_UPLOAD_TEX3;
779         }
780
781
782         if (dirty & I830_UPLOAD_TEXBLEND2) {
783                 i830EmitTexBlendVerified( 
784                         dev, 
785                         sarea_priv->TexBlendState2,
786                         sarea_priv->TexBlendStateWordsUsed2);
787
788                 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND2;
789         }
790
791         if (dirty & I830_UPLOAD_TEXBLEND3) {
792                 i830EmitTexBlendVerified( 
793                         dev, 
794                         sarea_priv->TexBlendState3,
795                         sarea_priv->TexBlendStateWordsUsed3);
796                 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND3;
797         }
798 }
799
800 /* ================================================================
801  * Performance monitoring functions
802  */
803
804 static void i830_fill_box( drm_device_t *dev,
805                            int x, int y, int w, int h,
806                            int r, int g, int b )
807 {
808         drm_i830_private_t *dev_priv = dev->dev_private;
809         u32 color;
810         unsigned int BR13, CMD;
811         RING_LOCALS;
812
813         BR13 = (0xF0 << 16) | (dev_priv->pitch * dev_priv->cpp) | (1<<24);
814         CMD = XY_COLOR_BLT_CMD;
815         x += dev_priv->sarea_priv->boxes[0].x1;
816         y += dev_priv->sarea_priv->boxes[0].y1;
817
818         if (dev_priv->cpp == 4) {
819                 BR13 |= (1<<25);
820                 CMD |= (XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
821                 color = (((0xff) << 24) | (r << 16) | (g <<  8) | b);   
822         } else {
823                 color = (((r & 0xf8) << 8) |
824                          ((g & 0xfc) << 3) |
825                          ((b & 0xf8) >> 3));
826         }
827
828         BEGIN_LP_RING( 6 );         
829         OUT_RING( CMD );
830         OUT_RING( BR13 );
831         OUT_RING( (y << 16) | x );
832         OUT_RING( ((y+h) << 16) | (x+w) );
833
834         if ( dev_priv->current_page == 1 ) { 
835                 OUT_RING( dev_priv->front_offset );
836         } else {         
837                 OUT_RING( dev_priv->back_offset );
838         } 
839
840         OUT_RING( color );
841         ADVANCE_LP_RING();
842 }
843
844 static void i830_cp_performance_boxes( drm_device_t *dev )
845 {
846         drm_i830_private_t *dev_priv = dev->dev_private;
847
848         /* Purple box for page flipping
849          */
850         if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_FLIP ) 
851                 i830_fill_box( dev, 4, 4, 8, 8, 255, 0, 255 );
852
853         /* Red box if we have to wait for idle at any point
854          */
855         if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_WAIT ) 
856                 i830_fill_box( dev, 16, 4, 8, 8, 255, 0, 0 );
857
858         /* Blue box: lost context?
859          */
860         if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_LOST_CONTEXT ) 
861                 i830_fill_box( dev, 28, 4, 8, 8, 0, 0, 255 );
862
863         /* Yellow box for texture swaps
864          */
865         if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_TEXTURE_LOAD ) 
866                 i830_fill_box( dev, 40, 4, 8, 8, 255, 255, 0 );
867
868         /* Green box if hardware never idles (as far as we can tell)
869          */
870         if ( !(dev_priv->sarea_priv->perf_boxes & I830_BOX_RING_EMPTY) ) 
871                 i830_fill_box( dev, 64, 4, 8, 8, 0, 255, 0 );
872
873
874         /* Draw bars indicating number of buffers allocated 
875          * (not a great measure, easily confused)
876          */
877         if (dev_priv->dma_used) {
878                 int bar = dev_priv->dma_used / 10240;
879                 if (bar > 100) bar = 100;
880                 if (bar < 1) bar = 1;
881                 i830_fill_box( dev, 4, 16, bar, 4, 196, 128, 128 );
882                 dev_priv->dma_used = 0;
883         }
884
885         dev_priv->sarea_priv->perf_boxes = 0;
886 }
887
888 static void i830_dma_dispatch_clear( drm_device_t *dev, int flags, 
889                                     unsigned int clear_color,
890                                     unsigned int clear_zval,
891                                     unsigned int clear_depthmask)
892 {
893         drm_i830_private_t *dev_priv = dev->dev_private;
894         drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
895         int nbox = sarea_priv->nbox;
896         drm_clip_rect_t *pbox = sarea_priv->boxes;
897         int pitch = dev_priv->pitch;
898         int cpp = dev_priv->cpp;
899         int i;
900         unsigned int BR13, CMD, D_CMD;
901         RING_LOCALS;
902
903
904         if ( dev_priv->current_page == 1 ) {
905                 unsigned int tmp = flags;
906
907                 flags &= ~(I830_FRONT | I830_BACK);
908                 if ( tmp & I830_FRONT ) flags |= I830_BACK;
909                 if ( tmp & I830_BACK )  flags |= I830_FRONT;
910         }
911
912         i830_kernel_lost_context(dev);
913
914         switch(cpp) {
915         case 2: 
916                 BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
917                 D_CMD = CMD = XY_COLOR_BLT_CMD;
918                 break;
919         case 4:
920                 BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25);
921                 CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA | 
922                        XY_COLOR_BLT_WRITE_RGB);
923                 D_CMD = XY_COLOR_BLT_CMD;
924                 if(clear_depthmask & 0x00ffffff)
925                         D_CMD |= XY_COLOR_BLT_WRITE_RGB;
926                 if(clear_depthmask & 0xff000000)
927                         D_CMD |= XY_COLOR_BLT_WRITE_ALPHA;
928                 break;
929         default:
930                 BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
931                 D_CMD = CMD = XY_COLOR_BLT_CMD;
932                 break;
933         }
934
935         if (nbox > I830_NR_SAREA_CLIPRECTS)
936                 nbox = I830_NR_SAREA_CLIPRECTS;
937
938         for (i = 0 ; i < nbox ; i++, pbox++) {
939                 if (pbox->x1 > pbox->x2 ||
940                     pbox->y1 > pbox->y2 ||
941                     pbox->x2 > dev_priv->w ||
942                     pbox->y2 > dev_priv->h)
943                         continue;
944
945                 if ( flags & I830_FRONT ) {         
946                         DRM_DEBUG("clear front\n");
947                         BEGIN_LP_RING( 6 );         
948                         OUT_RING( CMD );
949                         OUT_RING( BR13 );
950                         OUT_RING( (pbox->y1 << 16) | pbox->x1 );
951                         OUT_RING( (pbox->y2 << 16) | pbox->x2 );
952                         OUT_RING( dev_priv->front_offset );
953                         OUT_RING( clear_color );
954                         ADVANCE_LP_RING();
955                 }
956
957                 if ( flags & I830_BACK ) {
958                         DRM_DEBUG("clear back\n");
959                         BEGIN_LP_RING( 6 );         
960                         OUT_RING( CMD );
961                         OUT_RING( BR13 );
962                         OUT_RING( (pbox->y1 << 16) | pbox->x1 );
963                         OUT_RING( (pbox->y2 << 16) | pbox->x2 );
964                         OUT_RING( dev_priv->back_offset );
965                         OUT_RING( clear_color );
966                         ADVANCE_LP_RING();
967                 }
968
969                 if ( flags & I830_DEPTH ) {
970                         DRM_DEBUG("clear depth\n");
971                         BEGIN_LP_RING( 6 );
972                         OUT_RING( D_CMD );
973                         OUT_RING( BR13 );
974                         OUT_RING( (pbox->y1 << 16) | pbox->x1 );
975                         OUT_RING( (pbox->y2 << 16) | pbox->x2 );
976                         OUT_RING( dev_priv->depth_offset );
977                         OUT_RING( clear_zval );
978                         ADVANCE_LP_RING();
979                 }
980         }
981 }
982
983 static void i830_dma_dispatch_swap( drm_device_t *dev )
984 {
985         drm_i830_private_t *dev_priv = dev->dev_private;
986         drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
987         int nbox = sarea_priv->nbox;
988         drm_clip_rect_t *pbox = sarea_priv->boxes;
989         int pitch = dev_priv->pitch;
990         int cpp = dev_priv->cpp;
991         int i;
992         unsigned int CMD, BR13;
993         RING_LOCALS;
994
995         DRM_DEBUG("swapbuffers\n");
996
997         i830_kernel_lost_context(dev);
998
999         if (dev_priv->do_boxes)
1000                 i830_cp_performance_boxes( dev );
1001
1002         switch(cpp) {
1003         case 2: 
1004                 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
1005                 CMD = XY_SRC_COPY_BLT_CMD;
1006                 break;
1007         case 4:
1008                 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24) | (1<<25);
1009                 CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
1010                        XY_SRC_COPY_BLT_WRITE_RGB);
1011                 break;
1012         default:
1013                 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
1014                 CMD = XY_SRC_COPY_BLT_CMD;
1015                 break;
1016         }
1017
1018
1019         if (nbox > I830_NR_SAREA_CLIPRECTS)
1020                 nbox = I830_NR_SAREA_CLIPRECTS;
1021
1022         for (i = 0 ; i < nbox; i++, pbox++) 
1023         {
1024                 if (pbox->x1 > pbox->x2 ||
1025                     pbox->y1 > pbox->y2 ||
1026                     pbox->x2 > dev_priv->w ||
1027                     pbox->y2 > dev_priv->h)
1028                         continue;
1029  
1030                 DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
1031                           pbox->x1, pbox->y1,
1032                           pbox->x2, pbox->y2);
1033
1034                 BEGIN_LP_RING( 8 );
1035                 OUT_RING( CMD );
1036                 OUT_RING( BR13 );
1037                 OUT_RING( (pbox->y1 << 16) | pbox->x1 );
1038                 OUT_RING( (pbox->y2 << 16) | pbox->x2 );
1039
1040                 if (dev_priv->current_page == 0) 
1041                         OUT_RING( dev_priv->front_offset );
1042                 else
1043                         OUT_RING( dev_priv->back_offset );                      
1044
1045                 OUT_RING( (pbox->y1 << 16) | pbox->x1 );
1046                 OUT_RING( BR13 & 0xffff );
1047
1048                 if (dev_priv->current_page == 0) 
1049                         OUT_RING( dev_priv->back_offset );                      
1050                 else
1051                         OUT_RING( dev_priv->front_offset );
1052
1053                 ADVANCE_LP_RING();
1054         }
1055 }
1056
1057 static void i830_dma_dispatch_flip( drm_device_t *dev )
1058 {
1059         drm_i830_private_t *dev_priv = dev->dev_private;
1060         RING_LOCALS;
1061
1062         DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n", 
1063                    __FUNCTION__, 
1064                    dev_priv->current_page,
1065                    dev_priv->sarea_priv->pf_current_page);
1066
1067         i830_kernel_lost_context(dev);
1068
1069         if (dev_priv->do_boxes) {
1070                 dev_priv->sarea_priv->perf_boxes |= I830_BOX_FLIP;
1071                 i830_cp_performance_boxes( dev );
1072         }
1073
1074
1075         BEGIN_LP_RING( 2 );
1076         OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); 
1077         OUT_RING( 0 );
1078         ADVANCE_LP_RING();
1079
1080         BEGIN_LP_RING( 6 );
1081         OUT_RING( CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP );     
1082         OUT_RING( 0 );
1083         if ( dev_priv->current_page == 0 ) {
1084                 OUT_RING( dev_priv->back_offset );
1085                 dev_priv->current_page = 1;
1086         } else {
1087                 OUT_RING( dev_priv->front_offset );
1088                 dev_priv->current_page = 0;
1089         }
1090         OUT_RING(0);
1091         ADVANCE_LP_RING();
1092
1093
1094         BEGIN_LP_RING( 2 );
1095         OUT_RING( MI_WAIT_FOR_EVENT |
1096                   MI_WAIT_FOR_PLANE_A_FLIP );
1097         OUT_RING( 0 );
1098         ADVANCE_LP_RING();
1099         
1100
1101         dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
1102 }
1103
1104 static void i830_dma_dispatch_vertex(drm_device_t *dev, 
1105                                      drm_buf_t *buf,
1106                                      int discard,
1107                                      int used)
1108 {
1109         drm_i830_private_t *dev_priv = dev->dev_private;
1110         drm_i830_buf_priv_t *buf_priv = buf->dev_private;
1111         drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
1112         drm_clip_rect_t *box = sarea_priv->boxes;
1113         int nbox = sarea_priv->nbox;
1114         unsigned long address = (unsigned long)buf->bus_address;
1115         unsigned long start = address - dev->agp->base;     
1116         int i = 0, u;
1117         RING_LOCALS;
1118
1119         i830_kernel_lost_context(dev);
1120
1121         if (nbox > I830_NR_SAREA_CLIPRECTS) 
1122                 nbox = I830_NR_SAREA_CLIPRECTS;
1123
1124         if (discard) {
1125                 u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, 
1126                             I830_BUF_HARDWARE);
1127                 if(u != I830_BUF_CLIENT) {
1128                         DRM_DEBUG("xxxx 2\n");
1129                 }
1130         }
1131
1132         if (used > 4*1023) 
1133                 used = 0;
1134
1135         if (sarea_priv->dirty)
1136            i830EmitState( dev );
1137
1138         DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", 
1139                   address, used, nbox);
1140
1141         dev_priv->counter++;
1142         DRM_DEBUG(  "dispatch counter : %ld\n", dev_priv->counter);
1143         DRM_DEBUG(  "i830_dma_dispatch\n");
1144         DRM_DEBUG(  "start : %lx\n", start);
1145         DRM_DEBUG(  "used : %d\n", used);
1146         DRM_DEBUG(  "start + used - 4 : %ld\n", start + used - 4);
1147
1148         if (buf_priv->currently_mapped == I830_BUF_MAPPED) {
1149                 u32 *vp = buf_priv->kernel_virtual;
1150
1151                 vp[0] = (GFX_OP_PRIMITIVE |
1152                         sarea_priv->vertex_prim |
1153                         ((used/4)-2));
1154
1155                 if (dev_priv->use_mi_batchbuffer_start) {
1156                         vp[used/4] = MI_BATCH_BUFFER_END;
1157                         used += 4; 
1158                 }
1159                 
1160                 if (used & 4) {
1161                         vp[used/4] = 0;
1162                         used += 4;
1163                 }
1164
1165                 i830_unmap_buffer(buf);
1166         }
1167                    
1168         if (used) {
1169                 do {
1170                         if (i < nbox) {
1171                                 BEGIN_LP_RING(6);
1172                                 OUT_RING( GFX_OP_DRAWRECT_INFO );
1173                                 OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR1] );
1174                                 OUT_RING( box[i].x1 | (box[i].y1<<16) );
1175                                 OUT_RING( box[i].x2 | (box[i].y2<<16) );
1176                                 OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR4] );
1177                                 OUT_RING( 0 );
1178                                 ADVANCE_LP_RING();
1179                         }
1180
1181                         if (dev_priv->use_mi_batchbuffer_start) {
1182                                 BEGIN_LP_RING(2);
1183                                 OUT_RING( MI_BATCH_BUFFER_START | (2<<6) );
1184                                 OUT_RING( start | MI_BATCH_NON_SECURE );
1185                                 ADVANCE_LP_RING();
1186                         } 
1187                         else {
1188                                 BEGIN_LP_RING(4);
1189                                 OUT_RING( MI_BATCH_BUFFER );
1190                                 OUT_RING( start | MI_BATCH_NON_SECURE );
1191                                 OUT_RING( start + used - 4 );
1192                                 OUT_RING( 0 );
1193                                 ADVANCE_LP_RING();
1194                         }
1195
1196                 } while (++i < nbox);
1197         }
1198
1199         if (discard) {
1200                 dev_priv->counter++;
1201
1202                 (void) cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
1203                                I830_BUF_HARDWARE);
1204
1205                 BEGIN_LP_RING(8);
1206                 OUT_RING( CMD_STORE_DWORD_IDX );
1207                 OUT_RING( 20 );
1208                 OUT_RING( dev_priv->counter );
1209                 OUT_RING( CMD_STORE_DWORD_IDX );
1210                 OUT_RING( buf_priv->my_use_idx );
1211                 OUT_RING( I830_BUF_FREE );
1212                 OUT_RING( CMD_REPORT_HEAD );
1213                 OUT_RING( 0 );
1214                 ADVANCE_LP_RING();
1215         }
1216 }
1217
1218
1219 static void i830_dma_quiescent(drm_device_t *dev)
1220 {
1221         drm_i830_private_t *dev_priv = dev->dev_private;
1222         RING_LOCALS;
1223
1224         i830_kernel_lost_context(dev);
1225
1226         BEGIN_LP_RING(4);
1227         OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
1228         OUT_RING( CMD_REPORT_HEAD );
1229         OUT_RING( 0 );
1230         OUT_RING( 0 );
1231         ADVANCE_LP_RING();
1232
1233         i830_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ );
1234 }
1235
1236 static int i830_flush_queue(drm_device_t *dev)
1237 {
1238         drm_i830_private_t *dev_priv = dev->dev_private;
1239         drm_device_dma_t *dma = dev->dma;
1240         int i, ret = 0;
1241         RING_LOCALS;
1242         
1243         i830_kernel_lost_context(dev);
1244
1245         BEGIN_LP_RING(2);
1246         OUT_RING( CMD_REPORT_HEAD );
1247         OUT_RING( 0 );
1248         ADVANCE_LP_RING();
1249
1250         i830_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ );
1251
1252         for (i = 0; i < dma->buf_count; i++) {
1253                 drm_buf_t *buf = dma->buflist[ i ];
1254                 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
1255            
1256                 int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE, 
1257                                    I830_BUF_FREE);
1258
1259                 if (used == I830_BUF_HARDWARE)
1260                         DRM_DEBUG("reclaimed from HARDWARE\n");
1261                 if (used == I830_BUF_CLIENT)
1262                         DRM_DEBUG("still on client\n");
1263         }
1264
1265         return ret;
1266 }
1267
1268 /* Must be called with the lock held */
1269 void i830_reclaim_buffers(drm_device_t *dev, struct file *filp)
1270 {
1271         drm_device_dma_t *dma = dev->dma;
1272         int              i;
1273
1274         if (!dma) return;
1275         if (!dev->dev_private) return;
1276         if (!dma->buflist) return;
1277
1278         i830_flush_queue(dev);
1279
1280         for (i = 0; i < dma->buf_count; i++) {
1281                 drm_buf_t *buf = dma->buflist[ i ];
1282                 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
1283            
1284                 if (buf->filp == filp && buf_priv) {
1285                         int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, 
1286                                            I830_BUF_FREE);
1287
1288                         if (used == I830_BUF_CLIENT)
1289                                 DRM_DEBUG("reclaimed from client\n");
1290                         if(buf_priv->currently_mapped == I830_BUF_MAPPED)
1291                                 buf_priv->currently_mapped = I830_BUF_UNMAPPED;
1292                 }
1293         }
1294 }
1295
1296 static int i830_flush_ioctl(struct inode *inode, struct file *filp, 
1297                              unsigned int cmd, unsigned long arg)
1298 {
1299         drm_file_t        *priv   = filp->private_data;
1300         drm_device_t      *dev    = priv->head->dev;
1301
1302         LOCK_TEST_WITH_RETURN(dev, filp);
1303
1304         i830_flush_queue(dev);
1305         return 0;
1306 }
1307
1308 static int i830_dma_vertex(struct inode *inode, struct file *filp,
1309                        unsigned int cmd, unsigned long arg)
1310 {
1311         drm_file_t *priv = filp->private_data;
1312         drm_device_t *dev = priv->head->dev;
1313         drm_device_dma_t *dma = dev->dma;
1314         drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
1315         u32 *hw_status = dev_priv->hw_status_page;
1316         drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
1317                                         dev_priv->sarea_priv; 
1318         drm_i830_vertex_t vertex;
1319
1320         if (copy_from_user(&vertex, (drm_i830_vertex_t __user *)arg, sizeof(vertex)))
1321                 return -EFAULT;
1322
1323         LOCK_TEST_WITH_RETURN(dev, filp);
1324
1325         DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n",
1326                   vertex.idx, vertex.used, vertex.discard);
1327
1328         if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
1329
1330         i830_dma_dispatch_vertex( dev, 
1331                                   dma->buflist[ vertex.idx ], 
1332                                   vertex.discard, vertex.used );
1333
1334         sarea_priv->last_enqueue = dev_priv->counter-1;
1335         sarea_priv->last_dispatch = (int) hw_status[5];
1336    
1337         return 0;
1338 }
1339
1340 static int i830_clear_bufs(struct inode *inode, struct file *filp,
1341                            unsigned int cmd, unsigned long arg)
1342 {
1343         drm_file_t *priv = filp->private_data;
1344         drm_device_t *dev = priv->head->dev;
1345         drm_i830_clear_t clear;
1346
1347         if (copy_from_user(&clear, (drm_i830_clear_t __user *)arg, sizeof(clear)))
1348                 return -EFAULT;
1349    
1350         LOCK_TEST_WITH_RETURN(dev, filp);
1351
1352         /* GH: Someone's doing nasty things... */
1353         if (!dev->dev_private) {
1354                 return -EINVAL;
1355         }
1356
1357         i830_dma_dispatch_clear( dev, clear.flags, 
1358                                  clear.clear_color, 
1359                                  clear.clear_depth,
1360                                  clear.clear_depthmask);
1361         return 0;
1362 }
1363
1364 static int i830_swap_bufs(struct inode *inode, struct file *filp,
1365                           unsigned int cmd, unsigned long arg)
1366 {
1367         drm_file_t *priv = filp->private_data;
1368         drm_device_t *dev = priv->head->dev;
1369    
1370         DRM_DEBUG("i830_swap_bufs\n");
1371
1372         LOCK_TEST_WITH_RETURN(dev, filp);
1373
1374         i830_dma_dispatch_swap( dev );
1375         return 0;
1376 }
1377
1378
1379
1380 /* Not sure why this isn't set all the time:
1381  */ 
1382 static void i830_do_init_pageflip( drm_device_t *dev )
1383 {
1384         drm_i830_private_t *dev_priv = dev->dev_private;
1385
1386         DRM_DEBUG("%s\n", __FUNCTION__);
1387         dev_priv->page_flipping = 1;
1388         dev_priv->current_page = 0;
1389         dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
1390 }
1391
1392 static int i830_do_cleanup_pageflip( drm_device_t *dev )
1393 {
1394         drm_i830_private_t *dev_priv = dev->dev_private;
1395
1396         DRM_DEBUG("%s\n", __FUNCTION__);
1397         if (dev_priv->current_page != 0)
1398                 i830_dma_dispatch_flip( dev );
1399
1400         dev_priv->page_flipping = 0;
1401         return 0;
1402 }
1403
1404 static int i830_flip_bufs(struct inode *inode, struct file *filp,
1405                            unsigned int cmd, unsigned long arg)
1406 {
1407         drm_file_t *priv = filp->private_data;
1408         drm_device_t *dev = priv->head->dev;
1409         drm_i830_private_t *dev_priv = dev->dev_private;
1410
1411         DRM_DEBUG("%s\n", __FUNCTION__);
1412
1413         LOCK_TEST_WITH_RETURN(dev, filp);
1414
1415         if (!dev_priv->page_flipping) 
1416                 i830_do_init_pageflip( dev );
1417
1418         i830_dma_dispatch_flip( dev );
1419         return 0;
1420 }
1421
1422 static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
1423                         unsigned long arg)
1424 {
1425         drm_file_t        *priv     = filp->private_data;
1426         drm_device_t      *dev      = priv->head->dev;
1427         drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
1428         u32 *hw_status = dev_priv->hw_status_page;
1429         drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
1430                                         dev_priv->sarea_priv; 
1431
1432         sarea_priv->last_dispatch = (int) hw_status[5];
1433         return 0;
1434 }
1435
1436 static int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
1437                         unsigned long arg)
1438 {
1439         drm_file_t        *priv     = filp->private_data;
1440         drm_device_t      *dev      = priv->head->dev;
1441         int               retcode   = 0;
1442         drm_i830_dma_t    d;
1443         drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
1444         u32 *hw_status = dev_priv->hw_status_page;
1445         drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) 
1446                                         dev_priv->sarea_priv; 
1447
1448         DRM_DEBUG("getbuf\n");
1449         if (copy_from_user(&d, (drm_i830_dma_t __user *)arg, sizeof(d)))
1450                 return -EFAULT;
1451    
1452         LOCK_TEST_WITH_RETURN(dev, filp);
1453         
1454         d.granted = 0;
1455
1456         retcode = i830_dma_get_buffer(dev, &d, filp);
1457
1458         DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
1459                   current->pid, retcode, d.granted);
1460
1461         if (copy_to_user((drm_dma_t __user *)arg, &d, sizeof(d)))
1462                 return -EFAULT;
1463         sarea_priv->last_dispatch = (int) hw_status[5];
1464
1465         return retcode;
1466 }
1467
1468 static int i830_copybuf(struct inode *inode,
1469                          struct file *filp, unsigned int cmd, unsigned long arg)
1470 {
1471         /* Never copy - 2.4.x doesn't need it */
1472         return 0;
1473 }
1474
1475 static int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
1476                         unsigned long arg)
1477 {
1478         return 0;
1479 }
1480
1481
1482
1483 static int i830_getparam( struct inode *inode, struct file *filp, 
1484                         unsigned int cmd, unsigned long arg )
1485 {
1486         drm_file_t        *priv     = filp->private_data;
1487         drm_device_t      *dev      = priv->head->dev;
1488         drm_i830_private_t *dev_priv = dev->dev_private;
1489         drm_i830_getparam_t param;
1490         int value;
1491
1492         if ( !dev_priv ) {
1493                 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
1494                 return -EINVAL;
1495         }
1496
1497         if (copy_from_user(&param, (drm_i830_getparam_t __user *)arg, sizeof(param) ))
1498                 return -EFAULT;
1499
1500         switch( param.param ) {
1501         case I830_PARAM_IRQ_ACTIVE:
1502                 value = dev->irq_enabled;
1503                 break;
1504         default:
1505                 return -EINVAL;
1506         }
1507
1508         if ( copy_to_user( param.value, &value, sizeof(int) ) ) {
1509                 DRM_ERROR( "copy_to_user\n" );
1510                 return -EFAULT;
1511         }
1512         
1513         return 0;
1514 }
1515
1516
1517 static int i830_setparam( struct inode *inode, struct file *filp,
1518                         unsigned int cmd, unsigned long arg )
1519 {
1520         drm_file_t        *priv     = filp->private_data;
1521         drm_device_t      *dev      = priv->head->dev;
1522         drm_i830_private_t *dev_priv = dev->dev_private;
1523         drm_i830_setparam_t param;
1524
1525         if ( !dev_priv ) {
1526                 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
1527                 return -EINVAL;
1528         }
1529
1530         if (copy_from_user(&param, (drm_i830_setparam_t __user *)arg, sizeof(param) ))
1531                 return -EFAULT;
1532
1533         switch( param.param ) {
1534         case I830_SETPARAM_USE_MI_BATCHBUFFER_START:
1535                 dev_priv->use_mi_batchbuffer_start = param.value;
1536                 break;
1537         default:
1538                 return -EINVAL;
1539         }
1540
1541         return 0;
1542 }
1543
1544
1545 void i830_driver_pretakedown(drm_device_t *dev)
1546 {
1547         i830_dma_cleanup( dev );
1548 }
1549
1550 void i830_driver_prerelease(drm_device_t *dev, DRMFILE filp)
1551 {
1552         if (dev->dev_private) {
1553                 drm_i830_private_t *dev_priv = dev->dev_private;
1554                 if (dev_priv->page_flipping) {
1555                         i830_do_cleanup_pageflip(dev);
1556                 }
1557         }
1558 }
1559
1560 void i830_driver_release(drm_device_t *dev, struct file *filp)
1561 {
1562         i830_reclaim_buffers(dev, filp);
1563 }
1564
1565 int i830_driver_dma_quiescent(drm_device_t *dev)
1566 {
1567         i830_dma_quiescent( dev );
1568         return 0;
1569 }
1570
1571 drm_ioctl_desc_t i830_ioctls[] = {
1572         [DRM_IOCTL_NR(DRM_I830_INIT)]     = { i830_dma_init,    1, 1 },
1573         [DRM_IOCTL_NR(DRM_I830_VERTEX)]   = { i830_dma_vertex,  1, 0 },
1574         [DRM_IOCTL_NR(DRM_I830_CLEAR)]    = { i830_clear_bufs,  1, 0 },
1575         [DRM_IOCTL_NR(DRM_I830_FLUSH)]    = { i830_flush_ioctl, 1, 0 },
1576         [DRM_IOCTL_NR(DRM_I830_GETAGE)]   = { i830_getage,      1, 0 },
1577         [DRM_IOCTL_NR(DRM_I830_GETBUF)]   = { i830_getbuf,      1, 0 },
1578         [DRM_IOCTL_NR(DRM_I830_SWAP)]     = { i830_swap_bufs,   1, 0 },
1579         [DRM_IOCTL_NR(DRM_I830_COPY)]     = { i830_copybuf,     1, 0 },
1580         [DRM_IOCTL_NR(DRM_I830_DOCOPY)]   = { i830_docopy,      1, 0 },
1581         [DRM_IOCTL_NR(DRM_I830_FLIP)]     = { i830_flip_bufs,   1, 0 },
1582         [DRM_IOCTL_NR(DRM_I830_IRQ_EMIT)] = { i830_irq_emit,    1, 0 },
1583         [DRM_IOCTL_NR(DRM_I830_IRQ_WAIT)] = { i830_irq_wait,    1, 0 },
1584         [DRM_IOCTL_NR(DRM_I830_GETPARAM)] = { i830_getparam,    1, 0 },
1585         [DRM_IOCTL_NR(DRM_I830_SETPARAM)] = { i830_setparam,    1, 0 } 
1586 };
1587
1588 int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);