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