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 /* 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,28 +139,116 @@ 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) -{ - int i; - drm_buf_t *buf; +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, +}; - 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; - } +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) +{ + 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(¤t->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(¤t->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(¤t->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(¤t->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; + + buf = i810_freelist_get(dev); + if (!buf) { + retcode = -ENOMEM; + DRM_DEBUG("%s retcode %d\n", __FUNCTION__, retcode); + goto out_get_buf; + } + + 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) { unsigned long address; @@ -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 ) -{ - 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(); +/* 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_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + + if (dirty & I810_UPLOAD_BUFFERS) { + i810EmitDestVerified( dev, sarea_priv->BufferState ); + sarea_priv->dirty &= ~I810_UPLOAD_BUFFERS; + } + + 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,76 +1228,22 @@ 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) -{ - 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; - - 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_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(&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; @@ -907,12 +1252,56 @@ int i810_dma_vertex(struct inode *inode, struct file *filp, DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", vertex.idx, vertex.used, vertex.discard); - retcode = i810DmaVertex(dev, &vertex); + 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_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_clear_t clear; + + 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_clear_bufs called without lock held\n"); + return -EINVAL; + } + + i810_dma_dispatch_clear( dev, clear.flags, + clear.clear_color, + clear.clear_depth ); + return 0; +} + +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; + + 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]; diff --git a/linux-core/i810_drm.h b/linux-core/i810_drm.h index 0754874c..4c8e09f6 100644 --- a/linux-core/i810_drm.h +++ b/linux-core/i810_drm.h @@ -5,35 +5,112 @@ * if you change them, you must change the defines in the Xserver. */ -/* Might one day want to support the client-side ringbuffer code again. - */ #ifndef _I810_DEFINES_ #define _I810_DEFINES_ -#define I810_USE_BATCH 1 #define I810_DMA_BUF_ORDER 12 #define I810_DMA_BUF_SZ (1<dev_private = drm_alloc(sizeof(drm_i810_buf_priv_t), DRM_MEM_BUFS); buf->dev_priv_size = sizeof(drm_i810_buf_priv_t); + memset(buf->dev_private, 0, sizeof(drm_i810_buf_priv_t)); #if DRM_DMA_HISTOGRAM buf->time_queued = 0; @@ -332,113 +333,3 @@ int i810_freebufs(struct inode *inode, struct file *filp, unsigned int cmd, return 0; } -int i810_mapbufs(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; - const int zero = 0; - unsigned long virtual; - unsigned long address; - drm_buf_map_t request; - int i; - - if (!dma) return -EINVAL; - - DRM_DEBUG("\n"); - - spin_lock(&dev->count_lock); - if (atomic_read(&dev->buf_alloc)) { - spin_unlock(&dev->count_lock); - DRM_DEBUG("Busy\n"); - return -EBUSY; - } - ++dev->buf_use; /* Can't allocate more after this call */ - spin_unlock(&dev->count_lock); - - copy_from_user_ret(&request, - (drm_buf_map_t *)arg, - sizeof(request), - -EFAULT); - DRM_DEBUG("dma->flags : %lx\n", dma->flags); - if (request.count >= dma->buf_count) { - if(dma->flags & _DRM_DMA_USE_AGP) { - drm_i810_private_t *dev_priv = - (drm_i810_private_t *)dev->dev_private; - drm_map_t *map = NULL; - - map = dev->maplist[dev_priv->buffer_map_idx]; - if (!map) { - DRM_DEBUG("map is null\n"); - retcode = -EINVAL; - goto done; - } - DRM_DEBUG("map->offset : %lx\n", map->offset); - DRM_DEBUG("map->size : %lx\n", map->size); - DRM_DEBUG("map->type : %d\n", map->type); - DRM_DEBUG("map->flags : %x\n", map->flags); - DRM_DEBUG("map->handle : %lx\n", map->handle); - DRM_DEBUG("map->mtrr : %d\n", map->mtrr); - down(¤t->mm->mmap_sem); - virtual = do_mmap(filp, 0, map->size, - PROT_READ|PROT_WRITE, - MAP_SHARED, - (unsigned long)map->offset); - - up(¤t->mm->mmap_sem); - } else { - down(¤t->mm->mmap_sem); - virtual = do_mmap(filp, 0, dma->byte_count, - PROT_READ|PROT_WRITE, MAP_SHARED, 0); - up(¤t->mm->mmap_sem); - } - if (virtual > -1024UL) { - /* Real error */ - DRM_DEBUG("mmap error\n"); - retcode = (signed long)virtual; - goto done; - } - request.virtual = (void *)virtual; - - for (i = 0; i < dma->buf_count; i++) { - if (copy_to_user(&request.list[i].idx, - &dma->buflist[i]->idx, - sizeof(request.list[0].idx))) { - retcode = -EFAULT; - goto done; - } - if (copy_to_user(&request.list[i].total, - &dma->buflist[i]->total, - sizeof(request.list[0].total))) { - retcode = -EFAULT; - goto done; - } - if (copy_to_user(&request.list[i].used, - &zero, - sizeof(zero))) { - retcode = -EFAULT; - goto done; - } - address = virtual + dma->buflist[i]->offset; - if (copy_to_user(&request.list[i].address, - &address, - sizeof(address))) { - retcode = -EFAULT; - goto done; - } - } - } - done: - request.count = dma->buf_count; - DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); - - copy_to_user_ret((drm_buf_map_t *)arg, - &request, - sizeof(request), - -EFAULT); - - DRM_DEBUG("retcode : %d\n", retcode); - return retcode; -} diff --git a/linux/i810_dma.c b/linux/i810_dma.c index 6ac4d2ee..f041f209 100644 --- a/linux/i810_dma.c +++ b/linux/i810_dma.c @@ -37,8 +37,12 @@ #include /* 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,28 +139,116 @@ 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) -{ - int i; - drm_buf_t *buf; +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, +}; - 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; - } +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) +{ + 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(¤t->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(¤t->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(¤t->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(¤t->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; + + buf = i810_freelist_get(dev); + if (!buf) { + retcode = -ENOMEM; + DRM_DEBUG("%s retcode %d\n", __FUNCTION__, retcode); + goto out_get_buf; + } + + 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) { unsigned long address; @@ -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 ) -{ - 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(); +/* 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_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + + if (dirty & I810_UPLOAD_BUFFERS) { + i810EmitDestVerified( dev, sarea_priv->BufferState ); + sarea_priv->dirty &= ~I810_UPLOAD_BUFFERS; + } + + 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,76 +1228,22 @@ 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) -{ - 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; - - 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_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(&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; @@ -907,12 +1252,56 @@ int i810_dma_vertex(struct inode *inode, struct file *filp, DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", vertex.idx, vertex.used, vertex.discard); - retcode = i810DmaVertex(dev, &vertex); + 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_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_clear_t clear; + + 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_clear_bufs called without lock held\n"); + return -EINVAL; + } + + i810_dma_dispatch_clear( dev, clear.flags, + clear.clear_color, + clear.clear_depth ); + return 0; +} + +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; + + 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]; diff --git a/linux/i810_drm.h b/linux/i810_drm.h index 0754874c..4c8e09f6 100644 --- a/linux/i810_drm.h +++ b/linux/i810_drm.h @@ -5,35 +5,112 @@ * if you change them, you must change the defines in the Xserver. */ -/* Might one day want to support the client-side ringbuffer code again. - */ #ifndef _I810_DEFINES_ #define _I810_DEFINES_ -#define I810_USE_BATCH 1 #define I810_DMA_BUF_ORDER 12 #define I810_DMA_BUF_SZ (1<buf != NULL) { - DRM_DEBUG("buf index : %d\n", item->buf->idx); - } else { - DRM_DEBUG("Freelist head\n"); - } - DRM_DEBUG("item->age : %x\n", item->age); - DRM_DEBUG("item->next : %p\n", item->next); - DRM_DEBUG("item->prev : %p\n", item->prev); -} - static int mga_freelist_init(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; @@ -114,7 +107,9 @@ static int mga_freelist_init(drm_device_t *dev) drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_mga_freelist_t *item; int i; - + + DRM_DEBUG("%s\n", __FUNCTION__); + dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); if(dev_priv->head == NULL) return -ENOMEM; memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t)); @@ -136,19 +131,10 @@ static int mga_freelist_init(drm_device_t *dev) item->buf = buf; buf_priv->my_freelist = item; buf_priv->discard = 0; + buf_priv->dispatched = 0; dev_priv->head->next = item; } - item = dev_priv->head; - while(item) { - mga_freelist_debug(item); - item = item->next; - } - DRM_DEBUG("Head\n"); - mga_freelist_debug(dev_priv->head); - DRM_DEBUG("Tail\n"); - mga_freelist_debug(dev_priv->tail); - return 0; } @@ -158,6 +144,8 @@ static void mga_freelist_cleanup(drm_device_t *dev) drm_mga_freelist_t *item; drm_mga_freelist_t *prev; + DRM_DEBUG("%s\n", __FUNCTION__); + item = dev_priv->head; while(item) { prev = item; @@ -174,14 +162,14 @@ static inline void mga_dma_quiescent(drm_device_t *dev) drm_device_dma_t *dma = dev->dma; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; unsigned long end; int i; + DRM_DEBUG("%s\n", __FUNCTION__); end = jiffies + (HZ*3); while(1) { - if(!test_and_set_bit(0, &dev_priv->dispatch_lock)) { + if(!test_and_set_bit(MGA_IN_DISPATCH, + &dev_priv->dispatch_status)) { break; } if((signed)(end - jiffies) <= 0) { @@ -205,51 +193,25 @@ static inline void mga_dma_quiescent(drm_device_t *dev) } for (i = 0 ; i < 2000 ; i++) mga_delay(); } - DRM_DEBUG("status[1] : %x last_sync_tag : %x\n", status[1], - dev_priv->last_sync_tag); sarea_priv->dirty |= MGA_DMA_FLUSH; out_status: - clear_bit(0, &dev_priv->dispatch_lock); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); out_nolock: } -#define FREELIST_INITIAL (MGA_DMA_BUF_NR * 2) -#define FREELIST_COMPARE(age) ((age >> 2)) - -unsigned int mga_create_sync_tag(drm_device_t *dev) +static void mga_reset_freelist(drm_device_t *dev) { - drm_mga_private_t *dev_priv = - (drm_mga_private_t *) dev->dev_private; - unsigned int temp; - drm_buf_t *buf; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; drm_mga_buf_priv_t *buf_priv; - drm_device_dma_t *dma = dev->dma; - int i; - - dev_priv->sync_tag++; - - if(dev_priv->sync_tag < FREELIST_INITIAL) { - dev_priv->sync_tag = FREELIST_INITIAL; - } - if(dev_priv->sync_tag > 0x3fffffff) { - mga_flush_queue(dev); - mga_dma_quiescent(dev); - - for (i = 0; i < dma->buf_count; i++) { - buf = dma->buflist[ i ]; - buf_priv = buf->dev_private; - buf_priv->my_freelist->age = MGA_BUF_FREE; - } - - dev_priv->sync_tag = FREELIST_INITIAL; - } - temp = dev_priv->sync_tag << 2; + int i; - dev_priv->sarea_priv->last_enqueue = temp; - - DRM_DEBUG("sync_tag : %x\n", temp); - return temp; + for (i = 0; i < dma->buf_count; i++) { + buf = dma->buflist[ i ]; + buf_priv = buf->dev_private; + buf_priv->my_freelist->age = MGA_BUF_FREE; + } } /* Least recently used : @@ -258,23 +220,52 @@ unsigned int mga_create_sync_tag(drm_device_t *dev) drm_buf_t *mga_freelist_get(drm_device_t *dev) { + DECLARE_WAITQUEUE(entry, current); drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; drm_mga_freelist_t *prev; drm_mga_freelist_t *next; + static int failed = 0; + + DRM_DEBUG("%s : tail->age : %d last_prim_age : %d\n", __FUNCTION__, + dev_priv->tail->age, dev_priv->last_prim_age); - if((dev_priv->tail->age >> 2) <= FREELIST_COMPARE(status[1])) { + if(failed >= 1000 && dev_priv->tail->age >= dev_priv->last_prim_age) { + DRM_DEBUG("I'm waiting on the freelist!!! %d\n", + dev_priv->last_prim_age); + set_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&dev_priv->buf_queue, &entry); + for (;;) { + mga_dma_schedule(dev, 0); + if(!test_bit(MGA_IN_GETBUF, + &dev_priv->dispatch_status)) + break; + atomic_inc(&dev->total_sleeps); + schedule(); + if (signal_pending(current)) { + clear_bit(MGA_IN_GETBUF, + &dev_priv->dispatch_status); + goto failed_getbuf; + } + } + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->buf_queue, &entry); + } + + if(dev_priv->tail->age < dev_priv->last_prim_age) { prev = dev_priv->tail->prev; next = dev_priv->tail; prev->next = NULL; next->prev = next->next = NULL; dev_priv->tail = prev; next->age = MGA_BUF_USED; + failed = 0; return next->buf; - } + } +failed_getbuf: + failed++; return NULL; } @@ -287,6 +278,8 @@ int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf) drm_mga_freelist_t *head; drm_mga_freelist_t *next; + DRM_DEBUG("%s\n", __FUNCTION__); + if(buf_priv->my_freelist->age == MGA_BUF_USED) { /* Discarded buffer, put it on the tail */ next = buf_priv->my_freelist; @@ -313,32 +306,6 @@ int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf) return 0; } -static void mga_print_all_primary(drm_device_t *dev) -{ - drm_mga_private_t *dev_priv = dev->dev_private; - drm_mga_prim_buf_t *prim; - int i; - - DRM_DEBUG("Full list of primarys\n"); - for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { - prim = dev_priv->prim_bufs[i]; - DRM_DEBUG("index : %d num_dwords : %d " - "max_dwords : %d phy_head : %x\n", - prim->idx, prim->num_dwords, - prim->max_dwords, prim->phys_head); - DRM_DEBUG("sec_used : %d swap_pending : %x " - "in_use : %x force_fire : %d\n", - prim->sec_used, prim->swap_pending, - prim->in_use, atomic_read(&prim->force_fire)); - DRM_DEBUG("needs_overflow : %d\n", - atomic_read(&prim->needs_overflow)); - } - - DRM_DEBUG("current_idx : %d, next_idx : %d, last_idx : %d\n", - dev_priv->next_prim->idx, dev_priv->last_prim->idx, - dev_priv->current_prim->idx); -} - static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) { drm_mga_private_t *dev_priv = dev->dev_private; @@ -346,10 +313,9 @@ static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) int i, temp, size_of_buf; int offset = init->reserved_map_agpstart; - DRM_DEBUG("mga_init_primary_bufs\n"); + DRM_DEBUG("%s\n", __FUNCTION__); dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; - DRM_DEBUG("primary_size\n"); size_of_buf = dev_priv->primary_size / MGA_NUM_PRIM_BUFS; dev_priv->warp_ucode_size = init->warp_ucode_size; dev_priv->prim_bufs = drm_alloc(sizeof(drm_mga_prim_buf_t *) * @@ -359,18 +325,12 @@ static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) DRM_ERROR("Unable to allocate memory for prim_buf\n"); return -ENOMEM; } - DRM_DEBUG("memset\n"); memset(dev_priv->prim_bufs, 0, sizeof(drm_mga_prim_buf_t *) * (MGA_NUM_PRIM_BUFS + 1)); temp = init->warp_ucode_size + dev_priv->primary_size; temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; - DRM_DEBUG("temp : %x\n", temp); - DRM_DEBUG("dev->agp->base: %lx\n", dev->agp->base); - DRM_DEBUG("init->reserved_map_agpstart: %x\n", - init->reserved_map_agpstart); - DRM_DEBUG("ioremap\n"); dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, temp); if(dev_priv->ioremap == NULL) { @@ -380,11 +340,9 @@ static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) init_waitqueue_head(&dev_priv->wait_queue); for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { - DRM_DEBUG("For loop\n"); prim_buffer = drm_alloc(sizeof(drm_mga_prim_buf_t), DRM_MEM_DRIVER); if(prim_buffer == NULL) return -ENOMEM; - DRM_DEBUG("memset\n"); memset(prim_buffer, 0, sizeof(drm_mga_prim_buf_t)); prim_buffer->phys_head = offset + dev->agp->base; prim_buffer->current_dma_ptr = @@ -397,17 +355,18 @@ static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init) prim_buffer->max_dwords -= 5; /* Leave room for the softrap */ prim_buffer->sec_used = 0; prim_buffer->idx = i; + prim_buffer->prim_age = i + 1; offset = offset + size_of_buf; dev_priv->prim_bufs[i] = prim_buffer; - DRM_DEBUG("Looping\n"); } dev_priv->current_prim_idx = 0; dev_priv->next_prim = dev_priv->last_prim = dev_priv->current_prim = dev_priv->prim_bufs[0]; - set_bit(0, &dev_priv->current_prim->in_use); - DRM_DEBUG("init done\n"); + dev_priv->next_prim_age = 2; + dev_priv->last_prim_age = 1; + set_bit(MGA_BUF_IN_USE, &dev_priv->current_prim->buffer_status); return 0; } @@ -421,9 +380,8 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) int i; int next_idx; PRIMLOCALS; - - DRM_DEBUG("mga_fire_primary\n"); - dev_priv->last_sync_tag = mga_create_sync_tag(dev); + + DRM_DEBUG("%s\n", __FUNCTION__); dev_priv->last_prim = prim; /* We never check for overflow, b/c there is always room */ @@ -434,7 +392,7 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) } PRIMOUTREG( MGAREG_DMAPAD, 0); PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMOUTREG( MGAREG_DMAPAD, 0); PRIMOUTREG( MGAREG_SOFTRAP, 0); PRIMFINISH(prim); @@ -469,13 +427,13 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) for (i = 0 ; i < 4096 ; i++) mga_delay(); } } - + mga_flush_write_combine(); atomic_inc(&dev_priv->pending_bufs); - atomic_inc(&dma->total_lost); MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); prim->num_dwords = 0; + sarea_priv->last_enqueue = prim->prim_age; next_idx = prim->idx + 1; if(next_idx >= MGA_NUM_PRIM_BUFS) @@ -487,11 +445,10 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim) out_prim_wait: prim->num_dwords = 0; prim->sec_used = 0; - clear_bit(0, &prim->in_use); + clear_bit(MGA_BUF_IN_USE, &prim->buffer_status); wake_up_interruptible(&dev_priv->wait_queue); - clear_bit(0, &prim->swap_pending); - clear_bit(0, &dev_priv->dispatch_lock); - atomic_dec(&dev_priv->pending_bufs); + clear_bit(MGA_BUF_SWAP_PENDING, &prim->buffer_status); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); } int mga_advance_primary(drm_device_t *dev) @@ -506,27 +463,28 @@ int mga_advance_primary(drm_device_t *dev) /* This needs to reset the primary buffer if available, * we should collect stats on how many times it bites * it's tail */ + DRM_DEBUG("%s\n", __FUNCTION__); next_prim_idx = dev_priv->current_prim_idx + 1; if(next_prim_idx >= MGA_NUM_PRIM_BUFS) next_prim_idx = 0; prim_buffer = dev_priv->prim_bufs[next_prim_idx]; - atomic_set(&dev_priv->in_wait, 1); + set_bit(MGA_IN_WAIT, &dev_priv->dispatch_status); /* In use is cleared in interrupt handler */ - if(test_and_set_bit(0, &prim_buffer->in_use)) { + if(test_and_set_bit(MGA_BUF_IN_USE, &prim_buffer->buffer_status)) { add_wait_queue(&dev_priv->wait_queue, &entry); + current->state = TASK_INTERRUPTIBLE; + for (;;) { - current->state = TASK_INTERRUPTIBLE; mga_dma_schedule(dev, 0); - if(!test_and_set_bit(0, &prim_buffer->in_use)) break; + if(!test_and_set_bit(MGA_BUF_IN_USE, + &prim_buffer->buffer_status)) + break; atomic_inc(&dev->total_sleeps); atomic_inc(&dma->total_missed_sched); - mga_print_all_primary(dev); - DRM_DEBUG("Schedule in advance\n"); - /* Three second delay */ - schedule_timeout(HZ*3); + schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; break; @@ -536,16 +494,27 @@ int mga_advance_primary(drm_device_t *dev) remove_wait_queue(&dev_priv->wait_queue, &entry); if(ret) return ret; } - atomic_set(&dev_priv->in_wait, 0); + clear_bit(MGA_IN_WAIT, &dev_priv->dispatch_status); + /* This primary buffer is now free to use */ prim_buffer->current_dma_ptr = prim_buffer->head; prim_buffer->num_dwords = 0; prim_buffer->sec_used = 0; - atomic_set(&prim_buffer->needs_overflow, 0); + prim_buffer->prim_age = dev_priv->next_prim_age++; + if(prim_buffer->prim_age == 0 || prim_buffer->prim_age == 0xffffffff) { + mga_flush_queue(dev); + mga_dma_quiescent(dev); + mga_reset_freelist(dev); + prim_buffer->prim_age = (dev_priv->next_prim_age += 2); + } + + /* Reset all buffer status stuff */ + clear_bit(MGA_BUF_NEEDS_OVERFLOW, &prim_buffer->buffer_status); + clear_bit(MGA_BUF_FORCE_FIRE, &prim_buffer->buffer_status); + clear_bit(MGA_BUF_SWAP_PENDING, &prim_buffer->buffer_status); + dev_priv->current_prim = prim_buffer; dev_priv->current_prim_idx = next_prim_idx; - DRM_DEBUG("Primarys at advance\n"); - mga_print_all_primary(dev); return 0; } @@ -554,21 +523,29 @@ static inline int mga_decide_to_fire(drm_device_t *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_device_dma_t *dma = dev->dma; - - if(atomic_read(&dev_priv->next_prim->force_fire)) - { + + DRM_DEBUG("%s\n", __FUNCTION__); + + if(test_bit(MGA_BUF_FORCE_FIRE, &dev_priv->next_prim->buffer_status)) { atomic_inc(&dma->total_prio); return 1; } - if (atomic_read(&dev_priv->in_flush) && dev_priv->next_prim->num_dwords) - { + if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords) { + atomic_inc(&dma->total_prio); + return 1; + } + + if (test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords) { atomic_inc(&dma->total_prio); return 1; } if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS - 1) { - if(test_bit(0, &dev_priv->next_prim->swap_pending)) { + if(test_bit(MGA_BUF_SWAP_PENDING, + &dev_priv->next_prim->buffer_status)) { atomic_inc(&dma->total_dmas); return 1; } @@ -602,10 +579,11 @@ int mga_dma_schedule(drm_device_t *dev, int locked) return -EBUSY; } - DRM_DEBUG("mga_dma_schedule\n"); + DRM_DEBUG("%s\n", __FUNCTION__); - if(atomic_read(&dev_priv->in_flush) || - atomic_read(&dev_priv->in_wait)) { + if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) || + test_bit(MGA_IN_WAIT, &dev_priv->dispatch_status) || + test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) { locked = 1; } @@ -613,27 +591,25 @@ int mga_dma_schedule(drm_device_t *dev, int locked) !drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { atomic_inc(&dma->total_missed_lock); clear_bit(0, &dev->dma_flag); + DRM_DEBUG("Not locked\n"); return -EBUSY; } DRM_DEBUG("I'm locked\n"); - - if(!test_and_set_bit(0, &dev_priv->dispatch_lock)) { + if(!test_and_set_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status)) { /* Fire dma buffer */ if(mga_decide_to_fire(dev)) { - DRM_DEBUG("mga_fire_primary\n"); DRM_DEBUG("idx :%d\n", dev_priv->next_prim->idx); - atomic_set(&dev_priv->next_prim->force_fire, 0); - if(dev_priv->current_prim == dev_priv->next_prim && - dev_priv->next_prim->num_dwords != 0) { + clear_bit(MGA_BUF_FORCE_FIRE, + &dev_priv->next_prim->buffer_status); + if(dev_priv->current_prim == dev_priv->next_prim) { /* Schedule overflow for a later time */ - atomic_set( - &dev_priv->current_prim->needs_overflow, - 1); + set_bit(MGA_BUF_NEEDS_OVERFLOW, + &dev_priv->next_prim->buffer_status); } mga_fire_primary(dev, dev_priv->next_prim); } else { - clear_bit(0, &dev_priv->dispatch_lock); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); } } else { DRM_DEBUG("I can't get the dispatch lock\n"); @@ -646,17 +622,26 @@ int mga_dma_schedule(drm_device_t *dev, int locked) } } - clear_bit(0, &dev->dma_flag); - - if(atomic_read(&dev_priv->in_flush) == 1 && - dev_priv->next_prim->num_dwords == 0) { - /* Everything is on the hardware */ - DRM_DEBUG("Primarys at Flush\n"); - mga_print_all_primary(dev); - atomic_set(&dev_priv->in_flush, 0); + if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) && + dev_priv->next_prim->num_dwords == 0 && + atomic_read(&dev_priv->pending_bufs) == 0) { + /* Everything has been processed by the hardware */ + clear_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status); wake_up_interruptible(&dev_priv->flush_queue); } + if(test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) && + dev_priv->tail->age < dev_priv->last_prim_age) { + clear_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); + DRM_DEBUG("Waking up buf queue\n"); + wake_up_interruptible(&dev_priv->buf_queue); + } else if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) { + DRM_DEBUG("Not waking buf_queue on %d %d\n", + atomic_read(&dev->total_irq), + dev_priv->last_prim_age); + } + + clear_bit(0, &dev->dma_flag); return 0; } @@ -665,33 +650,35 @@ static void mga_dma_service(int irq, void *device, struct pt_regs *regs) drm_device_t *dev = (drm_device_t *)device; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_mga_prim_buf_t *last_prim_buffer; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; - + + DRM_DEBUG("%s\n", __FUNCTION__); atomic_inc(&dev->total_irq); + if((MGA_READ(MGAREG_STATUS) & 0x00000001) != 0x00000001) return; MGA_WRITE(MGAREG_ICLEAR, 0x00000001); last_prim_buffer = dev_priv->last_prim; last_prim_buffer->num_dwords = 0; last_prim_buffer->sec_used = 0; - clear_bit(0, &last_prim_buffer->in_use); + dev_priv->sarea_priv->last_dispatch = + dev_priv->last_prim_age = last_prim_buffer->prim_age; + clear_bit(MGA_BUF_IN_USE, &last_prim_buffer->buffer_status); wake_up_interruptible(&dev_priv->wait_queue); - clear_bit(0, &last_prim_buffer->swap_pending); - clear_bit(0, &dev_priv->dispatch_lock); + clear_bit(MGA_BUF_SWAP_PENDING, &last_prim_buffer->buffer_status); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); atomic_dec(&dev_priv->pending_bufs); - dev_priv->sarea_priv->last_dispatch = status[1]; queue_task(&dev->tq, &tq_immediate); mark_bh(IMMEDIATE_BH); } static void mga_dma_task_queue(void *device) { - drm_device_t *dev = (drm_device_t *) device; - - mga_dma_schedule(dev, 0); + DRM_DEBUG("%s\n", __FUNCTION__); + mga_dma_schedule((drm_device_t *)device, 0); } int mga_dma_cleanup(drm_device_t *dev) { + DRM_DEBUG("%s\n", __FUNCTION__); + if(dev->dev_private) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; @@ -740,14 +727,13 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { drm_map_t *sarea_map = NULL; int i; + DRM_DEBUG("%s\n", __FUNCTION__); + dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); if(dev_priv == NULL) return -ENOMEM; dev->dev_private = (void *) dev_priv; - DRM_DEBUG("dev_private\n"); - memset(dev_priv, 0, sizeof(drm_mga_private_t)); - atomic_set(&dev_priv->in_flush, 0); if((init->reserved_map_idx >= dev->map_count) || (init->buffer_map_idx >= dev->map_count)) { @@ -762,7 +748,6 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { dev_priv->sarea_priv = (drm_mga_sarea_t *) ((u8 *)sarea_map->handle + init->sarea_priv_offset); - DRM_DEBUG("sarea_priv\n"); /* Scale primary size to the next page */ dev_priv->chipset = init->chipset; @@ -777,6 +762,7 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { dev_priv->mAccess = init->mAccess; init_waitqueue_head(&dev_priv->flush_queue); + init_waitqueue_head(&dev_priv->buf_queue); dev_priv->WarpPipe = -1; DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n", @@ -796,20 +782,17 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { dev_priv->WarpIndex[i].phys_addr, dev_priv->WarpIndex[i].size); - DRM_DEBUG("Doing init prim buffers\n"); if(mga_init_primary_bufs(dev, init) != 0) { DRM_ERROR("Can not initialize primary buffers\n"); mga_dma_cleanup(dev); return -ENOMEM; } - DRM_DEBUG("Done with init prim buffers\n"); dev_priv->real_status_page = mga_alloc_page(dev); if(dev_priv->real_status_page == 0UL) { mga_dma_cleanup(dev); DRM_ERROR("Can not allocate status page\n"); return -ENOMEM; } - DRM_DEBUG("Status page at %lx\n", dev_priv->real_status_page); dev_priv->status_page = ioremap_nocache(virt_to_bus((void *)dev_priv->real_status_page), @@ -821,38 +804,23 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { return -ENOMEM; } - DRM_DEBUG("Status page remapped to %p\n", dev_priv->status_page); /* Write status page when secend or softrap occurs */ MGA_WRITE(MGAREG_PRIMPTR, virt_to_bus((void *)dev_priv->real_status_page) | 0x00000003); - - dev_priv->device = pci_find_device(0x102b, 0x0525, NULL); - if(dev_priv->device == NULL) { - DRM_ERROR("Could not find pci device for card\n"); - mga_dma_cleanup(dev); - return -EINVAL; - } - - DRM_DEBUG("dma initialization\n"); + /* Private is now filled in, initialize the hardware */ { - __volatile__ unsigned int *status = - (unsigned int *)dev_priv->status_page; PRIMLOCALS; PRIMGETPTR( dev_priv ); - - dev_priv->last_sync_tag = mga_create_sync_tag(dev); - + PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMOUTREG(MGAREG_DWGSYNC, 0x0100); PRIMOUTREG(MGAREG_SOFTRAP, 0); /* Poll for the first buffer to insure that * the status register will be correct */ - DRM_DEBUG("phys_head : %lx\n", (unsigned long)phys_head); - status[1] = 0; mga_flush_write_combine(); MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); @@ -860,9 +828,7 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | PDEA_pagpxfer_enable)); - while(MGA_READ(MGAREG_DWGSYNC) != dev_priv->last_sync_tag) ; - DRM_DEBUG("status[0] after initialization : %x\n", status[0]); - DRM_DEBUG("status[1] after initialization : %x\n", status[1]); + while(MGA_READ(MGAREG_DWGSYNC) != 0x0100) ; } if(mga_freelist_init(dev) != 0) { @@ -870,7 +836,6 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { mga_dma_cleanup(dev); return -ENOMEM; } - DRM_DEBUG("dma init was successful\n"); return 0; } @@ -881,6 +846,8 @@ int mga_dma_init(struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; drm_mga_init_t init; + DRM_DEBUG("%s\n", __FUNCTION__); + copy_from_user_ret(&init, (drm_mga_init_t *)arg, sizeof(init), -EFAULT); switch(init.func) { @@ -925,7 +892,7 @@ int mga_irq_install(drm_device_t *dev, int irq) /* Install handler */ if ((retcode = request_irq(dev->irq, mga_dma_service, - 0, + SA_SHIRQ, dev->devname, dev))) { down(&dev->struct_sem); @@ -964,7 +931,9 @@ int mga_control(struct inode *inode, struct file *filp, unsigned int cmd, drm_control_t ctl; copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT); - + + DRM_DEBUG("%s\n", __FUNCTION__); + switch (ctl.func) { case DRM_INST_HANDLER: return mga_irq_install(dev, ctl.irq); @@ -981,30 +950,33 @@ static int mga_flush_queue(drm_device_t *dev) drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; int ret = 0; + DRM_DEBUG("%s\n", __FUNCTION__); + if(dev_priv == NULL) { return 0; } if(dev_priv->next_prim->num_dwords != 0) { - atomic_set(&dev_priv->in_flush, 1); + set_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status); current->state = TASK_INTERRUPTIBLE; add_wait_queue(&dev_priv->flush_queue, &entry); for (;;) { mga_dma_schedule(dev, 0); - if (atomic_read(&dev_priv->in_flush) == 0) + if (!test_bit(MGA_IN_FLUSH, + &dev_priv->dispatch_status)) break; atomic_inc(&dev->total_sleeps); - DRM_DEBUG("Schedule in flush_queue\n"); - schedule_timeout(HZ*3); + schedule(); if (signal_pending(current)) { ret = -EINTR; /* Can't restart */ + clear_bit(MGA_IN_FLUSH, + &dev_priv->dispatch_status); break; } } current->state = TASK_RUNNING; remove_wait_queue(&dev_priv->flush_queue, &entry); } - atomic_set(&dev_priv->in_flush, 0); return ret; } @@ -1018,6 +990,7 @@ void mga_reclaim_buffers(drm_device_t *dev, pid_t pid) if(dev->dev_private == NULL) return; if(dma->buflist == NULL) return; + DRM_DEBUG("%s\n", __FUNCTION__); mga_flush_queue(dev); for (i = 0; i < dma->buf_count; i++) { @@ -1043,6 +1016,7 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, int ret = 0; drm_lock_t lock; + DRM_DEBUG("%s\n", __FUNCTION__); copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); if (lock.context == DRM_KERNEL_CONTEXT) { @@ -1081,7 +1055,6 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd, /* Contention */ atomic_inc(&dev->total_sleeps); current->state = TASK_INTERRUPTIBLE; - DRM_DEBUG("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; @@ -1111,11 +1084,8 @@ int mga_flush_ioctl(struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; drm_lock_t lock; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; - int i; - + + DRM_DEBUG("%s\n", __FUNCTION__); copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT); if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { @@ -1124,28 +1094,17 @@ int mga_flush_ioctl(struct inode *inode, struct file *filp, } if(lock.flags & _DRM_LOCK_FLUSH || lock.flags & _DRM_LOCK_FLUSH_ALL) { - mga_flush_queue(dev); + drm_mga_prim_buf_t *temp_buf = + dev_priv->prim_bufs[dev_priv->current_prim_idx]; - if((MGA_READ(MGAREG_STATUS) & 0x00030001) == 0x00020000 && - status[1] != dev_priv->last_sync_tag) - { - DRM_DEBUG("Reseting hardware status\n"); - MGA_WRITE(MGAREG_DWGSYNC, dev_priv->last_sync_tag); - - while(MGA_READ(MGAREG_DWGSYNC) != - dev_priv->last_sync_tag) - { - for(i = 0; i < 4096; i++) mga_delay(); - } - - status[1] = - sarea_priv->last_dispatch = - dev_priv->last_sync_tag; - } else { - sarea_priv->last_dispatch = status[1]; - } + if(temp_buf && temp_buf->num_dwords) { + set_bit(MGA_BUF_FORCE_FIRE, &temp_buf->buffer_status); + mga_advance_primary(dev); + mga_dma_schedule(dev, 1); + } } if(lock.flags & _DRM_LOCK_QUIESCENT) { + mga_flush_queue(dev); mga_dma_quiescent(dev); } diff --git a/linux/mga_drm.h b/linux/mga_drm.h index 12a858e7..7228b905 100644 --- a/linux/mga_drm.h +++ b/linux/mga_drm.h @@ -37,6 +37,7 @@ */ #ifndef _MGA_DEFINES_ #define _MGA_DEFINES_ + #define MGA_F 0x1 /* fog */ #define MGA_A 0x2 /* alpha */ #define MGA_S 0x4 /* specular */ @@ -61,11 +62,11 @@ #define MGA_MAX_G400_PIPES 16 #define MGA_MAX_G200_PIPES 8 /* no multitex */ - #define MGA_MAX_WARP_PIPES MGA_MAX_G400_PIPES #define MGA_CARD_TYPE_G200 1 #define MGA_CARD_TYPE_G400 2 + #define MGA_FRONT 0x1 #define MGA_BACK 0x2 #define MGA_DEPTH 0x4 @@ -110,19 +111,19 @@ #define MGA_UPLOAD_TEX0 0x2 #define MGA_UPLOAD_TEX1 0x4 #define MGA_UPLOAD_PIPE 0x8 -#define MGA_UPLOAD_TEX0IMAGE 0x10 -#define MGA_UPLOAD_TEX1IMAGE 0x20 +#define MGA_UPLOAD_TEX0IMAGE 0x10 /* handled client-side */ +#define MGA_UPLOAD_TEX1IMAGE 0x20 /* handled client-side */ #define MGA_UPLOAD_2D 0x40 #define MGA_WAIT_AGE 0x80 /* handled client-side */ #define MGA_UPLOAD_CLIPRECTS 0x100 /* handled client-side */ #define MGA_DMA_FLUSH 0x200 /* set when someone gets the lock quiescent */ -/* 64 buffers of 16k each, total 1 meg. +/* 32 buffers of 64k each, total 2 meg. */ -#define MGA_DMA_BUF_ORDER 14 +#define MGA_DMA_BUF_ORDER 16 #define MGA_DMA_BUF_SZ (1<prim_bufs[dev_priv->current_prim_idx]; \ - if( tmp_buf->max_dwords - tmp_buf->num_dwords < length || \ - tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \ - atomic_set(&tmp_buf->force_fire, 1); \ - mga_advance_primary(dev); \ - mga_dma_schedule(dev, 1); \ - } else if( atomic_read(&tmp_buf->needs_overflow)) { \ - mga_advance_primary(dev); \ - mga_dma_schedule(dev, 1); \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + if( test_bit(MGA_BUF_NEEDS_OVERFLOW, \ + &tmp_buf->buffer_status)) { \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ + } else if( tmp_buf->max_dwords - tmp_buf->num_dwords < length ||\ + tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \ + set_bit(MGA_BUF_FORCE_FIRE, &tmp_buf->buffer_status); \ + mga_advance_primary(dev); \ + mga_dma_schedule(dev, 1); \ } \ } while(0) @@ -266,6 +274,13 @@ drm_mga_prim_buf_t *tmp_buf = \ tmp_buf->sec_used++; \ } while (0) +#define AGEBUF(dev_priv, buf_priv) do { \ + drm_mga_prim_buf_t *tmp_buf = \ + dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ + buf_priv->my_freelist->age = tmp_buf->prim_age; \ +} while (0) + + #define PRIMOUTREG(reg, val) do { \ tempIndex[outcount]=ADRINDEX(reg); \ dma_ptr[1+outcount] = val; \ @@ -379,6 +394,9 @@ drm_mga_prim_buf_t *tmp_buf = \ #define DC_pattern_disable 0x0 #define DC_transc_disable 0x0 +#define SETADD_mode_vertlist 0x0 + + #define MGA_CLEAR_CMD (DC_opcod_trap | DC_arzero_enable | \ DC_sgnzero_enable | DC_shftzero_enable | \ (0xC << DC_bop_SHIFT) | DC_clipdis_enable | \ diff --git a/linux/mga_state.c b/linux/mga_state.c index a70f86d2..dc227769 100644 --- a/linux/mga_state.c +++ b/linux/mga_state.c @@ -41,14 +41,15 @@ static void mgaEmitClipRect( drm_mga_private_t *dev_priv, drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->ContextState; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); /* This takes 10 dwords */ PRIMGETPTR( dev_priv ); /* Force reset of dwgctl (eliminates clip disable) */ PRIMOUTREG( MGAREG_DMAPAD, 0 ); - PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag - 1 ); - PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag - 1 ); + PRIMOUTREG( MGAREG_DWGSYNC, 0 ); + PRIMOUTREG( MGAREG_DWGSYNC, 0 ); PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); PRIMOUTREG( MGAREG_DMAPAD, 0 ); @@ -64,6 +65,7 @@ static void mgaEmitContext(drm_mga_private_t *dev_priv ) drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->ContextState; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); /* This takes a max of 15 dwords */ PRIMGETPTR( dev_priv ); @@ -98,6 +100,7 @@ static void mgaG200EmitTex( drm_mga_private_t *dev_priv ) drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->TexState[0]; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR( dev_priv ); @@ -132,6 +135,7 @@ static void mgaG400EmitTex0( drm_mga_private_t *dev_priv ) unsigned int *regs = sarea_priv->TexState[0]; int multitex = sarea_priv->WarpPipe & MGA_T2; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR( dev_priv ); @@ -179,6 +183,7 @@ static void mgaG400EmitTex1( drm_mga_private_t *dev_priv ) drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->TexState[1]; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR(dev_priv); @@ -217,6 +222,7 @@ static void mgaG400EmitPipe(drm_mga_private_t *dev_priv ) unsigned int pipe = sarea_priv->WarpPipe; float fParam = 12800.0f; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR(dev_priv); @@ -255,7 +261,7 @@ static void mgaG400EmitPipe(drm_mga_private_t *dev_priv ) PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); - PRIMOUTREG(MGAREG_WIADDR2, (__u32)(dev_priv->WarpIndex[pipe].phys_addr | + PRIMOUTREG(MGAREG_WIADDR2, (u32)(dev_priv->WarpIndex[pipe].phys_addr | WIA_wmode_start | WIA_wagp_agp)); PRIMADVANCE(dev_priv); } @@ -265,6 +271,7 @@ static void mgaG200EmitPipe( drm_mga_private_t *dev_priv ) drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->WarpPipe; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR(dev_priv); @@ -284,7 +291,7 @@ static void mgaG200EmitPipe( drm_mga_private_t *dev_priv ) PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); - PRIMOUTREG(MGAREG_WIADDR, (__u32)(dev_priv->WarpIndex[pipe].phys_addr | + PRIMOUTREG(MGAREG_WIADDR, (u32)(dev_priv->WarpIndex[pipe].phys_addr | WIA_wmode_start | WIA_wagp_agp)); PRIMADVANCE(dev_priv); @@ -294,6 +301,7 @@ static void mgaEmitState( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; + DRM_DEBUG("%s\n", __FUNCTION__); if (dev_priv->chipset == MGA_CARD_TYPE_G400) { int multitex = sarea_priv->WarpPipe & MGA_T2; @@ -343,6 +351,8 @@ static int mgaVerifyContext(drm_mga_private_t *dev_priv ) drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->ContextState; + DRM_DEBUG("%s\n", __FUNCTION__); + if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOffset && regs[MGA_CTXREG_DSTORG] != dev_priv->backOffset) { DRM_DEBUG("BAD DSTORG: %x (front %x, back %x)\n\n", @@ -362,6 +372,8 @@ static int mgaVerifyTex(drm_mga_private_t *dev_priv, { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + DRM_DEBUG("%s\n", __FUNCTION__); + if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) { DRM_DEBUG("BAD TEXREG_ORG: %x, unit %d\n", sarea_priv->TexState[unit][MGA_TEXREG_ORG], @@ -379,6 +391,8 @@ static int mgaVerifyState( drm_mga_private_t *dev_priv ) unsigned int dirty = sarea_priv->dirty; int rv = 0; + DRM_DEBUG("%s\n", __FUNCTION__); + if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; @@ -409,6 +423,8 @@ static int mgaVerifyIload( drm_mga_private_t *dev_priv, unsigned long bus_address, unsigned int dstOrg, int length ) { + DRM_DEBUG("%s\n", __FUNCTION__); + if(dstOrg < dev_priv->textureOffset || dstOrg + length > (dev_priv->textureOffset + dev_priv->textureSize)) { @@ -432,14 +448,13 @@ static void mga_dma_dispatch_tex_blit( drm_device_t *dev, int use_agp = PDEA_pagpxfer_enable | 0x00000001; u16 y2; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); y2 = length / 64; PRIM_OVERFLOW(dev, dev_priv, 30); PRIMGETPTR( dev_priv ); - dev_priv->last_sync_tag = mga_create_sync_tag(dev); - PRIMOUTREG( MGAREG_DSTORG, destOrg); PRIMOUTREG( MGAREG_MACCESS, 0x00000000); DRM_DEBUG("srcorg : %lx\n", bus_address | use_agp); @@ -459,7 +474,7 @@ static void mga_dma_dispatch_tex_blit( drm_device_t *dev, PRIMOUTREG( MGAREG_SRCORG, 0); PRIMOUTREG( MGAREG_PITCH, dev_priv->stride / dev_priv->cpp); PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); + PRIMOUTREG( MGAREG_DMAPAD, 0); PRIMADVANCE(dev_priv); } @@ -475,33 +490,33 @@ static void mga_dma_dispatch_vertex(drm_device_t *dev, int i = 0; int primary_needed; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); DRM_DEBUG("dispatch vertex %d addr 0x%lx, " "length 0x%x nbox %d dirty %x\n", buf->idx, address, length, sarea_priv->nbox, sarea_priv->dirty); - - dev_priv->last_sync_tag = mga_create_sync_tag(dev); - - if (buf_priv->discard) { - buf_priv->my_freelist->age = dev_priv->last_sync_tag; - mga_freelist_put(dev, buf); + DRM_DEBUG("used : %d, total : %d\n", buf->used, buf->total); + if(sarea_priv->WarpPipe & MGA_T2) { + if ((buf->used/4) % 10) + DRM_DEBUG("Multitex Buf is not aligned properly!!!\n"); + } else { + if ((buf->used/4) % 8) + DRM_DEBUG("Buf is not aligned properly!!!\n"); } - - /* WARNING: if you change any of the state functions verify - * these numbers (Overestimating this doesn't hurt). - */ - primary_needed = (25+15+30+25+ - 10 + - 15 * MGA_NR_SAREA_CLIPRECTS); - - - PRIM_OVERFLOW(dev, dev_priv, primary_needed); - mgaEmitState( dev_priv ); - if (buf->used) { + /* WARNING: if you change any of the state functions verify + * these numbers (Overestimating this doesn't hurt). + */ + buf_priv->dispatched = 1; + primary_needed = (25+15+30+25+ + 10 + + 15 * MGA_NR_SAREA_CLIPRECTS); + PRIM_OVERFLOW(dev, dev_priv, primary_needed); + mgaEmitState( dev_priv ); + do { if (i < sarea_priv->nbox) { DRM_DEBUG("idx %d Emit box %d/%d:" @@ -521,20 +536,85 @@ static void mga_dma_dispatch_vertex(drm_device_t *dev, PRIMOUTREG( MGAREG_DMAPAD, 0); PRIMOUTREG( MGAREG_DMAPAD, 0); PRIMOUTREG( MGAREG_SECADDRESS, - ((__u32)address) | TT_VERTEX); + ((u32)address) | TT_VERTEX); PRIMOUTREG( MGAREG_SECEND, - (((__u32)(address + length)) | + (((u32)(address + length)) | use_agp)); PRIMADVANCE( dev_priv ); } while (++i < sarea_priv->nbox); } - PRIMGETPTR( dev_priv ); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, dev_priv->last_sync_tag); - PRIMADVANCE( dev_priv ); + if (buf_priv->discard) { + if(buf_priv->dispatched == 1) AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } + + +} + + +static void mga_dma_dispatch_indices(drm_device_t *dev, + drm_buf_t *buf, + unsigned int start, + unsigned int end) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_buf_priv_t *buf_priv = buf->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int address = (unsigned int)buf->bus_address; + int use_agp = PDEA_pagpxfer_enable; + int i = 0; + int primary_needed; + PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); + + DRM_DEBUG("dispatch indices %d addr 0x%x, " + "start 0x%x end 0x%x nbox %d dirty %x\n", + buf->idx, address, start, end, + sarea_priv->nbox, sarea_priv->dirty); + + if (start != end) { + /* WARNING: if you change any of the state functions verify + * these numbers (Overestimating this doesn't hurt). + */ + buf_priv->dispatched = 1; + primary_needed = (25+15+30+25+ + 10 + + 15 * MGA_NR_SAREA_CLIPRECTS); + PRIM_OVERFLOW(dev, dev_priv, primary_needed); + mgaEmitState( dev_priv ); + + do { + if (i < sarea_priv->nbox) { + DRM_DEBUG("idx %d Emit box %d/%d:" + "%d,%d - %d,%d\n", + buf->idx, + i, sarea_priv->nbox, + sarea_priv->boxes[i].x1, + sarea_priv->boxes[i].y1, + sarea_priv->boxes[i].x2, + sarea_priv->boxes[i].y2); + + mgaEmitClipRect( dev_priv, + &sarea_priv->boxes[i] ); + } + + PRIMGETPTR(dev_priv); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_SETUPADDRESS, + ((address + start) | SETADD_mode_vertlist)); + PRIMOUTREG( MGAREG_SETUPEND, + ((address + end) | use_agp)); + PRIMADVANCE( dev_priv ); + } while (++i < sarea_priv->nbox); + } + if (buf_priv->discard) { + if(buf_priv->dispatched == 1) AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } } @@ -551,6 +631,7 @@ static void mga_dma_dispatch_clear( drm_device_t *dev, int flags, int i; int primary_needed; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); if ( dev_priv->sgram ) cmd = MGA_CLEAR_CMD | DC_atype_blk; @@ -561,7 +642,6 @@ static void mga_dma_dispatch_clear( drm_device_t *dev, int flags, if(primary_needed == 0) primary_needed = 70; PRIM_OVERFLOW(dev, dev_priv, primary_needed); PRIMGETPTR( dev_priv ); - dev_priv->last_sync_tag = mga_create_sync_tag(dev); for (i = 0 ; i < nbox ; i++) { unsigned int height = pbox[i].y2 - pbox[i].y1; @@ -615,11 +695,6 @@ static void mga_dma_dispatch_clear( drm_device_t *dev, int flags, PRIMOUTREG( MGAREG_DMAPAD, 0); PRIMOUTREG( MGAREG_DMAPAD, 0); PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); - - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); PRIMADVANCE(dev_priv); } @@ -633,14 +708,13 @@ static void mga_dma_dispatch_swap( drm_device_t *dev ) int i; int primary_needed; PRIMLOCALS; + DRM_DEBUG("%s\n", __FUNCTION__); primary_needed = nbox * 5; primary_needed += 60; PRIM_OVERFLOW(dev, dev_priv, primary_needed); PRIMGETPTR( dev_priv ); - dev_priv->last_sync_tag = mga_create_sync_tag(dev); - PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset); PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess); PRIMOUTREG(MGAREG_SRCORG, dev_priv->backOffset); @@ -668,13 +742,9 @@ static void mga_dma_dispatch_swap( drm_device_t *dev ) /* Force reset of DWGCTL */ PRIMOUTREG( MGAREG_DMAPAD, 0); PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_SRCORG, 0); PRIMOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); - PRIMOUTREG( MGAREG_SRCORG, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DMAPAD, 0); - PRIMOUTREG( MGAREG_DWGSYNC, dev_priv->last_sync_tag); PRIMADVANCE(dev_priv); } @@ -685,12 +755,11 @@ int mga_clear_bufs(struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; drm_mga_clear_t clear; copy_from_user_ret(&clear, (drm_mga_clear_t *)arg, sizeof(clear), -EFAULT); + DRM_DEBUG("%s\n", __FUNCTION__); if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("mga_clear_bufs called without lock held\n"); @@ -707,8 +776,8 @@ int mga_clear_bufs(struct inode *inode, struct file *filp, clear.clear_color, clear.clear_depth ); PRIMUPDATE(dev_priv); + mga_flush_write_combine(); mga_dma_schedule(dev, 1); - sarea_priv->last_dispatch = status[1]; return 0; } @@ -719,8 +788,7 @@ int mga_swap_bufs(struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; + DRM_DEBUG("%s\n", __FUNCTION__); if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("mga_swap_bufs called without lock held\n"); @@ -735,10 +803,9 @@ int mga_swap_bufs(struct inode *inode, struct file *filp, dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX; mga_dma_dispatch_swap( dev ); PRIMUPDATE(dev_priv); - set_bit(0, &dev_priv->current_prim->swap_pending); - dev_priv->current_prim->swap_pending = 1; + set_bit(MGA_BUF_SWAP_PENDING, &dev_priv->current_prim->buffer_status); + mga_flush_write_combine(); mga_dma_schedule(dev, 1); - sarea_priv->last_dispatch = status[1]; return 0; } @@ -750,12 +817,11 @@ int mga_iload(struct inode *inode, struct file *filp, drm_device_dma_t *dma = dev->dma; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; drm_buf_t *buf; drm_mga_buf_priv_t *buf_priv; drm_mga_iload_t iload; unsigned long bus_address; + DRM_DEBUG("%s\n", __FUNCTION__); DRM_DEBUG("Starting Iload\n"); copy_from_user_ret(&iload, (drm_mga_iload_t *)arg, sizeof(iload), @@ -784,11 +850,11 @@ int mga_iload(struct inode *inode, struct file *filp, mga_dma_dispatch_tex_blit(dev, bus_address, iload.length, iload.destOrg); - buf_priv->my_freelist->age = dev_priv->last_sync_tag; + AGEBUF(dev_priv, buf_priv); buf_priv->discard = 1; mga_freelist_put(dev, buf); + mga_flush_write_combine(); mga_dma_schedule(dev, 1); - sarea_priv->last_dispatch = status[1]; return 0; } @@ -798,13 +864,11 @@ int mga_vertex(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; drm_mga_buf_priv_t *buf_priv; drm_mga_vertex_t vertex; + DRM_DEBUG("%s\n", __FUNCTION__); copy_from_user_ret(&vertex, (drm_mga_vertex_t *)arg, sizeof(vertex), -EFAULT); @@ -823,25 +887,75 @@ int mga_vertex(struct inode *inode, struct file *filp, buf_priv->discard = vertex.discard; if (!mgaVerifyState(dev_priv)) { - if (vertex.discard) { - buf_priv->my_freelist->age = dev_priv->last_sync_tag; - mga_freelist_put(dev, buf); + if (vertex.discard) { + if(buf_priv->dispatched == 1) AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); } + DRM_DEBUG("bad state\n"); return -EINVAL; } mga_dma_dispatch_vertex(dev, buf); PRIMUPDATE(dev_priv); + mga_flush_write_combine(); mga_dma_schedule(dev, 1); - sarea_priv->last_dispatch = status[1]; return 0; } + +int mga_indices(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_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_mga_buf_priv_t *buf_priv; + drm_mga_indices_t indices; + DRM_DEBUG("%s\n", __FUNCTION__); + + copy_from_user_ret(&indices, (drm_mga_indices_t *)arg, sizeof(indices), + -EFAULT); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("mga_indices called without lock held\n"); + return -EINVAL; + } + + DRM_DEBUG("mga_indices\n"); + + buf = dma->buflist[ indices.idx ]; + buf_priv = buf->dev_private; + + buf_priv->discard = indices.discard; + + if (!mgaVerifyState(dev_priv)) { + if (indices.discard) { + if(buf_priv->dispatched == 1) AGEBUF(dev_priv, buf_priv); + buf_priv->dispatched = 0; + mga_freelist_put(dev, buf); + } + return -EINVAL; + } + + mga_dma_dispatch_indices(dev, buf, indices.start, indices.end); + + PRIMUPDATE(dev_priv); + mga_flush_write_combine(); + mga_dma_schedule(dev, 1); + return 0; +} + + + static int mga_dma_get_buffers(drm_device_t *dev, drm_dma_t *d) { int i; drm_buf_t *buf; + DRM_DEBUG("%s\n", __FUNCTION__); for (i = d->granted_count; i < d->request_count; i++) { buf = mga_freelist_get(dev); @@ -866,12 +980,9 @@ int mga_dma(struct inode *inode, struct file *filp, unsigned int cmd, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - __volatile__ unsigned int *status = - (__volatile__ unsigned int *)dev_priv->status_page; int retcode = 0; drm_dma_t d; + DRM_DEBUG("%s\n", __FUNCTION__); copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT); DRM_DEBUG("%d %d: %d send, %d req\n", @@ -907,6 +1018,5 @@ int mga_dma(struct inode *inode, struct file *filp, unsigned int cmd, DRM_DEBUG("%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 = status[1]; return retcode; } diff --git a/shared-core/drm.h b/shared-core/drm.h index 25e4cce4..74ef83f4 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -341,13 +341,16 @@ typedef struct drm_agp_info { #define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) #define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t) #define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t ) +#define DRM_IOCTL_MGA_INDICES DRM_IOW( 0x46, drm_mga_indices_t) /* I810 specific ioctls */ #define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) #define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) -#define DRM_IOCTL_I810_DMA DRM_IOW( 0x42, drm_i810_general_t) +#define DRM_IOCTL_I810_CLEAR DRM_IOW( 0x42, drm_i810_clear_t) #define DRM_IOCTL_I810_FLUSH DRM_IO ( 0x43) #define DRM_IOCTL_I810_GETAGE DRM_IO ( 0x44) +#define DRM_IOCTL_I810_GETBUF DRM_IOW( 0x45, drm_i810_dma_t) +#define DRM_IOCTL_I810_SWAP DRM_IO ( 0x46) /* Rage 128 specific ioctls */ #define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t) diff --git a/shared/drm.h b/shared/drm.h index 25e4cce4..74ef83f4 100644 --- a/shared/drm.h +++ b/shared/drm.h @@ -341,13 +341,16 @@ typedef struct drm_agp_info { #define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x43, drm_mga_iload_t) #define DRM_IOCTL_MGA_VERTEX DRM_IOW( 0x44, drm_mga_vertex_t) #define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x45, drm_lock_t ) +#define DRM_IOCTL_MGA_INDICES DRM_IOW( 0x46, drm_mga_indices_t) /* I810 specific ioctls */ #define DRM_IOCTL_I810_INIT DRM_IOW( 0x40, drm_i810_init_t) #define DRM_IOCTL_I810_VERTEX DRM_IOW( 0x41, drm_i810_vertex_t) -#define DRM_IOCTL_I810_DMA DRM_IOW( 0x42, drm_i810_general_t) +#define DRM_IOCTL_I810_CLEAR DRM_IOW( 0x42, drm_i810_clear_t) #define DRM_IOCTL_I810_FLUSH DRM_IO ( 0x43) #define DRM_IOCTL_I810_GETAGE DRM_IO ( 0x44) +#define DRM_IOCTL_I810_GETBUF DRM_IOW( 0x45, drm_i810_dma_t) +#define DRM_IOCTL_I810_SWAP DRM_IO ( 0x46) /* Rage 128 specific ioctls */ #define DRM_IOCTL_R128_INIT DRM_IOW( 0x40, drm_r128_init_t)