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