Merged mga branch with trunk
[platform/upstream/libdrm.git] / linux / i810_dma.c
index 09959b6..30fda5b 100644 (file)
@@ -25,8 +25,9 @@
  *
  * Authors: Rickard E. (Rik) Faith <faith@precisioninsight.com>
  *         Jeff Hartmann <jhartmann@precisioninsight.com>
+ *          Keith Whitwell <keithw@precisioninsight.com>
  *
- * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/i810_dma.c,v 1.1 2000/02/11 17:26:04 dawes Exp $
+ * $XFree86$
  *
  */
 
@@ -36,6 +37,9 @@
 
 #include <linux/interrupt.h>   /* For task queue support */
 
+#define I810_BUF_FREE          1
+#define I810_BUF_USED          0
+
 #define I810_REG(reg)          2
 #define I810_BASE(reg)         ((unsigned long) \
                                dev->maplist[I810_REG(reg)]->handle)
 #define I810_DEREF(reg)                *(__volatile__ int *)I810_ADDR(reg)
 #define I810_READ(reg)         I810_DEREF(reg)
 #define I810_WRITE(reg,val)    do { I810_DEREF(reg) = val; } while (0)
-
-void i810_dma_init(drm_device_t *dev)
+#define I810_DEREF16(reg)      *(__volatile__ u16 *)I810_ADDR(reg)
+#define I810_READ16(reg)       I810_DEREF16(reg)
+#define I810_WRITE16(reg,val)  do { I810_DEREF16(reg) = val; } while (0)
+
+#define RING_LOCALS    unsigned int outring, ringmask; volatile char *virt;
+
+#define BEGIN_LP_RING(n) do {                          \
+       if (I810_VERBOSE)                               \
+               DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n",  \
+                         n, __FUNCTION__);             \
+       if (dev_priv->ring.space < n*4)                 \
+               i810_wait_ring(dev, n*4);               \
+       dev_priv->ring.space -= n*4;                    \
+       outring = dev_priv->ring.tail;                  \
+       ringmask = dev_priv->ring.tail_mask;            \
+       virt = dev_priv->ring.virtual_start;            \
+} while (0)
+
+#define ADVANCE_LP_RING() do {                                 \
+       if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n");       \
+       dev_priv->ring.tail = outring;                          \
+       I810_WRITE(LP_RING + RING_TAIL, outring);               \
+} while(0)
+
+#define OUT_RING(n) do {                                               \
+       if (I810_VERBOSE) DRM_DEBUG("   OUT_RING %x\n", (int)(n));      \
+       *(volatile unsigned int *)(virt + outring) = n;                 \
+       outring += 4;                                                   \
+       outring &= ringmask;                                            \
+} while (0);
+
+static inline void i810_print_status_page(drm_device_t *dev)
 {
-        printk(KERN_INFO "i810_dma_init\n");
+       drm_device_dma_t *dma = dev->dma;
+       drm_i810_private_t *dev_priv = dev->dev_private;
+       u32 *temp = (u32 *)dev_priv->hw_status_page;
+       int i;
+
+       DRM_DEBUG(  "hw_status: Interrupt Status : %x\n", temp[0]);
+       DRM_DEBUG(  "hw_status: LpRing Head ptr : %x\n", temp[1]);
+       DRM_DEBUG(  "hw_status: IRing Head ptr : %x\n", temp[2]);
+       DRM_DEBUG(  "hw_status: Reserved : %x\n", temp[3]);
+       DRM_DEBUG(  "hw_status: Driver Counter : %d\n", temp[5]);
+       for(i = 6; i < dma->buf_count + 6; i++) {
+               DRM_DEBUG(  "buffer status idx : %d used: %d\n", i - 6, temp[i]);
+       }
 }
 
-void i810_dma_cleanup(drm_device_t *dev)
+static drm_buf_t *i810_freelist_get(drm_device_t *dev)
 {
-   printk(KERN_INFO "i810_dma_cleanup\n");
+       drm_device_dma_t *dma = dev->dma;
+       int              i;
+       int              used;
+   
+       /* Linear search might not be the best solution */
+
+       for (i = 0; i < dma->buf_count; i++) {
+               drm_buf_t *buf = dma->buflist[ i ];
+               drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+               /* In use is already a pointer */
+               used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, 
+                              I810_BUF_USED);
+               if(used == I810_BUF_FREE) {
+                       return buf;
+               }
+       }
+       return NULL;
 }
 
-static inline void i810_dma_dispatch(drm_device_t *dev, unsigned long address,
-                                   unsigned long length)
+/* This should only be called if the buffer is not sent to the hardware
+ * yet, the hardware updates in use for us once its on the ring buffer.
+ */
+
+static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)
 {
-   printk(KERN_INFO "i810_dma_dispatch\n");
+       drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+       int used;
+   
+       /* In use is already a pointer */
+       used = cmpxchg(buf_priv->in_use, I810_BUF_USED, I810_BUF_FREE);
+       if(used != I810_BUF_USED) {
+               DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
+               return -EINVAL;
+       }
+   
+       return 0;
 }
 
-static inline void i810_dma_quiescent(drm_device_t *dev)
+static int i810_dma_get_buffers(drm_device_t *dev, drm_dma_t *d)
 {
+       int               i;
+       drm_buf_t         *buf;
+
+       for (i = d->granted_count; i < d->request_count; i++) {
+               buf = i810_freelist_get(dev);
+               if (!buf) break;
+               buf->pid     = current->pid;
+               copy_to_user_ret(&d->request_indices[i],
+                                &buf->idx,
+                                sizeof(buf->idx),
+                                -EFAULT);
+               copy_to_user_ret(&d->request_sizes[i],
+                                &buf->total,
+                                sizeof(buf->total),
+                                -EFAULT);
+               ++d->granted_count;
+       }
+       return 0;
 }
 
-static inline void i810_dma_ready(drm_device_t *dev)
+static unsigned long i810_alloc_page(drm_device_t *dev)
 {
-   i810_dma_quiescent(dev);
-   printk(KERN_INFO "i810_dma_ready\n");
+       unsigned long address;
+   
+       address = __get_free_page(GFP_KERNEL);
+       if(address == 0UL) 
+               return 0;
+       
+       atomic_inc(&mem_map[MAP_NR((void *) address)].count);
+       set_bit(PG_locked, &mem_map[MAP_NR((void *) address)].flags);
+   
+       return address;
 }
 
-static inline int i810_dma_is_ready(drm_device_t *dev)
+static void i810_free_page(drm_device_t *dev, unsigned long page)
 {
-
-   i810_dma_quiescent(dev);
-
-   printk(KERN_INFO "i810_dma_is_ready\n");
-   return 1;
+       if(page == 0UL) 
+               return;
+       
+       atomic_dec(&mem_map[MAP_NR((void *) page)].count);
+       clear_bit(PG_locked, &mem_map[MAP_NR((void *) page)].flags);
+       wake_up(&mem_map[MAP_NR((void *) page)].wait);
+       free_page(page);
+       return;
 }
 
-
-static void i810_dma_service(int irq, void *device, struct pt_regs *regs)
+static int i810_dma_cleanup(drm_device_t *dev)
 {
-       drm_device_t     *dev = (drm_device_t *)device;
-       drm_device_dma_t *dma = dev->dma;
-       
-       atomic_inc(&dev->total_irq);
-       if (i810_dma_is_ready(dev)) {
-                               /* Free previous buffer */
-               if (test_and_set_bit(0, &dev->dma_flag)) {
-                       atomic_inc(&dma->total_missed_free);
-                       return;
+       if(dev->dev_private) {
+               drm_i810_private_t *dev_priv = 
+                       (drm_i810_private_t *) dev->dev_private;
+          
+               if(dev_priv->ring.virtual_start) {
+                       drm_ioremapfree((void *) dev_priv->ring.virtual_start,
+                                       dev_priv->ring.Size);
                }
-               if (dma->this_buffer) {
-                       drm_free_buffer(dev, dma->this_buffer);
-                       dma->this_buffer = NULL;
+               if(dev_priv->hw_status_page != 0UL) {
+                       i810_free_page(dev, dev_priv->hw_status_page);
+                       /* Need to rewrite hardware status page */
+                       I810_WRITE(0x02080, 0x1ffff000);
                }
-               clear_bit(0, &dev->dma_flag);
-
-                               /* Dispatch new buffer */
-               queue_task(&dev->tq, &tq_immediate);
-               mark_bh(IMMEDIATE_BH);
+               drm_free(dev->dev_private, sizeof(drm_i810_private_t), 
+                        DRM_MEM_DRIVER);
+               dev->dev_private = NULL;
        }
+       return 0;
 }
 
-/* Only called by i810_dma_schedule. */
-static int i810_do_dma(drm_device_t *dev, int locked)
+static int i810_wait_ring(drm_device_t *dev, int n)
 {
-       unsigned long    address;
-       unsigned long    length;
-       drm_buf_t        *buf;
-       int              retcode = 0;
-       drm_device_dma_t *dma = dev->dma;
-#if DRM_DMA_HISTOGRAM
-       cycles_t         dma_start, dma_stop;
-#endif
-
-       if (test_and_set_bit(0, &dev->dma_flag)) {
-               atomic_inc(&dma->total_missed_dma);
-               return -EBUSY;
-       }
-       
-#if DRM_DMA_HISTOGRAM
-       dma_start = get_cycles();
-#endif
-
-       if (!dma->next_buffer) {
-               DRM_ERROR("No next_buffer\n");
-               clear_bit(0, &dev->dma_flag);
-               return -EINVAL;
-       }
-
-       buf     = dma->next_buffer;
-       address = (unsigned long)buf->bus_address;
-       length  = buf->used;
+       drm_i810_private_t *dev_priv = dev->dev_private;
+       drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+       int iters = 0;
+       unsigned long end;
+
+       end = jiffies + (HZ*3);
+       while (ring->space < n) {
+               int i;
        
-
-       DRM_DEBUG("context %d, buffer %d (%ld bytes)\n",
-                 buf->context, buf->idx, length);
-
-       if (buf->list == DRM_LIST_RECLAIM) {
-               drm_clear_next_buffer(dev);
-               drm_free_buffer(dev, buf);
-               clear_bit(0, &dev->dma_flag);
-               return -EINVAL;
-       }
-
-       if (!length) {
-               DRM_ERROR("0 length buffer\n");
-               drm_clear_next_buffer(dev);
-               drm_free_buffer(dev, buf);
-               clear_bit(0, &dev->dma_flag);
-               return 0;
-       }
-       
-       if (!i810_dma_is_ready(dev)) {
-               clear_bit(0, &dev->dma_flag);
-               return -EBUSY;
-       }
-
-       if (buf->while_locked) {
-               if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
-                       DRM_ERROR("Dispatching buffer %d from pid %d"
-                                 " \"while locked\", but no lock held\n",
-                                 buf->idx, buf->pid);
-               }
-       } else {
-               if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock,
-                                             DRM_KERNEL_CONTEXT)) {
-                       atomic_inc(&dma->total_missed_lock);
-                       clear_bit(0, &dev->dma_flag);
-                       return -EBUSY;
+               ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+               ring->space = ring->head - (ring->tail+8);
+          
+               if (ring->space < 0) ring->space += ring->Size;
+          
+               iters++;
+               if((signed)(end - jiffies) <= 0) {
+                       DRM_ERROR("space: %d wanted %d\n", ring->space, n);
+                       DRM_ERROR("lockup\n");
+                       goto out_wait_ring;
                }
-       }
-
-       if (dev->last_context != buf->context
-           && !(dev->queuelist[buf->context]->flags
-                & _DRM_CONTEXT_PRESERVED)) {
-                               /* PRE: dev->last_context != buf->context */
-               if (drm_context_switch(dev, dev->last_context, buf->context)) {
-                       drm_clear_next_buffer(dev);
-                       drm_free_buffer(dev, buf);
-               }
-               retcode = -EBUSY;
-               goto cleanup;
-                       
-                               /* POST: we will wait for the context
-                                  switch and will dispatch on a later call
-                                  when dev->last_context == buf->context.
-                                  NOTE WE HOLD THE LOCK THROUGHOUT THIS
-                                  TIME! */
-       }
-
-       drm_clear_next_buffer(dev);
-       buf->pending     = 1;
-       buf->waiting     = 0;
-       buf->list        = DRM_LIST_PEND;
-#if DRM_DMA_HISTOGRAM
-       buf->time_dispatched = get_cycles();
-#endif
 
-       i810_dma_dispatch(dev, address, length);
-       drm_free_buffer(dev, dma->this_buffer);
-       dma->this_buffer = buf;
-
-       atomic_add(length, &dma->total_bytes);
-       atomic_inc(&dma->total_dmas);
-
-       if (!buf->while_locked && !dev->context_flag && !locked) {
-               if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
-                                 DRM_KERNEL_CONTEXT)) {
-                       DRM_ERROR("\n");
-               }
+               for (i = 0 ; i < 2000 ; i++) ;
        }
-cleanup:
-
-       clear_bit(0, &dev->dma_flag);
 
-#if DRM_DMA_HISTOGRAM
-       dma_stop = get_cycles();
-       atomic_inc(&dev->histo.dma[drm_histogram_slot(dma_stop - dma_start)]);
-#endif
-
-       return retcode;
-}
-
-static void i810_dma_schedule_timer_wrapper(unsigned long dev)
-{
-       i810_dma_schedule((drm_device_t *)dev, 0);
+out_wait_ring:   
+       return iters;
 }
 
-static void i810_dma_schedule_tq_wrapper(void *dev)
+static void i810_kernel_lost_context(drm_device_t *dev)
 {
-       i810_dma_schedule(dev, 0);
+       drm_i810_private_t *dev_priv = dev->dev_private;
+       drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
+      
+       ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
+       ring->tail = I810_READ(LP_RING + RING_TAIL);
+       ring->space = ring->head - (ring->tail+8);
+       if (ring->space < 0) ring->space += ring->Size;
 }
 
-int i810_dma_schedule(drm_device_t *dev, int locked)
+static int i810_freelist_init(drm_device_t *dev)
 {
-       int              next;
-       drm_queue_t      *q;
-       drm_buf_t        *buf;
-       int              retcode   = 0;
-       int              processed = 0;
-       int              missed;
-       int              expire    = 20;
-       drm_device_dma_t *dma      = dev->dma;
-#if DRM_DMA_HISTOGRAM
-       cycles_t         schedule_start;
-#endif
-
-       if (test_and_set_bit(0, &dev->interrupt_flag)) {
-                               /* Not reentrant */
-               atomic_inc(&dma->total_missed_sched);
-               return -EBUSY;
-       }
-       missed = atomic_read(&dma->total_missed_sched);
-
-#if DRM_DMA_HISTOGRAM
-       schedule_start = get_cycles();
-#endif
-
-again:
-       if (dev->context_flag) {
-               clear_bit(0, &dev->interrupt_flag);
-               return -EBUSY;
-       }
-       if (dma->next_buffer) {
-                               /* Unsent buffer that was previously
-                                  selected, but that couldn't be sent
-                                  because the lock could not be obtained
-                                  or the DMA engine wasn't ready.  Try
-                                  again. */
-               atomic_inc(&dma->total_tried);
-               if (!(retcode = i810_do_dma(dev, locked))) {
-                       atomic_inc(&dma->total_hit);
-                       ++processed;
-               }
-       } else {
-               do {
-                       next = drm_select_queue(dev,
-                                            i810_dma_schedule_timer_wrapper);
-                       if (next >= 0) {
-                               q   = dev->queuelist[next];
-                               buf = drm_waitlist_get(&q->waitlist);
-                               dma->next_buffer = buf;
-                               dma->next_queue  = q;
-                               if (buf && buf->list == DRM_LIST_RECLAIM) {
-                                       drm_clear_next_buffer(dev);
-                                       drm_free_buffer(dev, buf);
-                               }
-                       }
-               } while (next >= 0 && !dma->next_buffer);
-               if (dma->next_buffer) {
-                       if (!(retcode = i810_do_dma(dev, locked))) {
-                               ++processed;
-                       }
-               }
+       drm_device_dma_t *dma = dev->dma;
+       drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+       u8 *hw_status = (u8 *)dev_priv->hw_status_page;
+       int i;
+       int my_idx = 24;
+   
+       if(dma->buf_count > 1019) {
+               /* Not enough space in the status page for the freelist */
+               return -EINVAL;
        }
 
-       if (--expire) {
-               if (missed != atomic_read(&dma->total_missed_sched)) {
-                       atomic_inc(&dma->total_lost);
-                       if (i810_dma_is_ready(dev)) goto again;
-               }
-               if (processed && i810_dma_is_ready(dev)) {
-                       atomic_inc(&dma->total_lost);
-                       processed = 0;
-                       goto again;
-               }
+       for (i = 0; i < dma->buf_count; i++) {
+               drm_buf_t *buf = dma->buflist[ i ];
+               drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+          
+               buf_priv->in_use = hw_status + my_idx;
+               DRM_DEBUG("buf_priv->in_use : %p\n", buf_priv->in_use);
+               *buf_priv->in_use = I810_BUF_FREE;
+               buf_priv->my_use_idx = my_idx;
+               my_idx += 4;
        }
-       
-       clear_bit(0, &dev->interrupt_flag);
-       
-#if DRM_DMA_HISTOGRAM
-       atomic_inc(&dev->histo.schedule[drm_histogram_slot(get_cycles()
-                                                          - schedule_start)]);
-#endif
-       return retcode;
+       return 0;
 }
 
-static int i810_dma_priority(drm_device_t *dev, drm_dma_t *d)
+static int i810_dma_initialize(drm_device_t *dev, 
+                              drm_i810_private_t *dev_priv,
+                              drm_i810_init_t *init)
 {
-       unsigned long     address;
-       unsigned long     length;
-       int               must_free = 0;
-       int               retcode   = 0;
-       int               i;
-       int               idx;
-       drm_buf_t         *buf;
-       drm_buf_t         *last_buf = NULL;
-       drm_device_dma_t  *dma      = dev->dma;
-       DECLARE_WAITQUEUE(entry, current);
-
-                               /* Turn off interrupt handling */
-       while (test_and_set_bit(0, &dev->interrupt_flag)) {
-               schedule();
-               if (signal_pending(current)) return -EINTR;
-       }
-       if (!(d->flags & _DRM_DMA_WHILE_LOCKED)) {
-               while (!drm_lock_take(&dev->lock.hw_lock->lock,
-                                     DRM_KERNEL_CONTEXT)) {
-                       schedule();
-                       if (signal_pending(current)) {
-                               clear_bit(0, &dev->interrupt_flag);
-                               return -EINTR;
-                       }
-               }
-               ++must_free;
-       }
-       atomic_inc(&dma->total_prio);
-
-       for (i = 0; i < d->send_count; i++) {
-               idx = d->send_indices[i];
-               if (idx < 0 || idx >= dma->buf_count) {
-                       DRM_ERROR("Index %d (of %d max)\n",
-                                 d->send_indices[i], dma->buf_count - 1);
-                       continue;
-               }
-               buf = dma->buflist[ idx ];
-               if (buf->pid != current->pid) {
-                       DRM_ERROR("Process %d using buffer owned by %d\n",
-                                 current->pid, buf->pid);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-               if (buf->list != DRM_LIST_NONE) {
-                       DRM_ERROR("Process %d using %d's buffer on list %d\n",
-                                 current->pid, buf->pid, buf->list);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-                               /* This isn't a race condition on
-                                  buf->list, since our concern is the
-                                  buffer reclaim during the time the
-                                  process closes the /dev/drm? handle, so
-                                  it can't also be doing DMA. */
-               buf->list         = DRM_LIST_PRIO;
-               buf->used         = d->send_sizes[i];
-               buf->context      = d->context;
-               buf->while_locked = d->flags & _DRM_DMA_WHILE_LOCKED;
-               address           = (unsigned long)buf->address;
-               length            = buf->used;
-               if (!length) {
-                       DRM_ERROR("0 length buffer\n");
-               }
-               if (buf->pending) {
-                       DRM_ERROR("Sending pending buffer:"
-                                 " buffer %d, offset %d\n",
-                                 d->send_indices[i], i);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-               if (buf->waiting) {
-                       DRM_ERROR("Sending waiting buffer:"
-                                 " buffer %d, offset %d\n",
-                                 d->send_indices[i], i);
-                       retcode = -EINVAL;
-                       goto cleanup;
-               }
-               buf->pending = 1;
-               
-               if (dev->last_context != buf->context
-                   && !(dev->queuelist[buf->context]->flags
-                        & _DRM_CONTEXT_PRESERVED)) {
-                       add_wait_queue(&dev->context_wait, &entry);
-                       current->state = TASK_INTERRUPTIBLE;
-                               /* PRE: dev->last_context != buf->context */
-                       drm_context_switch(dev, dev->last_context,
-                                          buf->context);
-                               /* POST: we will wait for the context
-                                  switch and will dispatch on a later call
-                                  when dev->last_context == buf->context.
-                                  NOTE WE HOLD THE LOCK THROUGHOUT THIS
-                                  TIME! */
-                       schedule();
-                       current->state = TASK_RUNNING;
-                       remove_wait_queue(&dev->context_wait, &entry);
-                       if (signal_pending(current)) {
-                               retcode = -EINTR;
-                               goto cleanup;
-                       }
-                       if (dev->last_context != buf->context) {
-                               DRM_ERROR("Context mismatch: %d %d\n",
-                                         dev->last_context,
-                                         buf->context);
-                       }
-               }
-
-#if DRM_DMA_HISTOGRAM
-               buf->time_queued     = get_cycles();
-               buf->time_dispatched = buf->time_queued;
-#endif
-               i810_dma_dispatch(dev, address, length);
-               if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
-                                 DRM_KERNEL_CONTEXT)) {
-                  DRM_ERROR("\n");
-               }
-
-               atomic_add(length, &dma->total_bytes);
-               atomic_inc(&dma->total_dmas);
-               
-               if (last_buf) {
-                       drm_free_buffer(dev, last_buf);
-               }
-               last_buf = buf;
-       }
+       drm_map_t *sarea_map;
 
+       dev->dev_private = (void *) dev_priv;
+       memset(dev_priv, 0, sizeof(drm_i810_private_t));
 
-cleanup:
-       if (last_buf) {
-               i810_dma_ready(dev);
-               drm_free_buffer(dev, last_buf);
+       if (init->ring_map_idx >= dev->map_count ||
+           init->buffer_map_idx >= dev->map_count) {
+               i810_dma_cleanup(dev);
+               DRM_ERROR("ring_map or buffer_map are invalid\n");
+               return -EINVAL;
        }
-       
-       if (must_free && !dev->context_flag) {
-               if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
-                                 DRM_KERNEL_CONTEXT)) {
-                       DRM_ERROR("\n");
-               }
+   
+       dev_priv->ring_map_idx = init->ring_map_idx;
+       dev_priv->buffer_map_idx = init->buffer_map_idx;
+       sarea_map = dev->maplist[0];
+       dev_priv->sarea_priv = (drm_i810_sarea_t *) 
+               ((u8 *)sarea_map->handle + 
+                init->sarea_priv_offset);
+
+       atomic_set(&dev_priv->flush_done, 0);
+       init_waitqueue_head(&dev_priv->flush_queue);
+       
+       dev_priv->ring.Start = init->ring_start;
+       dev_priv->ring.End = init->ring_end;
+       dev_priv->ring.Size = init->ring_size;
+       dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + 
+                                                  init->ring_start, 
+                                                  init->ring_size);
+       dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+   
+       if (dev_priv->ring.virtual_start == NULL) {
+               i810_dma_cleanup(dev);
+               DRM_ERROR("can not ioremap virtual address for"
+                         " ring buffer\n");
+               return -ENOMEM;
        }
-       clear_bit(0, &dev->interrupt_flag);
-       return retcode;
+   
+       /* Program Hardware Status Page */
+       dev_priv->hw_status_page = i810_alloc_page(dev);
+       memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE);
+       if(dev_priv->hw_status_page == 0UL) {
+               i810_dma_cleanup(dev);
+               DRM_ERROR("Can not allocate hardware status page\n");
+               return -ENOMEM;
+       }
+       DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page);
+   
+       I810_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page));
+       DRM_DEBUG("Enabled hardware status page\n");
+   
+       /* Now we need to init our freelist */
+       if(i810_freelist_init(dev) != 0) {
+               i810_dma_cleanup(dev);
+               DRM_ERROR("Not enough space in the status page for"
+                         " the freelist\n");
+               return -ENOMEM;
+       }
+       return 0;
 }
 
-static int i810_dma_send_buffers(drm_device_t *dev, drm_dma_t *d)
+int i810_dma_init(struct inode *inode, struct file *filp,
+                 unsigned int cmd, unsigned long arg)
 {
-       DECLARE_WAITQUEUE(entry, current);
-       drm_buf_t         *last_buf = NULL;
-       int               retcode   = 0;
-       drm_device_dma_t  *dma      = dev->dma;
-
-       if (d->flags & _DRM_DMA_BLOCK) {
-               last_buf = dma->buflist[d->send_indices[d->send_count-1]];
-               add_wait_queue(&last_buf->dma_wait, &entry);
-       }
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->dev;
+       drm_i810_private_t *dev_priv;
+       drm_i810_init_t init;
+       int retcode = 0;
        
-       if ((retcode = drm_dma_enqueue(dev, d))) {
-               if (d->flags & _DRM_DMA_BLOCK)
-                       remove_wait_queue(&last_buf->dma_wait, &entry);
-               return retcode;
-       }
-       
-       i810_dma_schedule(dev, 0);
+       copy_from_user_ret(&init, (drm_i810_init_t *)arg, 
+                          sizeof(init), -EFAULT);
        
-       if (d->flags & _DRM_DMA_BLOCK) {
-               DRM_DEBUG("%d waiting\n", current->pid);
-               current->state = TASK_INTERRUPTIBLE;
-               for (;;) {
-                       if (!last_buf->waiting
-                           && !last_buf->pending)
-                               break; /* finished */
-                       schedule();
-                       if (signal_pending(current)) {
-                               retcode = -EINTR; /* Can't restart */
-                               break;
-                       }
-               }
-               current->state = TASK_RUNNING;
-               DRM_DEBUG("%d running\n", current->pid);
-               remove_wait_queue(&last_buf->dma_wait, &entry);
-               if (!retcode
-                   || (last_buf->list==DRM_LIST_PEND && !last_buf->pending)) {
-                       if (!waitqueue_active(&last_buf->dma_wait)) {
-                               drm_free_buffer(dev, last_buf);
-                       }
-               }
-               if (retcode) {
-                       DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n",
-                                 d->context,
-                                 last_buf->waiting,
-                                 last_buf->pending,
-                                 DRM_WAITCOUNT(dev, d->context),
-                                 last_buf->idx,
-                                 last_buf->list,
-                                 last_buf->pid,
-                                 current->pid);
-               }
+       switch(init.func) {
+               case I810_INIT_DMA:
+                       dev_priv = drm_alloc(sizeof(drm_i810_private_t), 
+                                            DRM_MEM_DRIVER);
+                       if(dev_priv == NULL) return -ENOMEM;
+                       retcode = i810_dma_initialize(dev, dev_priv, &init);
+               break;
+               case I810_CLEANUP_DMA:
+                       retcode = i810_dma_cleanup(dev);
+               break;
+               default:
+                       retcode = -EINVAL;
+               break;
        }
-       return retcode;
+   
+       return retcode;
 }
 
-int i810_dma(struct inode *inode, struct file *filp, unsigned int cmd,
-             unsigned long arg)
+static void i810_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf,
+                                     int used )
 {
-       drm_file_t        *priv     = filp->private_data;
-       drm_device_t      *dev      = priv->dev;
-       drm_device_dma_t  *dma      = dev->dma;
-       int               retcode   = 0;
-       drm_dma_t         d;
-
-        printk("i810_dma start\n");
-       copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT);
-       DRM_DEBUG("%d %d: %d send, %d req\n",
-                 current->pid, d.context, d.send_count, d.request_count);
+       drm_i810_private_t *dev_priv = dev->dev_private;
+       drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+       unsigned long address = (unsigned long)buf->bus_address;
+       unsigned long start = address - dev->agp->base;
+       RING_LOCALS;
+
+       dev_priv->counter++;
+       DRM_DEBUG(  "dispatch counter : %ld\n", dev_priv->counter);
+       DRM_DEBUG(  "i810_dma_dispatch\n");
+       DRM_DEBUG(  "start : 0x%lx\n", start);
+       DRM_DEBUG(  "used : 0x%x\n", used);
+       DRM_DEBUG(  "start + used - 4 : 0x%lx\n", start + used - 4);
+       i810_kernel_lost_context(dev);
+
+       BEGIN_LP_RING(10);
+       OUT_RING( CMD_OP_BATCH_BUFFER );
+       OUT_RING( start | BB1_PROTECTED );
+       OUT_RING( start + used - 4 );
+       OUT_RING( CMD_STORE_DWORD_IDX );
+       OUT_RING( 20 );
+       OUT_RING( dev_priv->counter );
+       OUT_RING( CMD_STORE_DWORD_IDX );
+       OUT_RING( buf_priv->my_use_idx );
+       OUT_RING( I810_BUF_FREE );   
+       OUT_RING( CMD_REPORT_HEAD );
+       ADVANCE_LP_RING();
+}
 
-       if (d.context == DRM_KERNEL_CONTEXT || d.context >= dev->queue_slots) {
-               DRM_ERROR("Process %d using context %d\n",
-                         current->pid, d.context);
-               return -EINVAL;
-       }
+static void i810_dma_dispatch_vertex(drm_device_t *dev, 
+                                    drm_buf_t *buf,
+                                    int discard,
+                                    int used)
+{
+       drm_i810_private_t *dev_priv = dev->dev_private;
+       drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+       drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       drm_clip_rect_t *box = sarea_priv->boxes;
+       int nbox = sarea_priv->nbox;
+       unsigned long address = (unsigned long)buf->bus_address;
+       unsigned long start = address - dev->agp->base;     
+       int i = 0;
+       RING_LOCALS;
 
-       if (d.send_count < 0 || d.send_count > dma->buf_count) {
-               DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n",
-                         current->pid, d.send_count, dma->buf_count);
-               return -EINVAL;
-       }
-       if (d.request_count < 0 || d.request_count > dma->buf_count) {
-               DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
-                         current->pid, d.request_count, dma->buf_count);
-               return -EINVAL;
+   
+       if (nbox > I810_NR_SAREA_CLIPRECTS) 
+               nbox = I810_NR_SAREA_CLIPRECTS;
+   
+       DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n", 
+                 address, used, nbox);
+
+       dev_priv->counter++;
+       DRM_DEBUG(  "dispatch counter : %ld\n", dev_priv->counter);
+       DRM_DEBUG(  "i810_dma_dispatch\n");
+       DRM_DEBUG(  "start : %lx\n", start);
+       DRM_DEBUG(  "used : %d\n", used);
+       DRM_DEBUG(  "start + used - 4 : %ld\n", start + used - 4);
+       i810_kernel_lost_context(dev);
+
+       if (used) {
+               do {
+                       if (i < nbox) {
+                               BEGIN_LP_RING(4);
+                               OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR | 
+                                         SC_ENABLE );
+                               OUT_RING( GFX_OP_SCISSOR_INFO );
+                               OUT_RING( box[i].x1 | (box[i].y1 << 16) );
+                               OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) );
+                               ADVANCE_LP_RING();
+                       }
+                       
+                       BEGIN_LP_RING(4);
+                       OUT_RING( CMD_OP_BATCH_BUFFER );
+                       OUT_RING( start | BB1_PROTECTED );
+                       OUT_RING( start + used - 4 );
+                       OUT_RING( 0 );
+                       ADVANCE_LP_RING();
+                       
+               } while (++i < nbox);
        }
 
-       if (d.send_count) {
-#if 0
-               if (d.flags & _DRM_DMA_PRIORITY)
-                       retcode = i810_dma_priority(dev, &d);
-               else 
-                       retcode = i810_dma_send_buffers(dev, &d);
-#endif
-          printk("i810_dma priority\n");
+       BEGIN_LP_RING(10);
+       OUT_RING( CMD_STORE_DWORD_IDX );
+       OUT_RING( 20 );
+       OUT_RING( dev_priv->counter );
+       OUT_RING( 0 );
 
-          retcode = i810_dma_priority(dev, &d);
+       if (discard) {
+               OUT_RING( CMD_STORE_DWORD_IDX );
+               OUT_RING( buf_priv->my_use_idx );
+               OUT_RING( I810_BUF_FREE );
+               OUT_RING( 0 );
        }
 
-       d.granted_count = 0;
+       OUT_RING( CMD_REPORT_HEAD );
+       OUT_RING( 0 );
+       ADVANCE_LP_RING();
+}
 
-       if (!retcode && d.request_count) {
-               retcode = drm_dma_get_buffers(dev, &d);
-       }
 
-       DRM_DEBUG("%d returning, granted = %d\n",
-                 current->pid, d.granted_count);
-       copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
+/* Interrupts are only for flushing */
+static void i810_dma_service(int irq, void *device, struct pt_regs *regs)
+{
+       drm_device_t     *dev = (drm_device_t *)device;
+       u16 temp;
+   
+       atomic_inc(&dev->total_irq);
+       temp = I810_READ16(I810REG_INT_IDENTITY_R);
+       temp = temp & ~(0x6000);
+       if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, 
+                                  temp); /* Clear all interrupts */
+   
+       queue_task(&dev->tq, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
 
-       printk("i810_dma end (granted)\n");
-       return retcode;
+static void i810_dma_task_queue(void *device)
+{
+       drm_device_t *dev = (drm_device_t *) device;
+       drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+
+       atomic_set(&dev_priv->flush_done, 1);
+       wake_up_interruptible(&dev_priv->flush_queue);
 }
 
 int i810_irq_install(drm_device_t *dev, int irq)
 {
        int retcode;
-
+       u16 temp;
+   
        if (!irq)     return -EINVAL;
        
        down(&dev->struct_sem);
@@ -591,6 +508,7 @@ int i810_irq_install(drm_device_t *dev, int irq)
        dev->irq = irq;
        up(&dev->struct_sem);
        
+       DRM_DEBUG(  "Interrupt Install : %d\n", irq);
        DRM_DEBUG("%d\n", irq);
 
        dev->context_flag     = 0;
@@ -603,12 +521,21 @@ int i810_irq_install(drm_device_t *dev, int irq)
 
        dev->tq.next          = NULL;
        dev->tq.sync          = 0;
-       dev->tq.routine       = i810_dma_schedule_tq_wrapper;
+       dev->tq.routine       = i810_dma_task_queue;
        dev->tq.data          = dev;
 
-
                                /* Before installing handler */
-       /* TODO */      
+       temp = I810_READ16(I810REG_HWSTAM);
+       temp = temp & 0x6000;
+       I810_WRITE16(I810REG_HWSTAM, temp);
+       
+       temp = I810_READ16(I810REG_INT_MASK_R);
+       temp = temp & 0x6000;
+       I810_WRITE16(I810REG_INT_MASK_R, temp); /* Unmask interrupts */
+       temp = I810_READ16(I810REG_INT_ENABLE_R);
+       temp = temp & 0x6000;
+       I810_WRITE16(I810REG_INT_ENABLE_R, temp); /* Disable all interrupts */
+
                                /* Install handler */
        if ((retcode = request_irq(dev->irq,
                                   i810_dma_service,
@@ -620,15 +547,18 @@ int i810_irq_install(drm_device_t *dev, int irq)
                up(&dev->struct_sem);
                return retcode;
        }
-
-                               /* After installing handler */
-       /* TODO */
+       temp = I810_READ16(I810REG_INT_ENABLE_R);
+       temp = temp & 0x6000;
+       temp = temp | 0x0003;
+       I810_WRITE16(I810REG_INT_ENABLE_R, 
+                    temp); /* Enable bp & user interrupts */
        return 0;
 }
 
 int i810_irq_uninstall(drm_device_t *dev)
 {
        int irq;
+       u16 temp;
 
        down(&dev->struct_sem);
        irq      = dev->irq;
@@ -636,16 +566,25 @@ int i810_irq_uninstall(drm_device_t *dev)
        up(&dev->struct_sem);
        
        if (!irq) return -EINVAL;
-       
+
+       DRM_DEBUG(  "Interrupt UnInstall: %d\n", irq);  
        DRM_DEBUG("%d\n", irq);
-       
-       /* TODO : Disable interrupts */
+   
+       temp = I810_READ16(I810REG_INT_IDENTITY_R);
+       temp = temp & ~(0x6000);
+       if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R, 
+                                  temp); /* Clear all interrupts */
+   
+       temp = I810_READ16(I810REG_INT_ENABLE_R);
+       temp = temp & 0x6000;
+       I810_WRITE16(I810REG_INT_ENABLE_R, 
+                    temp);                     /* Disable all interrupts */
+
        free_irq(irq, dev);
 
        return 0;
 }
 
-
 int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,
                  unsigned long arg)
 {
@@ -654,8 +593,7 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,
        drm_control_t   ctl;
        int             retcode;
    
-       printk(KERN_INFO "i810_control\n");
-       i810_dma_init(dev);
+       DRM_DEBUG(  "i810_control\n");
 
        copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT);
        
@@ -674,20 +612,134 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,
        return 0;
 }
 
+static inline void i810_dma_emit_flush(drm_device_t *dev)
+{
+       drm_i810_private_t *dev_priv = dev->dev_private;
+       RING_LOCALS;
+
+       i810_kernel_lost_context(dev);
+       BEGIN_LP_RING(2);
+       OUT_RING( CMD_REPORT_HEAD );
+       OUT_RING( GFX_OP_USER_INTERRUPT );
+       ADVANCE_LP_RING();
+}
+
+static inline void i810_dma_quiescent_emit(drm_device_t *dev)
+{
+       drm_i810_private_t *dev_priv = dev->dev_private;
+       RING_LOCALS;
+
+       i810_kernel_lost_context(dev);
+       BEGIN_LP_RING(4);
+
+       OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
+       OUT_RING( CMD_REPORT_HEAD );
+       OUT_RING( GFX_OP_USER_INTERRUPT );
+       OUT_RING( 0 );
+       ADVANCE_LP_RING();
+}
+
+static void i810_dma_quiescent(drm_device_t *dev)
+{
+       DECLARE_WAITQUEUE(entry, current);
+       drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+       unsigned long end;      
+
+       if(dev_priv == NULL) {
+               return;
+       }
+       atomic_set(&dev_priv->flush_done, 0);
+       current->state = TASK_INTERRUPTIBLE;
+       add_wait_queue(&dev_priv->flush_queue, &entry);
+       end = jiffies + (HZ*3);
+   
+       for (;;) {
+               i810_dma_quiescent_emit(dev);
+               if (atomic_read(&dev_priv->flush_done) == 1) break;
+               if((signed)(end - jiffies) <= 0) {
+                       DRM_ERROR("lockup\n");
+                       break;
+               }          
+               schedule_timeout(HZ*3);
+               if (signal_pending(current)) {
+                       break;
+               }
+       }
+   
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&dev_priv->flush_queue, &entry);
+   
+       return;
+}
+
+static int i810_flush_queue(drm_device_t *dev)
+{
+       DECLARE_WAITQUEUE(entry, current);
+       drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+       unsigned long end;
+       int ret = 0;      
+
+       if(dev_priv == NULL) {
+               return 0;
+       }
+       atomic_set(&dev_priv->flush_done, 0);
+       current->state = TASK_INTERRUPTIBLE;
+       add_wait_queue(&dev_priv->flush_queue, &entry);
+       end = jiffies + (HZ*3);
+       for (;;) {
+               i810_dma_emit_flush(dev);
+               if (atomic_read(&dev_priv->flush_done) == 1) break;
+               if((signed)(end - jiffies) <= 0) {
+                       DRM_ERROR("lockup\n");
+                       break;
+               }          
+               schedule_timeout(HZ*3);
+               if (signal_pending(current)) {
+                       ret = -EINTR; /* Can't restart */
+                       break;
+               }
+       }
+   
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&dev_priv->flush_queue, &entry);
+   
+       return ret;
+}
+
+/* Must be called with the lock held */
+void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)
+{
+       drm_device_dma_t *dma = dev->dma;
+       int              i;
+
+       if (!dma) return;
+       if(dev->dev_private == NULL) return;
+
+        i810_flush_queue(dev);
+
+       for (i = 0; i < dma->buf_count; i++) {
+               drm_buf_t *buf = dma->buflist[ i ];
+               drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+
+               if (buf->pid == pid) {
+                       /* Only buffers that need to get reclaimed ever 
+                        * get set to free */
+                       if(buf_priv == NULL) return;
+                       cmpxchg(buf_priv->in_use, 
+                               I810_BUF_USED, I810_BUF_FREE);
+               }
+       }
+}
+
 int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
               unsigned long arg)
 {
        drm_file_t        *priv   = filp->private_data;
        drm_device_t      *dev    = priv->dev;
+
        DECLARE_WAITQUEUE(entry, current);
        int               ret   = 0;
        drm_lock_t        lock;
-       drm_queue_t       *q;
-#if DRM_DMA_HISTOGRAM
-       cycles_t          start;
-
-       dev->lck_start = start = get_cycles();
-#endif
 
        copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
 
@@ -696,16 +748,20 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
                          current->pid, lock.context);
                return -EINVAL;
        }
+   
+       DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+                 lock.context, current->pid, dev->lock.hw_lock->lock,
+                 lock.flags);
 
-       if (lock.context < 0 || lock.context >= dev->queue_count) {
+       if (lock.context < 0) {
                return -EINVAL;
        }
-       q = dev->queuelist[lock.context];
-       
-       ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
+       /* Only one queue:
+        */
 
        if (!ret) {
-               if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
+#if 0
+               if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
                    != lock.context) {
                        long j = jiffies - dev->lock.lock_time;
 
@@ -716,6 +772,7 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
                                schedule_timeout(j);
                        }
                }
+#endif
                add_wait_queue(&dev->lock.lock_queue, &entry);
                for (;;) {
                        if (!dev->lock.hw_lock) {
@@ -728,13 +785,13 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
                                dev->lock.pid       = current->pid;
                                dev->lock.lock_time = jiffies;
                                atomic_inc(&dev->total_locks);
-                               atomic_inc(&q->total_locks);
                                break;  /* Got lock */
                        }
                        
                                /* Contention */
                        atomic_inc(&dev->total_sleeps);
                        current->state = TASK_INTERRUPTIBLE;
+                       DRM_DEBUG("Calling lock schedule\n");
                        schedule();
                        if (signal_pending(current)) {
                                ret = -ERESTARTSYS;
@@ -744,19 +801,184 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
                current->state = TASK_RUNNING;
                remove_wait_queue(&dev->lock.lock_queue, &entry);
        }
-
-       drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */
        
        if (!ret) {
-               if (lock.flags & _DRM_LOCK_READY)
-                       i810_dma_ready(dev);
-               if (lock.flags & _DRM_LOCK_QUIESCENT)
-                       i810_dma_quiescent(dev);
+               if (lock.flags & _DRM_LOCK_QUIESCENT) {
+                  DRM_DEBUG("_DRM_LOCK_QUIESCENT\n");
+                  DRM_DEBUG("fred\n");
+                  i810_dma_quiescent(dev);
+               }
        }
+       DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+       return ret;
+}
 
-#if DRM_DMA_HISTOGRAM
-       atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
-#endif
+int i810_flush_ioctl(struct inode *inode, struct file *filp, 
+                    unsigned int cmd, unsigned long arg)
+{
+       drm_file_t        *priv   = filp->private_data;
+       drm_device_t      *dev    = priv->dev;
+   
+       DRM_DEBUG("i810_flush_ioctl\n");
+       if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i810_flush_ioctl called without lock held\n");
+               return -EINVAL;
+       }
+
+       i810_flush_queue(dev);
+       return 0;
+}
+
+static int i810DmaGeneral(drm_device_t *dev, drm_i810_general_t *args)
+{
+       drm_device_dma_t *dma = dev->dma;
+       drm_buf_t *buf = dma->buflist[ args->idx ];
+       
+       if (!args->used) {
+               i810_freelist_put(dev, buf);
+       } else {  
+               i810_dma_dispatch_general( dev, buf, args->used );
+               atomic_add(args->used, &dma->total_bytes);
+               atomic_inc(&dma->total_dmas);
+       }
+       return 0; 
+}
+
+static int i810DmaVertex(drm_device_t *dev, drm_i810_vertex_t *args)
+{
+       drm_device_dma_t *dma = dev->dma;
+       drm_buf_t *buf = dma->buflist[ args->idx ];
+       i810_dma_dispatch_vertex( dev, buf, args->discard, args->used );
+       atomic_add(args->used, &dma->total_bytes);
+       atomic_inc(&dma->total_dmas);
+       return 0;
+}
+
+int i810_dma_general(struct inode *inode, struct file *filp,
+                    unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->dev;
+       drm_i810_general_t general;
+       drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+       u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+       drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+                                       dev_priv->sarea_priv; 
+
+       int retcode = 0;
        
-       return ret;
+       copy_from_user_ret(&general, (drm_i810_general_t *)arg, sizeof(general),
+                          -EFAULT);
+
+       DRM_DEBUG("i810 dma general idx %d used %d\n",
+                 general.idx, general.used);
+   
+       if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i810_dma_general called without lock held\n");
+               return -EINVAL;
+       }
+
+       retcode = i810DmaGeneral(dev, &general);
+       sarea_priv->last_enqueue = dev_priv->counter-1;
+       sarea_priv->last_dispatch = (int) hw_status[5];
+   
+       return retcode;
+}
+
+int i810_dma_vertex(struct inode *inode, struct file *filp,
+              unsigned int cmd, unsigned long arg)
+{
+       drm_file_t *priv = filp->private_data;
+       drm_device_t *dev = priv->dev;
+       drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+       u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+       drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+                                       dev_priv->sarea_priv; 
+       drm_i810_vertex_t vertex;
+       int retcode = 0;
+
+       copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex),
+                          -EFAULT);
+       if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i810_dma_vertex called without lock held\n");
+               return -EINVAL;
+       }
+
+       DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
+                 vertex.idx, vertex.used, vertex.discard);
+
+       retcode = i810DmaVertex(dev, &vertex);
+       sarea_priv->last_enqueue = dev_priv->counter-1;
+       sarea_priv->last_dispatch = (int) hw_status[5];
+   
+       return retcode;
+
+}
+
+int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
+               unsigned long arg)
+{
+       drm_file_t        *priv     = filp->private_data;
+       drm_device_t      *dev      = priv->dev;
+       drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+       u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+       drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+                                       dev_priv->sarea_priv; 
+
+       sarea_priv->last_dispatch = (int) hw_status[5];
+       return 0;
+}
+
+int i810_dma(struct inode *inode, struct file *filp, unsigned int cmd,
+           unsigned long arg)
+{
+       drm_file_t        *priv     = filp->private_data;
+       drm_device_t      *dev      = priv->dev;
+       drm_device_dma_t  *dma      = dev->dma;
+       int               retcode   = 0;
+       drm_dma_t         d;
+       drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+       u32 *hw_status = (u32 *)dev_priv->hw_status_page;
+       drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) 
+                                       dev_priv->sarea_priv; 
+
+
+       copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT);
+       DRM_DEBUG("%d %d: %d send, %d req\n",
+                 current->pid, d.context, d.send_count, d.request_count);
+   
+       if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+               DRM_ERROR("i810_dma called without lock held\n");
+               return -EINVAL;
+       }
+
+       /* Please don't send us buffers.
+        */
+       if (d.send_count != 0) {
+               DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
+                         current->pid, d.send_count);
+               return -EINVAL;
+       }
+       
+       /* We'll send you buffers.
+        */
+       if (d.request_count < 0 || d.request_count > dma->buf_count) {
+               DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+                         current->pid, d.request_count, dma->buf_count);
+               return -EINVAL;
+       }
+       
+       d.granted_count = 0;
+
+       if (!retcode && d.request_count) {
+               retcode = i810_dma_get_buffers(dev, &d);
+       }
+
+       DRM_DEBUG("i810_dma: %d returning, granted = %d\n",
+                 current->pid, d.granted_count);
+
+       copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);   
+       sarea_priv->last_dispatch = (int) hw_status[5];
+
+       return retcode;
 }