summaryrefslogtreecommitdiff
path: root/linux-core/i810_dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core/i810_dma.c')
-rw-r--r--linux-core/i810_dma.c712
1 files changed, 540 insertions, 172 deletions
diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c
index 6ac4d2ee..f041f209 100644
--- a/linux-core/i810_dma.c
+++ b/linux-core/i810_dma.c
@@ -37,8 +37,12 @@
#include <linux/interrupt.h> /* For task queue support */
-#define I810_BUF_FREE 1
-#define I810_BUF_USED 0
+#define I810_BUF_FREE 2
+#define I810_BUF_CLIENT 1
+#define I810_BUF_HARDWARE 0
+
+#define I810_BUF_UNMAPPED 0
+#define I810_BUF_MAPPED 1
#define I810_REG(reg) 2
#define I810_BASE(reg) ((unsigned long) \
@@ -91,7 +95,7 @@ static inline void i810_print_status_page(drm_device_t *dev)
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]);
+ DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 6, temp[i]);
}
}
@@ -108,7 +112,7 @@ static drm_buf_t *i810_freelist_get(drm_device_t *dev)
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);
+ I810_BUF_CLIENT);
if(used == I810_BUF_FREE) {
return buf;
}
@@ -126,8 +130,8 @@ static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)
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) {
+ used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE);
+ if(used != I810_BUF_CLIENT) {
DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
return -EINVAL;
}
@@ -135,26 +139,114 @@ static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)
return 0;
}
-static int i810_dma_get_buffers(drm_device_t *dev, drm_dma_t *d)
+static struct file_operations i810_buffer_fops = {
+ open: i810_open,
+ flush: drm_flush,
+ release: i810_release,
+ ioctl: i810_ioctl,
+ mmap: i810_mmap_buffers,
+ read: drm_read,
+ fasync: drm_fasync,
+ poll: drm_poll,
+};
+
+int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_buf_t *buf = dev_priv->mmap_buffer;
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+
+ vma->vm_flags |= (VM_IO | VM_DONTCOPY);
+ vma->vm_file = filp;
+
+ buf_priv->currently_mapped = I810_BUF_MAPPED;
+
+ if (remap_page_range(vma->vm_start,
+ VM_OFFSET(vma),
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) return -EAGAIN;
+ return 0;
+}
+
+static int i810_map_buffer(drm_buf_t *buf, struct file *filp)
{
- int i;
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ struct file_operations *old_fops;
+ int retcode = 0;
+
+ if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL;
+ down(&current->mm->mmap_sem);
+ old_fops = filp->f_op;
+ filp->f_op = &i810_buffer_fops;
+ dev_priv->mmap_buffer = buf;
+ buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total,
+ PROT_READ|PROT_WRITE,
+ MAP_SHARED,
+ buf->bus_address);
+ dev_priv->mmap_buffer = NULL;
+ filp->f_op = old_fops;
+ if ((unsigned long)buf_priv->virtual > -1024UL) {
+ /* Real error */
+ DRM_DEBUG("mmap error\n");
+ retcode = (signed int)buf_priv->virtual;
+ buf_priv->virtual = 0;
+ }
+ up(&current->mm->mmap_sem);
+ return retcode;
+}
+
+static int i810_unmap_buffer(drm_buf_t *buf)
+{
+ drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+ int retcode = 0;
+
+ if(buf_priv->currently_mapped != I810_BUF_MAPPED) return -EINVAL;
+ down(&current->mm->mmap_sem);
+ retcode = do_munmap((unsigned long)buf_priv->virtual,
+ (size_t) buf->total);
+ buf_priv->currently_mapped = I810_BUF_UNMAPPED;
+ buf_priv->virtual = 0;
+ up(&current->mm->mmap_sem);
+
+ return retcode;
+}
+
+static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,
+ struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
drm_buf_t *buf;
+ drm_i810_buf_priv_t *buf_priv;
+ int retcode = 0;
- 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;
+ buf = i810_freelist_get(dev);
+ if (!buf) {
+ retcode = -ENOMEM;
+ DRM_DEBUG("%s retcode %d\n", __FUNCTION__, retcode);
+ goto out_get_buf;
}
- return 0;
+
+ retcode = i810_map_buffer(buf, filp);
+ if(retcode) {
+ i810_freelist_put(dev, buf);
+ DRM_DEBUG("mapbuf failed in %s retcode %d\n",
+ __FUNCTION__, retcode);
+ goto out_get_buf;
+ }
+ buf->pid = priv->pid;
+ buf_priv = buf->dev_private;
+ d->granted = 1;
+ d->request_idx = buf->idx;
+ d->request_size = buf->total;
+ d->virtual = buf_priv->virtual;
+
+out_get_buf:
+ return retcode;
}
static unsigned long i810_alloc_page(drm_device_t *dev)
@@ -185,7 +277,10 @@ static void i810_free_page(drm_device_t *dev, unsigned long page)
static int i810_dma_cleanup(drm_device_t *dev)
{
+ drm_device_dma_t *dma = dev->dma;
+
if(dev->dev_private) {
+ int i;
drm_i810_private_t *dev_priv =
(drm_i810_private_t *) dev->dev_private;
@@ -201,6 +296,12 @@ static int i810_dma_cleanup(drm_device_t *dev)
drm_free(dev->dev_private, sizeof(drm_i810_private_t),
DRM_MEM_DRIVER);
dev->dev_private = NULL;
+
+ 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;
+ drm_ioremapfree(buf_priv->kernel_virtual, buf->total);
+ }
}
return 0;
}
@@ -211,6 +312,7 @@ static int i810_wait_ring(drm_device_t *dev, int n)
drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
int iters = 0;
unsigned long end;
+ unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
end = jiffies + (HZ*3);
while (ring->space < n) {
@@ -218,9 +320,11 @@ static int i810_wait_ring(drm_device_t *dev, int n)
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;
- if (ring->space < 0) ring->space += ring->Size;
-
+ if (ring->head != last_head)
+ end = jiffies + (HZ*3);
+
iters++;
if((signed)(end - jiffies) <= 0) {
DRM_ERROR("space: %d wanted %d\n", ring->space, n);
@@ -250,9 +354,9 @@ static int i810_freelist_init(drm_device_t *dev)
{
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;
+ u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
+ int i;
if(dma->buf_count > 1019) {
/* Not enough space in the status page for the freelist */
@@ -263,11 +367,14 @@ static int i810_freelist_init(drm_device_t *dev)
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->in_use = hw_status++;
buf_priv->my_use_idx = my_idx;
my_idx += 4;
+
+ *buf_priv->in_use = I810_BUF_FREE;
+
+ buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
+ buf->total);
}
return 0;
}
@@ -301,9 +408,11 @@ static int i810_dma_initialize(drm_device_t *dev,
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) {
@@ -312,6 +421,17 @@ static int i810_dma_initialize(drm_device_t *dev,
" ring buffer\n");
return -ENOMEM;
}
+
+ dev_priv->w = init->w;
+ dev_priv->h = init->h;
+ dev_priv->pitch = init->pitch;
+ dev_priv->back_offset = init->back_offset;
+ dev_priv->depth_offset = init->depth_offset;
+
+ dev_priv->front_di1 = init->front_offset | init->pitch_bits;
+ dev_priv->back_di1 = init->back_offset | init->pitch_bits;
+ dev_priv->zi1 = init->depth_offset | init->pitch_bits;
+
/* Program Hardware Status Page */
dev_priv->hw_status_page = i810_alloc_page(dev);
@@ -366,37 +486,270 @@ int i810_dma_init(struct inode *inode, struct file *filp,
return retcode;
}
-static void i810_dma_dispatch_general(drm_device_t *dev, drm_buf_t *buf,
- int used )
+
+
+/* Most efficient way to verify state for the i810 is as it is
+ * emitted. Non-conformant state is silently dropped.
+ *
+ * Use 'volatile' & local var tmp to force the emitted values to be
+ * identical to the verified ones.
+ */
+static void i810EmitContextVerified( drm_device_t *dev,
+ volatile unsigned int *code )
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ int i, j = 0;
+ unsigned int tmp;
+ RING_LOCALS;
+
+ BEGIN_LP_RING( I810_CTX_SETUP_SIZE );
+
+ OUT_RING( GFX_OP_COLOR_FACTOR );
+ OUT_RING( code[I810_CTXREG_CF1] );
+
+ OUT_RING( GFX_OP_STIPPLE );
+ OUT_RING( code[I810_CTXREG_ST1] );
+
+ for ( i = 4 ; i < I810_CTX_SETUP_SIZE ; i++ ) {
+ tmp = code[i];
+
+ if ((tmp & (7<<29)) == (3<<29) &&
+ (tmp & (0x1f<<24)) < (0x1d<<24))
+ {
+ OUT_RING( tmp );
+ j++;
+ }
+ }
+
+ if (j & 1)
+ OUT_RING( 0 );
+
+ ADVANCE_LP_RING();
+}
+
+static void i810EmitTexVerified( drm_device_t *dev,
+ volatile unsigned int *code )
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ int i, j = 0;
+ unsigned int tmp;
+ RING_LOCALS;
+
+ BEGIN_LP_RING( I810_TEX_SETUP_SIZE );
+
+ OUT_RING( GFX_OP_MAP_INFO );
+ OUT_RING( code[I810_TEXREG_MI1] );
+ OUT_RING( code[I810_TEXREG_MI2] );
+ OUT_RING( code[I810_TEXREG_MI3] );
+
+ for ( i = 4 ; i < I810_TEX_SETUP_SIZE ; i++ ) {
+ tmp = code[i];
+
+ if ((tmp & (7<<29)) == (3<<29) &&
+ (tmp & (0x1f<<24)) < (0x1d<<24))
+ {
+ OUT_RING( tmp );
+ j++;
+ }
+ }
+
+ if (j & 1)
+ OUT_RING( 0 );
+
+ ADVANCE_LP_RING();
+}
+
+
+/* Need to do some additional checking when setting the dest buffer.
+ */
+static void i810EmitDestVerified( drm_device_t *dev,
+ volatile unsigned int *code )
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ unsigned int tmp;
+ RING_LOCALS;
+
+ BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 );
+
+ tmp = code[I810_DESTREG_DI1];
+ if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
+ OUT_RING( CMD_OP_DESTBUFFER_INFO );
+ OUT_RING( tmp );
+ } else
+ DRM_DEBUG("bad di1 %x (allow %x or %x)\n",
+ tmp, dev_priv->front_di1, dev_priv->back_di1);
+
+ /* invarient:
+ */
+ OUT_RING( CMD_OP_Z_BUFFER_INFO );
+ OUT_RING( dev_priv->zi1 );
+
+ OUT_RING( GFX_OP_DESTBUFFER_VARS );
+ OUT_RING( code[I810_DESTREG_DV1] );
+
+ OUT_RING( GFX_OP_DRAWRECT_INFO );
+ OUT_RING( code[I810_DESTREG_DR1] );
+ OUT_RING( code[I810_DESTREG_DR2] );
+ OUT_RING( code[I810_DESTREG_DR3] );
+ OUT_RING( code[I810_DESTREG_DR4] );
+ OUT_RING( 0 );
+
+ ADVANCE_LP_RING();
+}
+
+
+
+static void i810EmitState( drm_device_t *dev )
{
- 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;
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ unsigned int dirty = sarea_priv->dirty;
- 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);
+ if (dirty & I810_UPLOAD_BUFFERS) {
+ i810EmitDestVerified( dev, sarea_priv->BufferState );
+ sarea_priv->dirty &= ~I810_UPLOAD_BUFFERS;
+ }
- 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 (dirty & I810_UPLOAD_CTX) {
+ i810EmitContextVerified( dev, sarea_priv->ContextState );
+ sarea_priv->dirty &= ~I810_UPLOAD_CTX;
+ }
+
+ if (dirty & I810_UPLOAD_TEX0) {
+ i810EmitTexVerified( dev, sarea_priv->TexState[0] );
+ sarea_priv->dirty &= ~I810_UPLOAD_TEX0;
+ }
+
+ if (dirty & I810_UPLOAD_TEX1) {
+ i810EmitTexVerified( dev, sarea_priv->TexState[1] );
+ sarea_priv->dirty &= ~I810_UPLOAD_TEX1;
+ }
+}
+
+
+
+/* need to verify
+ */
+static void i810_dma_dispatch_clear( drm_device_t *dev, int flags,
+ unsigned int clear_color,
+ unsigned int clear_zval )
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ int nbox = sarea_priv->nbox;
+ drm_clip_rect_t *pbox = sarea_priv->boxes;
+ int pitch = dev_priv->pitch;
+ int cpp = 2;
+ int i;
+ RING_LOCALS;
+
+ i810_kernel_lost_context(dev);
+
+ if (nbox > I810_NR_SAREA_CLIPRECTS)
+ nbox = I810_NR_SAREA_CLIPRECTS;
+
+ for (i = 0 ; i < nbox ; i++, pbox++) {
+ unsigned int x = pbox->x1;
+ unsigned int y = pbox->y1;
+ unsigned int width = (pbox->x2 - x) * cpp;
+ unsigned int height = pbox->y2 - y;
+ unsigned int start = y * pitch + x * cpp;
+
+ if (pbox->x1 > pbox->x2 ||
+ pbox->y1 > pbox->y2 ||
+ pbox->x2 > dev_priv->w ||
+ pbox->y2 > dev_priv->h)
+ continue;
+
+ if ( flags & I810_FRONT ) {
+ DRM_DEBUG("clear front\n");
+ BEGIN_LP_RING( 6 );
+ OUT_RING( BR00_BITBLT_CLIENT |
+ BR00_OP_COLOR_BLT | 0x3 );
+ OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
+ OUT_RING( (height << 16) | width );
+ OUT_RING( start );
+ OUT_RING( clear_color );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+ }
+
+ if ( flags & I810_BACK ) {
+ DRM_DEBUG("clear back\n");
+ BEGIN_LP_RING( 6 );
+ OUT_RING( BR00_BITBLT_CLIENT |
+ BR00_OP_COLOR_BLT | 0x3 );
+ OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
+ OUT_RING( (height << 16) | width );
+ OUT_RING( dev_priv->back_offset + start );
+ OUT_RING( clear_color );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+ }
+
+ if ( flags & I810_DEPTH ) {
+ DRM_DEBUG("clear depth\n");
+ BEGIN_LP_RING( 6 );
+ OUT_RING( BR00_BITBLT_CLIENT |
+ BR00_OP_COLOR_BLT | 0x3 );
+ OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch );
+ OUT_RING( (height << 16) | width );
+ OUT_RING( dev_priv->depth_offset + start );
+ OUT_RING( clear_zval );
+ OUT_RING( 0 );
+ ADVANCE_LP_RING();
+ }
+ }
+}
+
+static void i810_dma_dispatch_swap( drm_device_t *dev )
+{
+ drm_i810_private_t *dev_priv = dev->dev_private;
+ drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ int nbox = sarea_priv->nbox;
+ drm_clip_rect_t *pbox = sarea_priv->boxes;
+ int pitch = dev_priv->pitch;
+ int cpp = 2;
+ int ofs = dev_priv->back_offset;
+ int i;
+ RING_LOCALS;
+
+ DRM_DEBUG("swapbuffers\n");
+
+ i810_kernel_lost_context(dev);
+
+ if (nbox > I810_NR_SAREA_CLIPRECTS)
+ nbox = I810_NR_SAREA_CLIPRECTS;
+
+ for (i = 0 ; i < nbox; i++, pbox++)
+ {
+ unsigned int w = pbox->x2 - pbox->x1;
+ unsigned int h = pbox->y2 - pbox->y1;
+ unsigned int dst = pbox->x1*cpp + pbox->y1*pitch;
+ unsigned int start = ofs + dst;
+
+ if (pbox->x1 > pbox->x2 ||
+ pbox->y1 > pbox->y2 ||
+ pbox->x2 > dev_priv->w ||
+ pbox->y2 > dev_priv->h)
+ continue;
+
+ DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
+ pbox[i].x1, pbox[i].y1,
+ pbox[i].x2, pbox[i].y2);
+
+ BEGIN_LP_RING( 6 );
+ OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 );
+ OUT_RING( pitch | (0xCC << 16));
+ OUT_RING( (h << 16) | (w * cpp));
+ OUT_RING( dst );
+ OUT_RING( pitch );
+ OUT_RING( start );
+ ADVANCE_LP_RING();
+ }
}
+
static void i810_dma_dispatch_vertex(drm_device_t *dev,
drm_buf_t *buf,
int discard,
@@ -409,14 +762,29 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,
int nbox = sarea_priv->nbox;
unsigned long address = (unsigned long)buf->bus_address;
unsigned long start = address - dev->agp->base;
- int i = 0;
+ int i = 0, u;
RING_LOCALS;
-
+ i810_kernel_lost_context(dev);
+
if (nbox > I810_NR_SAREA_CLIPRECTS)
nbox = I810_NR_SAREA_CLIPRECTS;
-
- DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",
+
+ if (discard) {
+ u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
+ I810_BUF_HARDWARE);
+ if(u != I810_BUF_CLIENT) {
+ DRM_DEBUG("xxxx 2\n");
+ }
+ }
+
+ if (used > 4*1024)
+ used = 0;
+
+ if (sarea_priv->dirty)
+ i810EmitState( dev );
+
+ DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",
address, used, nbox);
dev_priv->counter++;
@@ -425,8 +793,20 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,
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 (buf_priv->currently_mapped == I810_BUF_MAPPED) {
+ *(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE |
+ sarea_priv->vertex_prim |
+ ((used/4)-2));
+
+ if (used & 4) {
+ *(u32 *)((u32)buf_priv->virtual + used) = 0;
+ used += 4;
+ }
+
+ i810_unmap_buffer(buf);
+ }
+
if (used) {
do {
if (i < nbox) {
@@ -434,7 +814,7 @@ static void i810_dma_dispatch_vertex(drm_device_t *dev,
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].x1 | (box[i].y1<<16) );
OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) );
ADVANCE_LP_RING();
}
@@ -479,7 +859,9 @@ static void i810_dma_service(int irq, void *device, struct pt_regs *regs)
temp = temp & ~(0x6000);
if(temp != 0) I810_WRITE16(I810REG_INT_IDENTITY_R,
temp); /* Clear all interrupts */
-
+ else
+ return;
+
queue_task(&dev->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
@@ -539,7 +921,7 @@ int i810_irq_install(drm_device_t *dev, int irq)
/* Install handler */
if ((retcode = request_irq(dev->irq,
i810_dma_service,
- 0,
+ SA_SHIRQ,
dev->devname,
dev))) {
down(&dev->struct_sem);
@@ -560,6 +942,9 @@ int i810_irq_uninstall(drm_device_t *dev)
int irq;
u16 temp;
+
+/* return 0; */
+
down(&dev->struct_sem);
irq = dev->irq;
dev->irq = 0;
@@ -618,10 +1003,15 @@ static inline void i810_dma_emit_flush(drm_device_t *dev)
RING_LOCALS;
i810_kernel_lost_context(dev);
+
BEGIN_LP_RING(2);
OUT_RING( CMD_REPORT_HEAD );
- OUT_RING( GFX_OP_USER_INTERRUPT );
+ OUT_RING( GFX_OP_USER_INTERRUPT );
ADVANCE_LP_RING();
+
+/* i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */
+/* atomic_set(&dev_priv->flush_done, 1); */
+/* wake_up_interruptible(&dev_priv->flush_queue); */
}
static inline void i810_dma_quiescent_emit(drm_device_t *dev)
@@ -630,13 +1020,17 @@ static inline void i810_dma_quiescent_emit(drm_device_t *dev)
RING_LOCALS;
i810_kernel_lost_context(dev);
- BEGIN_LP_RING(4);
+ 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 );
+ OUT_RING( 0 );
+ OUT_RING( GFX_OP_USER_INTERRUPT );
ADVANCE_LP_RING();
+
+/* i810_wait_ring( dev, dev_priv->ring.Size - 8 ); */
+/* atomic_set(&dev_priv->flush_done, 1); */
+/* wake_up_interruptible(&dev_priv->flush_queue); */
}
static void i810_dma_quiescent(drm_device_t *dev)
@@ -676,8 +1070,9 @@ 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;
+ drm_device_dma_t *dma = dev->dma;
unsigned long end;
- int ret = 0;
+ int i, ret = 0;
if(dev_priv == NULL) {
return 0;
@@ -702,7 +1097,21 @@ static int i810_flush_queue(drm_device_t *dev)
current->state = TASK_RUNNING;
remove_wait_queue(&dev_priv->flush_queue, &entry);
-
+
+
+ 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;
+
+ int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE,
+ I810_BUF_FREE);
+
+ if (used == I810_BUF_HARDWARE)
+ DRM_DEBUG("reclaimed from HARDWARE\n");
+ if (used == I810_BUF_CLIENT)
+ DRM_DEBUG("still on client HARDWARE\n");
+ }
+
return ret;
}
@@ -713,20 +1122,23 @@ void i810_reclaim_buffers(drm_device_t *dev, pid_t pid)
int i;
if (!dma) return;
- if(dev->dev_private == NULL) return;
- if(dma->buflist == NULL) return;
+ if (!dev->dev_private) return;
+ if (!dma->buflist) 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;
- /* Only buffers that need to get reclaimed ever
- * get set to free
- */
if (buf->pid == pid && buf_priv) {
- cmpxchg(buf_priv->in_use,
- I810_BUF_USED, I810_BUF_FREE);
+ int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT,
+ I810_BUF_FREE);
+
+ if (used == I810_BUF_CLIENT)
+ DRM_DEBUG("reclaimed from client\n");
+ if(buf_priv->currently_mapped == I810_BUF_MAPPED)
+ buf_priv->currently_mapped = I810_BUF_UNMAPPED;
}
}
}
@@ -760,19 +1172,6 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
*/
if (!ret) {
-#if 0
- if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
- != lock.context) {
- long j = jiffies - dev->lock.lock_time;
-
- if (j > 0 && j <= DRM_LOCK_SLICE) {
- /* Can't take lock if we just had it and
- there is contention. */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(j);
- }
- }
-#endif
add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
if (!dev->lock.hw_lock) {
@@ -829,90 +1228,80 @@ int i810_flush_ioctl(struct inode *inode, struct file *filp,
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)
+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_general_t general;
- drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private;
+ drm_device_dma_t *dma = dev->dma;
+ 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(&general, (drm_i810_general_t *)arg, sizeof(general),
+ copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex),
-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");
+ DRM_ERROR("i810_dma_vertex called without lock held\n");
return -EINVAL;
}
- retcode = i810DmaGeneral(dev, &general);
+ DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n",
+ vertex.idx, vertex.used, vertex.discard);
+
+ i810_dma_dispatch_vertex( dev,
+ dma->buflist[ vertex.idx ],
+ vertex.discard, vertex.used );
+
+ atomic_add(vertex.used, &dma->total_bytes);
+ atomic_inc(&dma->total_dmas);
sarea_priv->last_enqueue = dev_priv->counter-1;
sarea_priv->last_dispatch = (int) hw_status[5];
- return retcode;
+ return 0;
}
-int i810_dma_vertex(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+
+
+int i810_clear_bufs(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;
+ drm_i810_clear_t clear;
- copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex),
+ copy_from_user_ret(&clear, (drm_i810_clear_t *)arg, sizeof(clear),
-EFAULT);
+
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
- DRM_ERROR("i810_dma_vertex called without lock held\n");
+ DRM_ERROR("i810_clear_bufs 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);
+ i810_dma_dispatch_clear( dev, clear.flags,
+ clear.clear_color,
+ clear.clear_depth );
+ return 0;
+}
- retcode = i810DmaVertex(dev, &vertex);
- sarea_priv->last_enqueue = dev_priv->counter-1;
- sarea_priv->last_dispatch = (int) hw_status[5];
+int i810_swap_bufs(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;
- return retcode;
+ DRM_DEBUG("i810_swap_bufs\n");
+ if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+ DRM_ERROR("i810_swap_buf called without lock held\n");
+ return -EINVAL;
+ }
+
+ i810_dma_dispatch_swap( dev );
+ return 0;
}
int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
@@ -929,53 +1318,32 @@ int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
}
-int i810_dma(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+int i810_getbuf(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_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);
+ DRM_DEBUG("getbuf\n");
+ copy_from_user_ret(&d, (drm_i810_dma_t *)arg, sizeof(d), -EFAULT);
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;
+ d.granted = 0;
- if (!retcode && d.request_count) {
- retcode = i810_dma_get_buffers(dev, &d);
- }
+ retcode = i810_dma_get_buffer(dev, &d, filp);
- DRM_DEBUG("i810_dma: %d returning, granted = %d\n",
- current->pid, d.granted_count);
+ DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
+ current->pid, retcode, d.granted);
copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
sarea_priv->last_dispatch = (int) hw_status[5];