diff options
author | Gareth Hughes <gareth@users.sourceforge.net> | 2001-01-31 16:30:45 +0000 |
---|---|---|
committer | Gareth Hughes <gareth@users.sourceforge.net> | 2001-01-31 16:30:45 +0000 |
commit | 5f15407b9cfe89274557aa4b94aae89bb1688713 (patch) | |
tree | 5b8a31eeb361303dcfb7305335dfcb6efe15382d | |
parent | b5366b97892ee5a80284cdd744ec6d4a8a996c21 (diff) |
This is how it should be done...
We generate a SOFTRAP interrupt only when the primary DMA space wraps
around. All writes to dev_priv->prim.tail must be locked with an
IRQ-safe spinlock, as the interrupt handler reads this value.
-rw-r--r-- | linux/mga_dma.c | 440 | ||||
-rw-r--r-- | linux/mga_drv.h | 74 | ||||
-rw-r--r-- | linux/mga_state.c | 38 |
3 files changed, 161 insertions, 391 deletions
diff --git a/linux/mga_dma.c b/linux/mga_dma.c index e56e36e3..a20f5e44 100644 --- a/linux/mga_dma.c +++ b/linux/mga_dma.c @@ -1060,7 +1060,7 @@ int mga_do_wait_for_idle( drm_mga_private_t *dev_priv ) udelay( 1 ); } - DRM_ERROR( "failed! status=0x%08x\n", status ); + DRM_DEBUG( "failed! status=0x%08x\n", status ); return -EBUSY; } @@ -1076,22 +1076,18 @@ int mga_do_dma_idle( drm_mga_private_t *dev_priv ) udelay( 1 ); } - DRM_ERROR( "failed! status=0x%08x\n", status ); + DRM_DEBUG( "failed! status=0x%08x\n", status ); return -EBUSY; } int mga_do_dma_reset( drm_mga_private_t *dev_priv ) { drm_mga_primary_buffer_t *primary = &dev_priv->prim; - unsigned long flags; DRM_DEBUG( "%s\n", __FUNCTION__ ); - spin_lock_irqsave( &primary->lock, flags ); - /* The primary DMA stream should look like new right about now. */ - primary->head = 0; primary->tail = 0; primary->wrap = 0; primary->space = primary->size - MGA_DMA_SOFTRAP_SIZE; @@ -1100,15 +1096,9 @@ int mga_do_dma_reset( drm_mga_private_t *dev_priv ) /* FIXME: Reset counters, buffer ages etc... */ - clear_bit( MGA_DMA_FLUSH, &primary->state ); - clear_bit( MGA_DMA_WRAP, &primary->state ); - - set_bit( MGA_DMA_IDLE, &primary->state ); - /* FIXME: What else do we need to reinitialize? WARP stuff? */ - spin_unlock_irqrestore( &dev_priv->prim.lock, flags ); return 0; } @@ -1154,169 +1144,95 @@ int mga_do_engine_reset( drm_mga_private_t *dev_priv ) * Primary DMA stream */ -/* The primary DMA stream *MUST* be idle before this is called. Use - * mga_do_dma_idle() above if required. - * - * The mga_dma_lock IRQ-safe spinlock *MUST* be held before this is - * called. You have been warned... - */ -static inline void mga_do_dma( drm_mga_private_t *dev_priv, - u32 head, u32 tail ) -{ - drm_mga_primary_buffer_t *primary = &dev_priv->prim; - DRM_INFO( "%s:\n", __FUNCTION__ ); - - /* Only flush the primary DMA stream if there are new commands. - */ - if ( head == tail ) { - DRM_INFO( " bailing out...\n" ); - return; - } - - if ( tail < head ) { - DRM_ERROR( " head = 0x%08x 0x%04x\n", - head, head - dev_priv->primary->offset ); - DRM_ERROR( " tail = 0x%08x 0x%04x\n", - tail, tail - dev_priv->primary->offset ); - DRM_ERROR( "*** oops, we messed up ***\n" ); - } - - DRM_INFO( " status = 0x%08x\n", MGA_READ( MGA_STATUS ) ); - DRM_INFO( " head = 0x%08x 0x%04x\n", - head, head - dev_priv->primary->offset ); - DRM_INFO( " tail = 0x%08x 0x%04x\n", - tail, tail - dev_priv->primary->offset ); - - clear_bit( MGA_DMA_IDLE, &primary->state ); - - mga_flush_write_combine(); - - MGA_WRITE( MGA_PRIMADDRESS, head | MGA_DMA_GENERAL ); - MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); - - DRM_INFO( "%s: done.\n", __FUNCTION__ ); -} - void mga_do_dma_flush( drm_mga_private_t *dev_priv ) { drm_mga_primary_buffer_t *primary = &dev_priv->prim; u32 head, tail; DMA_LOCALS; - DRM_INFO( "%s:\n", __FUNCTION__ ); - - /* Flushing the primary DMA stream will always result in this - * function being called, even if there are no new commands. - */ - if ( test_and_clear_bit( MGA_DMA_FLUSH, &primary->state ) ) { - DRM_DEBUG( " got DMA flush...\n" ); - } + DRM_DEBUG( "%s:\n", __FUNCTION__ ); - /* Only flush the primary DMA stream if there are new commands. - */ if ( primary->tail == primary->last_flush ) { - DRM_INFO( " bailing out...\n" ); + DRM_DEBUG( " bailing out...\n" ); return; } - /* Writing the SOFTRAP register will cause an interrupt. We use - * this as notification that the primary DMA stream is complete. - */ + tail = primary->tail + dev_priv->primary->offset; + + mga_flush_write_combine(); + + MGA_WRITE( MGA_PRIMEND, tail | MGA_PRIMNOSTART | MGA_PAGPXFER ); + BEGIN_DMA( 1 ); DMA_BLOCK( MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000, - MGA_SOFTRAP, 0x00000000 ); + MGA_DMAPAD, 0x00000000 ); ADVANCE_DMA(); - primary->space = primary->size - primary->tail - MGA_DMA_SOFTRAP_SIZE; - primary->last_flush = primary->tail; + head = *primary->head; - head = primary->head + dev_priv->primary->offset; - tail = primary->tail + dev_priv->primary->offset; + DRM_DEBUG( " head = 0x%06lx\n", head - dev_priv->primary->offset ); + DRM_DEBUG( " tail = 0x%06lx\n", tail - dev_priv->primary->offset ); - /* Kick off the DMA transfer. - */ - mga_do_dma( dev_priv, head, tail ); - DRM_INFO( "%s: done.\n", __FUNCTION__ ); + if ( head <= tail ) { + primary->space = primary->size - primary->tail; + } else { + primary->space = head - tail; + } + primary->space -= MGA_DMA_SOFTRAP_SIZE; + + DRM_DEBUG( " space = 0x%06lx\n", primary->space ); + + primary->last_flush = primary->tail; + + DRM_DEBUG( "%s: done.\n", __FUNCTION__ ); } void mga_do_dma_wrap( drm_mga_private_t *dev_priv ) { drm_mga_primary_buffer_t *primary = &dev_priv->prim; u32 head, tail; - DRM_INFO( "%s:\n", __FUNCTION__ ); + DMA_LOCALS; + DRM_DEBUG( "%s:\n", __FUNCTION__ ); - /* Only wrap the primary DMA stream if we have to. - */ - if ( !primary->wrap ) { - DRM_INFO( " bailing out...\n" ); - return; - } + BEGIN_DMA_WRAP(); - head = primary->head + dev_priv->primary->offset; + DMA_BLOCK( MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_SOFTRAP, 0x00000000 ); - /* Wrap the primary DMA stream. We use primary->wrap to - * determine when the comamnds have wrapped around, and - * MGA_DMA_WRAP to determine when the last batch of commands - * has been dispatched. We need to reset PRIMADDRESS when this - * last batch has completed. - */ - tail = primary->wrap + dev_priv->primary->offset; - primary->wrap = 0; + ADVANCE_DMA(); - /* Kick off the DMA transfer. - */ - mga_do_dma( dev_priv, head, tail ); - DRM_INFO( "%s: done.\n", __FUNCTION__ ); -} + tail = primary->tail + dev_priv->primary->offset; -void mga_dma_wrap_or_wait( drm_mga_private_t *dev_priv, int n ) -{ - drm_mga_primary_buffer_t *primary = &dev_priv->prim; - DMA_LOCALS; - DRM_INFO( "%s: wrap=0x%x\n", __FUNCTION__, primary->wrap ); + mga_flush_write_combine(); - if ( !primary->wrap ) { - /* Add the SOFTRAP interrupt generator here. That way, - * we don't have to worry about adding it later if the - * primary DMA stream is currently active. - */ - BEGIN_DMA( 1 ); + MGA_WRITE( MGA_PRIMEND, tail | MGA_PRIMNOSTART | MGA_PAGPXFER ); - DMA_BLOCK( MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_SOFTRAP, 0x00000000 ); + spin_lock_irqsave( &primary->lock, flags ); + primary->tail = 0; + spin_unlock_irqrestore( &primary->lock, flags ); - ADVANCE_DMA(); + head = *primary->head; - primary->wrap = primary->tail; - primary->tail = 0; - primary->last_flush = 0; + DRM_DEBUG( " head = 0x%06lx\n", head - dev_priv->primary->offset ); + DRM_DEBUG( " tail = 0x%06lx\n", 0 ); - primary->space = primary->head - MGA_DMA_SOFTRAP_SIZE; + if ( head <= tail ) { + primary->space = primary->size - primary->tail; + } else { + primary->space = head - tail; + } + primary->space -= MGA_DMA_SOFTRAP_SIZE; - DRM_INFO( " wrap=0x%04x head=0x%04x space=0x%x\n", - primary->wrap, primary->head, primary->space ); + DRM_DEBUG( " space = 0x%06lx\n", primary->space ); - /* Kick off the last chunk of commands immediately if - * the primary DMA stream is idle. This makes wrapping - * nice and simple. - */ - if ( MGA_DMA_IS_IDLE( dev_priv ) ) { - mga_do_dma_wrap( dev_priv ); - } - } else { - /* FIXME: This is terribly broken... - */ - panic( "*** WTF??? ***\n" ); - while ( mga_do_wait_for_idle( dev_priv ) < 0 ) - ; + primary->last_flush = 0; - mga_do_dma_flush( dev_priv ); - } + DRM_DEBUG( "%s: done.\n", __FUNCTION__ ); } @@ -1328,8 +1244,10 @@ 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_primary_buffer_t *primary = &dev_priv->prim; + u32 head = dev_priv->primary->offset; + u32 tail; - DRM_INFO( " *** took interrupt\n" ); atomic_inc( &dev->total_irq ); /* Verify the interrupt we're servicing is actually the one we @@ -1340,55 +1258,16 @@ static void mga_dma_service( int irq, void *device, struct pt_regs *regs ) MGA_WRITE( MGA_ICLEAR, MGA_SOFTRAPICLR ); - queue_task( &dev->tq, &tq_immediate ); - mark_bh( IMMEDIATE_BH ); -} - -static void mga_dma_task_queue( void *dev ) -{ - mga_dma_schedule( dev ); -} - -int mga_dma_schedule( drm_device_t *dev ) -{ - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_primary_buffer_t *primary = &dev_priv->prim; - unsigned long flags; - - spin_lock_irqsave( &primary->lock, flags ); - DRM_INFO( "spin_lock() in %s\n", __FUNCTION__ ); - - DRM_INFO( "%s: prim=0x%x low=0x%x\n", - __FUNCTION__, - primary->tail - primary->last_flush, - primary->low_mark ); - - set_bit( MGA_DMA_IDLE, &primary->state ); - - primary->head = primary->last_flush; - - if ( primary->wrap ) { - DRM_INFO( " wrapping primary DMA...\n" ); - mga_do_dma_wrap( dev_priv ); - } else if ( test_bit( MGA_DMA_FLUSH, &primary->state ) ) { - DRM_INFO( " forcing primary DMA...\n" ); - mga_do_dma_flush( dev_priv ); -#if 0 - } else if ( primary->tail - primary->last_flush >= - primary->low_mark ) { - DRM_INFO( " flushing primary DMA...\n" ); - mga_do_dma_flush( dev_priv ); -#endif - } else { - DRM_INFO( " going idle...\n" ); - } + tail = primary->tail + dev_priv->primary->offset; - DRM_INFO( "%s: done.\n", __FUNCTION__ ); + DRM_DEBUG( " *** wrap interrupt:\n" ); + DRM_DEBUG( " head = 0x%06x\n", head - dev_priv->primary->offset ); + DRM_DEBUG( " tail = 0x%06x\n", tail - dev_priv->primary->offset ); - DRM_INFO( "spin_unlock() in %s\n", __FUNCTION__ ); - spin_unlock_irqrestore( &primary->lock, flags ); + mga_flush_write_combine(); - return 0; + MGA_WRITE( MGA_PRIMADDRESS, head | MGA_DMA_GENERAL ); + MGA_WRITE( MGA_PRIMEND, tail | MGA_PRIMNOSTART | MGA_PAGPXFER ); } @@ -1401,10 +1280,8 @@ int mga_dma_schedule( drm_device_t *dev ) static void mga_freelist_print( drm_device_t *dev ) { - drm_device_dma_t *dma = dev->dma; drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_freelist_t *entry; - int i; DRM_INFO( "\n" ); DRM_INFO( "current dispatch: last=0x%x done=0x%x\n", @@ -1505,9 +1382,6 @@ static drm_buf_t *mga_freelist_get( drm_device_t *dev ) drm_mga_freelist_t *next; drm_mga_freelist_t *prev; - spin_lock_bh( &dev_priv->prim.lock ); - DRM_DEBUG( "spin_lock_bh() in %s\n", __FUNCTION__ ); - DRM_DEBUG( "%s: tail=0x%x status=0x%x\n", __FUNCTION__, dev_priv->tail->age, dev_priv->prim.status[1] ); @@ -1521,15 +1395,9 @@ static drm_buf_t *mga_freelist_get( drm_device_t *dev ) next->prev = next->next = NULL; dev_priv->tail = prev; next->age = MGA_BUFFER_USED; - - DRM_DEBUG( "spin_unlock_bh() in %s\n", __FUNCTION__ ); - spin_unlock_bh( &dev_priv->prim.lock ); return next->buf; } - DRM_DEBUG( "spin_unlock_bh() in %s\n", __FUNCTION__ ); - spin_unlock_bh( &dev_priv->prim.lock ); - DRM_ERROR( "returning NULL!\n" ); return NULL; } @@ -1664,32 +1532,29 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) mga_do_wait_for_idle( dev_priv ); - /* Init the DMA status pointer. + /* Init the primary DMA registers. */ -#if 0 + MGA_WRITE( MGA_PRIMADDRESS, + dev_priv->primary->offset | MGA_DMA_GENERAL ); + MGA_WRITE( MGA_PRIMPTR, virt_to_bus((void *)dev_priv->prim.status_page) | MGA_PRIMPTREN0 | /* Soft trap, SECEND, SETUPEND */ MGA_PRIMPTREN1 ); /* DWGSYNC */ -#endif dev_priv->prim.start = (u8 *)dev_priv->primary->handle; dev_priv->prim.end = ((u8 *)dev_priv->primary->handle + dev_priv->primary->size); dev_priv->prim.size = dev_priv->primary->size; - dev_priv->prim.head = 0; + dev_priv->prim.head = &dev_priv->prim.status[0]; dev_priv->prim.tail = 0; dev_priv->prim.wrap = 0; dev_priv->prim.space = dev_priv->prim.size - MGA_DMA_SOFTRAP_SIZE; dev_priv->prim.last_flush = 0; - dev_priv->prim.low_mark = 32 * DMA_BLOCK_SIZE; - dev_priv->prim.mid_mark = dev_priv->prim.space / 4; dev_priv->prim.high_mark = 0; - set_bit( MGA_DMA_IDLE, &dev_priv->prim.state ); - spin_lock_init( &dev_priv->prim.lock ); dev_priv->sarea_priv->last_dispatch = 0; @@ -1777,31 +1642,14 @@ int mga_dma_flush( struct inode *inode, struct file *filp, if ( copy_from_user( &lock, (drm_lock_t *)arg, sizeof(lock) ) ) return -EFAULT; - DRM_INFO( "%s: %s%s%s\n", - __FUNCTION__, - (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "", - (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "", - (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "" ); + DRM_DEBUG( "%s: %s%s%s\n", + __FUNCTION__, + (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "", + (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "", + (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "" ); if ( lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL) ) { - - spin_lock_bh( &dev_priv->prim.lock ); - DRM_INFO( "spin_lock_bh() in %s\n", __FUNCTION__ ); - - /* Force the flushing of any outstanding primary DMA - * commands. We must flag this so the interrupt - * handler can take appropriate action if the primary - * DMA stream is currently active. - */ - set_bit( MGA_DMA_FLUSH, &dev_priv->prim.state ); - - /* If the primary DMA stream is currently idle, do the - * flush immediately. - */ - FLUSH_DMA(); - - DRM_INFO( "spin_unlock_bh() in %s\n", __FUNCTION__ ); - spin_unlock_bh( &dev_priv->prim.lock ); + mga_do_dma_flush( dev_priv ); } if ( lock.flags & _DRM_LOCK_QUIESCENT ) { @@ -1853,11 +1701,6 @@ int mga_irq_install( drm_device_t *dev, int irq ) dev->dma->next_queue = NULL; dev->dma->this_buffer = NULL; - INIT_LIST_HEAD( &dev->tq.list ); - dev->tq.sync = 0; - dev->tq.routine = mga_dma_task_queue; - dev->tq.data = dev; - /* Before installing handler */ MGA_WRITE( MGA_IEN, 0 ); @@ -1912,97 +1755,76 @@ if ( 0 ) { */ mga_do_wait_for_idle( dev_priv ); - for ( i = 0 ; i < 1 * 1024 ; i++ ) { + for ( i = 0 ; i < 256 ; i++ ) { DMA_LOCALS; - spin_lock_bh( &dev_priv->prim.lock ); - DRM_DEBUG( "spin_lock_bh() in %s\n", __FUNCTION__ ); - BEGIN_DMA( 8 ); - DMA_BLOCK( MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000 ); - - DMA_BLOCK( MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000 ); - - DMA_BLOCK( MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000 ); - - DMA_BLOCK( MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000 ); - - DMA_BLOCK( MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000 ); - - DMA_BLOCK( MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000 ); - - DMA_BLOCK( MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000 ); - - DMA_BLOCK( MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000, - MGA_DMAPAD, 0x00000000 ); + DMA_BLOCK( MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000 ); + + DMA_BLOCK( MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000 ); + + DMA_BLOCK( MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000 ); + + DMA_BLOCK( MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000 ); + + DMA_BLOCK( MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000 ); + + DMA_BLOCK( MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000 ); + + DMA_BLOCK( MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000 ); + + DMA_BLOCK( MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DMAPAD, 0x00000000, + MGA_DWGSYNC, 0x12345678 ); ADVANCE_DMA(); - DRM_DEBUG( "spin_unlock_bh() in %s\n", __FUNCTION__ ); - spin_unlock_bh( &dev_priv->prim.lock ); - - if ( (i & 0x7f) == 0x7f ) { - DRM_DEBUG( "*** forcing flush now ***\n" ); - - if ( mga_do_wait_for_idle( dev_priv ) < 0 ) - return -EINVAL; - - spin_lock_bh( &dev_priv->prim.lock ); - DRM_DEBUG( "spin_lock_bh() in %s\n", __FUNCTION__ ); - - mga_do_dma_flush( dev_priv ); - - DRM_DEBUG( "spin_unlock_bh() in %s\n", __FUNCTION__ ); - spin_unlock_bh( &dev_priv->prim.lock ); - } + FLUSH_DMA(); udelay( 5 ); - } - - /* Flush the primary DMA stream. - */ - mga_do_wait_for_idle( dev_priv ); - - DRM_DEBUG( "*** forcing final flush now ***\n" ); - - spin_lock_bh( &dev_priv->prim.lock ); - DRM_DEBUG( "spin_lock_bh() in %s\n", __FUNCTION__ ); - - mga_do_dma_flush( dev_priv ); - DRM_DEBUG( "spin_unlock_bh() in %s\n", __FUNCTION__ ); - spin_unlock_bh( &dev_priv->prim.lock ); + DRM_INFO( "\n" ); + DRM_INFO( "head = 0x%08x 0x%06x\n", + dev_priv->prim.status[0], + dev_priv->prim.status[0] - + dev_priv->primary->offset ); + DRM_INFO( "sync = 0x%08x\n", dev_priv->prim.status[1] ); + DRM_INFO( "\n" ); + } - mga_do_wait_for_idle( dev_priv ); + udelay( 10 ); - spin_lock_bh( &dev_priv->prim.lock ); + ret = 0; + if ( mga_do_wait_for_idle( dev_priv ) < 0 ) + ret = -EINVAL; - DRM_DEBUG( "head = 0x%08x\n", dev_priv->prim.status[0] ); - DRM_DEBUG( "sync = 0x%08x\n", dev_priv->prim.status[1] ); + DRM_INFO( "head = 0x%08x 0x%06x\n", + dev_priv->prim.status[0], + dev_priv->prim.status[0] - dev_priv->primary->offset ); + DRM_INFO( "sync = 0x%08x\n", dev_priv->prim.status[1] ); DRM_INFO( "\n" ); DRM_INFO( "space = 0x%x / 0x%x\n", dev_priv->prim.space, @@ -2010,7 +1832,7 @@ if ( 0 ) { DRM_INFO( "\n" ); DRM_INFO( " irqs = %d\n", atomic_read( &dev->total_irq ) ); - spin_unlock_bh( &dev_priv->prim.lock ); + return ret; } return 0; diff --git a/linux/mga_drv.h b/linux/mga_drv.h index 154ca429..97c8faef 100644 --- a/linux/mga_drv.h +++ b/linux/mga_drv.h @@ -60,7 +60,7 @@ typedef struct drm_mga_primary_buffer { u8 *end; int size; - u32 head; + volatile u32 *head; u32 tail; u32 wrap; int space; @@ -69,11 +69,8 @@ typedef struct drm_mga_primary_buffer { volatile u32 *status; u32 last_flush; - u32 low_mark; - u32 mid_mark; u32 high_mark; - unsigned long state; spinlock_t lock; } drm_mga_primary_buffer_t; @@ -200,8 +197,9 @@ extern int mga_do_dma_reset( drm_mga_private_t *dev_priv ); extern int mga_do_engine_reset( drm_mga_private_t *dev_priv ); extern int mga_do_cleanup_dma( drm_device_t *dev ); -extern int mga_dma_schedule( drm_device_t *dev ); -extern void mga_dma_wrap_or_wait( drm_mga_private_t *dev_priv, int n ); +extern void mga_do_dma_flush( drm_mga_private_t *dev_priv ); +extern void mga_do_dma_wrap( drm_mga_private_t *dev_priv ); + extern int mga_irq_uninstall( drm_device_t *dev ); /* mga_state.c */ @@ -379,18 +377,6 @@ do { \ } \ } while (0) -#define PRINT_DMA_STATE( dev_priv ) \ -do { \ - DRM_INFO( " state: %d %s%s%s\n", \ - dev_priv->prim.state, \ - test_bit( MGA_DMA_IDLE, &dev_priv->prim.state ) \ - ? "idle, " : "active, ", \ - test_bit( MGA_DMA_FLUSH, &dev_priv->prim.state ) \ - ? "flush, " : "", \ - test_bit( MGA_DMA_WRAP, &dev_priv->prim.state ) \ - ? "wrap, " : "" ); \ -} while (0) - /* ================================================================ * Primary DMA command stream @@ -398,7 +384,8 @@ do { \ #define MGA_VERBOSE 0 -#define DMA_LOCALS unsigned int write; volatile u8 *prim; +#define DMA_LOCALS unsigned int write; volatile u8 *prim; \ + unsigned long flags; #define DMA_BLOCK_SIZE (5 * sizeof(u32)) #define BEGIN_DMA( n ) \ @@ -406,55 +393,40 @@ do { \ if ( MGA_VERBOSE ) { \ DRM_INFO( "BEGIN_DMA( %d ) in %s\n", \ (n), __FUNCTION__ ); \ - DRM_DEBUG( " space=0x%x req=0x%x\n", \ + DRM_INFO( " space=0x%x req=0x%x\n", \ dev_priv->prim.space, (n) * DMA_BLOCK_SIZE ); \ } \ if ( dev_priv->prim.space < (int)((n) * DMA_BLOCK_SIZE) ) { \ - mga_dma_wrap_or_wait( dev_priv, \ - (n) * DMA_BLOCK_SIZE ); \ + mga_do_dma_wrap( dev_priv ); \ } \ prim = dev_priv->prim.start; \ write = dev_priv->prim.tail; \ } while (0) -#define ADVANCE_DMA() \ +#define BEGIN_DMA_WRAP() \ do { \ - dev_priv->prim.space -= (write - dev_priv->prim.tail); \ - dev_priv->prim.tail = write; \ if ( MGA_VERBOSE ) { \ - DRM_INFO( "ADVANCE_DMA() tail=0x%05x sp=0x%x s=%lx\n", \ - write, dev_priv->prim.space, \ - dev_priv->prim.state ); \ + DRM_INFO( "BEGIN_DMA_WRAP() in %s\n", __FUNCTION__ ); \ + DRM_INFO( " space=0x%x\n", dev_priv->prim.space ); \ } \ + prim = dev_priv->prim.start; \ + write = dev_priv->prim.tail; \ } while (0) -#define MAYBE_FLUSH_DMA() \ +#define ADVANCE_DMA() \ do { \ - if ( dev_priv->prim.wrap && MGA_DMA_IS_IDLE( dev_priv ) ) { \ - DRM_INFO( "MAYBE_FLUSH_DMA() wrap at 0x%x\n", \ - dev_priv->prim.wrap ); \ - mga_do_dma_wrap( dev_priv ); \ - } else if ( dev_priv->prim.tail - dev_priv->prim.last_flush >= \ - dev_priv->prim.mid_mark && \ - MGA_DMA_IS_IDLE( dev_priv ) ) { \ - DRM_INFO( "MAYBE_FLUSH_DMA() wm hit 0x%x >= 0x%x\n", \ - dev_priv->prim.tail - \ - dev_priv->prim.last_flush, \ - dev_priv->prim.mid_mark ); \ - mga_do_dma_flush( dev_priv ); \ + dev_priv->prim.space -= (write - dev_priv->prim.tail); \ + spin_lock_irqsave( &dev_priv->prim.lock, flags ); \ + dev_priv->prim.tail = write; \ + spin_unlock_irqrestore( &dev_priv->prim.lock, flags ); \ + if ( MGA_VERBOSE ) { \ + DRM_INFO( "ADVANCE_DMA() tail=0x%05x sp=0x%x\n", \ + write, dev_priv->prim.space ); \ } \ } while (0) -#define FLUSH_DMA() \ -do { \ - if ( MGA_DMA_IS_IDLE( dev_priv ) ) { \ - if ( dev_priv->prim.wrap ) { \ - mga_do_dma_wrap( dev_priv ); \ - } else { \ - mga_do_dma_flush( dev_priv ); \ - } \ - } \ -} while (0) +#define FLUSH_DMA() mga_do_dma_flush( dev_priv ); + /* Never use this, always use DMA_BLOCK(...) for primary DMA output. */ diff --git a/linux/mga_state.c b/linux/mga_state.c index 48a1baf8..5093d1ed 100644 --- a/linux/mga_state.c +++ b/linux/mga_state.c @@ -70,8 +70,6 @@ static void mga_emit_clip_rect( drm_mga_private_t *dev_priv, unsigned int pitch = dev_priv->front_pitch / dev_priv->fb_cpp; DMA_LOCALS; - return; - BEGIN_DMA( 2 ); /* Force reset of DWGCTL on G400 (eliminates clip disable bit). @@ -522,10 +520,7 @@ static void mga_dma_dispatch_clear( drm_device_t *dev, int nbox = sarea_priv->nbox; int i; DMA_LOCALS; - DRM_INFO( "%s\n", __FUNCTION__ ); - - spin_lock_bh( &dev_priv->prim.lock ); - DRM_INFO( "spin_lock_bh() in %s\n", __FUNCTION__ ); + DRM_DEBUG( "%s\n", __FUNCTION__ ); for ( i = 0 ; i < nbox ; i++ ) { unsigned int height = pbox[i].y2 - pbox[i].y1; @@ -583,8 +578,7 @@ static void mga_dma_dispatch_clear( drm_device_t *dev, ADVANCE_DMA(); - DRM_INFO( "spin_unlock_bh() in %s\n", __FUNCTION__ ); - spin_unlock_bh( &dev_priv->prim.lock ); + mga_do_dma_flush( dev_priv ); } static void mga_dma_dispatch_swap( drm_device_t *dev ) @@ -597,10 +591,7 @@ static void mga_dma_dispatch_swap( drm_device_t *dev ) u32 pitch = dev_priv->front_pitch / dev_priv->fb_cpp; int i; DMA_LOCALS; - DRM_INFO( "%s\n", __FUNCTION__ ); - - spin_lock_bh( &dev_priv->prim.lock ); - DRM_INFO( "spin_lock_bh() in %s\n", __FUNCTION__ ); + DRM_DEBUG( "%s\n", __FUNCTION__ ); BEGIN_DMA( 4 + nbox ); @@ -637,8 +628,7 @@ static void mga_dma_dispatch_swap( drm_device_t *dev ) ADVANCE_DMA(); - DRM_INFO( "spin_unlock_bh() in %s\n", __FUNCTION__ ); - spin_unlock_bh( &dev_priv->prim.lock ); + mga_do_dma_flush( dev_priv ); } @@ -652,11 +642,8 @@ static void mga_dma_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf ) int i = 0; DMA_LOCALS; - DRM_INFO( "%s: buf=%d used=%d\n", - __FUNCTION__, buf->idx, buf->used ); - - spin_lock_bh( &dev_priv->prim.lock ); - DRM_INFO( "spin_lock_bh() in %s\n", __FUNCTION__ ); + DRM_DEBUG( "%s: buf=%d used=%d\n", + __FUNCTION__, buf->idx, buf->used ); if ( buf->used ) { buf_priv->dispatched = 1; @@ -707,8 +694,7 @@ static void mga_dma_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf ) mga_freelist_put( dev, buf ); } - DRM_INFO( "spin_unlock_bh() in %s\n", __FUNCTION__ ); - spin_unlock_bh( &dev_priv->prim.lock ); + mga_do_dma_flush( dev_priv ); } @@ -858,16 +844,6 @@ int mga_dma_swap( struct inode *inode, struct file *filp, */ dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CONTEXT; - /* If we're idle, flush the primary DMA stream... - */ - spin_lock_bh( &dev_priv->prim.lock ); - DRM_INFO( "spin_lock_bh() in %s\n", __FUNCTION__ ); - - FLUSH_DMA(); - - DRM_INFO( "spin_unlock_bh() in %s\n", __FUNCTION__ ); - spin_unlock_bh( &dev_priv->prim.lock ); - return 0; } |