summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGareth Hughes <gareth@users.sourceforge.net>2001-01-31 16:30:45 +0000
committerGareth Hughes <gareth@users.sourceforge.net>2001-01-31 16:30:45 +0000
commit5f15407b9cfe89274557aa4b94aae89bb1688713 (patch)
tree5b8a31eeb361303dcfb7305335dfcb6efe15382d
parentb5366b97892ee5a80284cdd744ec6d4a8a996c21 (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.c440
-rw-r--r--linux/mga_drv.h74
-rw-r--r--linux/mga_state.c38
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;
}