summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorJose Fonseca <jrfonseca@users.sourceforge.net>2002-06-06 09:15:50 +0000
committerJose Fonseca <jrfonseca@users.sourceforge.net>2002-06-06 09:15:50 +0000
commitfe8e3bcca99ec39e30bb33918e8af75afb60af36 (patch)
tree8565d04830cc55e7232c4569d5e5a8c4e7c8d566 /linux
parentc7f975325e87cdead26c4f92cfd6ac79f7164cd4 (diff)
The bus master operation is now always checked on the wait loops, fixing
the lockups experienced in the NO_BATCH_DISPATCH code path. All other code paths besides NO_BATCH_DISPATCH are broken. do_dma_flush waits for completion of all DMA buffers and not just idle engine.
Diffstat (limited to 'linux')
-rw-r--r--linux/mach64_dma.c122
-rw-r--r--linux/mach64_drv.h122
2 files changed, 69 insertions, 175 deletions
diff --git a/linux/mach64_dma.c b/linux/mach64_dma.c
index 92e78155..27fa9e63 100644
--- a/linux/mach64_dma.c
+++ b/linux/mach64_dma.c
@@ -27,6 +27,7 @@
* Gareth Hughes <gareth@valinux.com>
* Frank C. Earl <fearl@airmail.net>
* Leif Delgass <ldelgass@retinalburn.net>
+ * José Fonseca <j_r_fonseca@yahoo.co.uk>
*/
#include "mach64.h"
@@ -180,52 +181,43 @@ int mach64_wait_ring( drm_mach64_private_t *dev_priv, int n )
}
/* Wait until all DMA requests have been processed... */
-int mach64_do_wait_for_dma( drm_mach64_private_t *dev_priv )
+int mach64_do_dma_flush( drm_mach64_private_t *dev_priv )
{
- int i, ret;
-
- /* Assume we timeout... */
- ret = -EBUSY;
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
+ int i;
- for ( i = 0 ; i < dev_priv->usec_timeout; i++ )
- {
- if ( list_empty(&dev_priv->dma_queue) )
- {
- ret = mach64_do_wait_for_idle( dev_priv );
- break;
+ for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
+ mach64_update_ring_snapshot( dev_priv );
+ if ( ring->head == ring->tail ) {
+ if (i > 0) {
+ DRM_DEBUG( "do_dma_idle: %d usecs\n", i );
+ }
+ return 0;
}
udelay( 1 );
}
- if (ret != 0)
- DRM_INFO( "do_wait_for_dma failed! GUI_STAT=0x%08x\n", MACH64_READ( MACH64_GUI_STAT ) );
-
- return ret;
+ DRM_INFO( "%s failed! GUI_STAT=0x%08x\n", __FUNCTION__,
+ MACH64_READ( MACH64_GUI_STAT ) );
+ return -EBUSY;
}
int mach64_do_dma_idle( drm_mach64_private_t *dev_priv ) {
int ret;
-#if MACH64_NO_BATCH_DISPATCH
- u32 reg;
-#endif
/* wait for completion */
- if ( (ret = mach64_do_wait_for_idle( dev_priv )) < 0 ) {
+ if ( (ret = mach64_do_dma_flush( dev_priv )) < 0 ) {
DRM_ERROR( "%s failed BM_GUI_TABLE=0x%08x tail: %d\n", __FUNCTION__,
MACH64_READ(MACH64_BM_GUI_TABLE), dev_priv->ring.tail );
return ret;
}
-#if MACH64_NO_BATCH_DISPATCH
- reg = MACH64_READ( MACH64_BUS_CNTL );
/* Disable bus-mastering, but keep block 1 registers enabled */
- MACH64_WRITE( MACH64_BUS_CNTL, reg | MACH64_BUS_MASTER_DIS | MACH64_BUS_EXT_REG_EN );
+ MACH64_WRITE( MACH64_BUS_CNTL, MACH64_READ( MACH64_BUS_CNTL ) | MACH64_BUS_MASTER_DIS | MACH64_BUS_EXT_REG_EN );
MACH64_WRITE( MACH64_SRC_CNTL, 0 );
- return 0;
-#else
+
/* clean up after pass */
mach64_do_release_used_buffers( dev_priv );
return 0;
-#endif
}
/* Reset the engine. This will stop the DMA if it is running.
@@ -1038,40 +1030,34 @@ static int mach64_do_dispatch_pseudo_dma( drm_mach64_private_t *dev_priv )
#endif /* MACH64_NO_BATCH_DISPATCH */
-int mach64_do_dma_flush( drm_mach64_private_t *dev_priv )
+int mach64_dma_start( drm_mach64_private_t *dev_priv )
{
#if MACH64_NO_BATCH_DISPATCH
drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
- UPDATE_RING_HEAD( dev_priv, ring );
-
- if ( ring->tail != ring->head &&
- !(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE) ) {
-
- if (ring->head_addr < ring->start_addr ||
- ring->head_addr > ring->start_addr + (ring->size - 4*sizeof(u32))) {
- DRM_ERROR("Bad address in BM_GUI_TABLE: 0x%08x\n", ring->head_addr);
- return -EINVAL;
- }
-
+ if ( (MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE) )
+ return 0;
+
+ if ( !(MACH64_READ(MACH64_SRC_CNTL) & MACH64_SRC_BM_ENABLE) ) {
/* enable bus mastering and block 1 registers */
MACH64_WRITE( MACH64_BUS_CNTL,
( MACH64_READ(MACH64_BUS_CNTL) &
~MACH64_BUS_MASTER_DIS )
| MACH64_BUS_EXT_REG_EN );
- /* reset descriptor table ring head */
- MACH64_WRITE( MACH64_BM_GUI_TABLE_CMD,
- ( ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB ) );
/* enable GUI-master operation */
MACH64_WRITE( MACH64_SRC_CNTL,
MACH64_SRC_BM_ENABLE | MACH64_SRC_BM_SYNC |
MACH64_SRC_BM_OP_SYSTEM_TO_REG );
- /* kick off the transfer */
- MACH64_WRITE( MACH64_DST_HEIGHT_WIDTH, 0 );
- DRM_DEBUG( "%s: new dispatch: head_addr: 0x%08x head: %d tail: %d space: %d\n",
- __FUNCTION__,
- ring->head_addr, ring->head, ring->tail, ring->space);
}
+
+ if ( ring->head_addr < ring->start_addr ||
+ ring->head_addr > ring->start_addr + (ring->size - 4 * sizeof(u32)) ) {
+ DRM_ERROR("Bad address in BM_GUI_TABLE: 0x%08x\n", ring->head_addr);
+ return -EINVAL;
+ }
+
+ UPDATE_RING_HEAD( dev_priv, ring );
+
return 0;
#else
DRM_DEBUG("%s\n", __FUNCTION__);
@@ -1211,8 +1197,7 @@ int mach64_dma_flush( struct inode *inode, struct file *filp,
VB_AGE_TEST_WITH_RETURN( dev_priv );
- DMAFLUSH( dev_priv );
- return 0;
+ return mach64_do_dma_flush( dev_priv );
}
int mach64_engine_reset( struct inode *inode, struct file *filp,
@@ -1303,11 +1288,8 @@ drm_buf_t *mach64_freelist_get( drm_mach64_private_t *dev_priv )
int t;
if ( list_empty(&dev_priv->free_list) ) {
-#if !MACH64_USE_BUFFER_AGING
u32 head, tail, ofs;
-#else
- u32 done_age = 0;
-#endif
+
if ( list_empty( &dev_priv->pending ) ) {
/* All 3 lists should never be empty - this is here for debugging */
if ( list_empty( &dev_priv->dma_queue ) ) {
@@ -1320,16 +1302,8 @@ drm_buf_t *mach64_freelist_get( drm_mach64_private_t *dev_priv )
}
}
-#if MACH64_NO_BATCH_DISPATCH
- /* Make sure we haven't gone idle */
- mach64_do_dma_flush( dev_priv );
-#endif
-
-#if !MACH64_USE_BUFFER_AGING
tail = ring->tail;
-#endif
for ( t = 0 ; t < dev_priv->usec_timeout ; t++ ) {
-#if !MACH64_USE_BUFFER_AGING
UPDATE_RING_HEAD( dev_priv, ring );
head = ring->head;
@@ -1339,16 +1313,12 @@ drm_buf_t *mach64_freelist_get( drm_mach64_private_t *dev_priv )
DRM_DEBUG( "%s: idle engine, freed all buffers.\n", __FUNCTION__ );
goto _freelist_entry_found;
}
-#else
- done_age = MACH64_READ( MACH64_LAST_DISPATCH_REG );
-#endif
/* Look for a completed buffer and bail out of the loop
* as soon as we find one -- don't waste time trying
* to free extra bufs here, leave that to do_release_used_buffers
*/
list_for_each_safe(ptr, tmp, &dev_priv->pending) {
entry = list_entry(ptr, drm_mach64_freelist_t, list);
-#if !MACH64_USE_BUFFER_AGING
ofs = entry->ring_ofs;
if ( (head < tail && (ofs < head || ofs >= tail)) ||
(head > tail && (ofs < head && ofs >= tail)) ) {
@@ -1359,24 +1329,10 @@ drm_buf_t *mach64_freelist_get( drm_mach64_private_t *dev_priv )
DRM_DEBUG( "%s: freed processed buffer (head=%d tail=%d buf ring ofs=%d).\n", __FUNCTION__, head, tail, ofs );
goto _freelist_entry_found;
}
-#else
- if (entry->age <= done_age && done_age > 0) {
- /* found a processed buffer */
- entry->buf->pending = 0;
- list_del(ptr);
- list_add_tail(ptr, &dev_priv->free_list);
- DRM_DEBUG( "%s: freed processed buffer (buffer age: %d last dispatch reg: %d last_dispatch: %d\n", __FUNCTION__, entry->age, done_age, dev_priv->sarea_priv->last_dispatch );
- goto _freelist_entry_found;
- }
-#endif
}
udelay( 1 );
}
-#if !MACH64_USE_BUFFER_AGING
DRM_ERROR( "timeout waiting for buffers: ring head_addr: 0x%08x head: %d tail: %d last cmd ofs %d\n", ring->head_addr, ring->head, ring->tail, ring->last_cmd_ofs );
-#else
- DRM_ERROR( "timeout waiting for buffers: last dispatch reg: %d last_dispatch: %d\n", done_age, dev_priv->sarea_priv->last_dispatch );
-#endif
return NULL;
}
@@ -1454,18 +1410,6 @@ static int mach64_dma_get_buffers( drm_device_t *dev, drm_dma_t *d )
return 0;
}
-/*
- Through some pretty thorough testing, it has been found that the
- RagePRO engine will pretty much ignore any "commands" sent
- via the gui-master pathway that aren't gui operations (the register
- gets set, but the actions that are normally associated with the setting
- of those said registers doesn't happen.). So, it's safe to send us
- buffers of gui commands from userspace (altering the buffer in mid-
- execution will at worst scribble all over the screen and pushing
- bogus commands will have no apparent effect...)
-
- FCE (03-08-2002)
-*/
int mach64_dma_buffers( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg )
{
diff --git a/linux/mach64_drv.h b/linux/mach64_drv.h
index 8e2c5068..c1335ff9 100644
--- a/linux/mach64_drv.h
+++ b/linux/mach64_drv.h
@@ -45,7 +45,7 @@
#define MACH64_USE_BUFFER_AGING 0
#define MACH64_USE_FRAME_AGING 0
-#define MACH64_NO_BATCH_DISPATCH 0
+#define MACH64_NO_BATCH_DISPATCH 1
#define MACH64_DEFAULT_MODE MACH64_MODE_DMA_ASYNC
@@ -98,7 +98,7 @@ typedef struct drm_mach64_private {
drm_mach64_descriptor_ring_t ring;
struct list_head free_list; /* Free-list head */
- struct list_head placeholders; /* Free-list placeholder list */
+ struct list_head placeholders; /* Free-list placeholder list */
struct list_head pending; /* Pending submission placeholder */
struct list_head dma_queue; /* Submission queue head */
@@ -147,6 +147,8 @@ extern int mach64_do_release_used_buffers( drm_mach64_private_t *dev_priv );
extern void mach64_dump_engine_info( drm_mach64_private_t *dev_priv );
extern int mach64_do_engine_reset( drm_mach64_private_t *dev_priv );
+extern int mach64_dma_start( drm_mach64_private_t *dev_priv );
+
extern int mach64_do_dma_idle( drm_mach64_private_t *dev_priv );
extern int mach64_do_dma_flush( drm_mach64_private_t *dev_priv );
extern int mach64_do_cleanup_dma( drm_device_t *dev );
@@ -454,19 +456,28 @@ extern int mach64_dma_blit( struct inode *inode, struct file *filp,
* Misc helper macros
*/
-#define UPDATE_RING_HEAD( dev_priv, ring ) \
-do { \
- int idle = 0; \
- if (!(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE)) idle = 1; \
- (ring)->head_addr = (MACH64_READ(MACH64_BM_GUI_TABLE) & 0xfffffff0); \
- /* If not idle, BM_GUI_TABLE points one descriptor past the current head */ \
- if ( !idle ) { \
- if ((ring)->head_addr == (ring)->start_addr) \
- (ring)->head_addr += ((ring)->size - (sizeof(u32)*4)); \
- else \
- (ring)->head_addr -= (sizeof(u32)*4); \
- } \
- (ring)->head = ((ring)->head_addr - (ring)->start_addr) / sizeof(u32); \
+#define UPDATE_RING_HEAD( dev_priv, ring ) \
+do { \
+ int gui_active = MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE; \
+ (ring)->head_addr = (MACH64_READ(MACH64_BM_GUI_TABLE) & 0xfffffff0); \
+ if ( gui_active ) { \
+ /* If not idle, BM_GUI_TABLE points one descriptor past the current head */ \
+ if ((ring)->head_addr == (ring)->start_addr) \
+ (ring)->head_addr += (ring)->size - 4 * sizeof(u32)*4; \
+ else \
+ (ring)->head_addr -= 4 * sizeof(u32); \
+ } \
+ (ring)->head = ((ring)->head_addr - (ring)->start_addr) / sizeof(u32); \
+ if ( !gui_active && (ring)->head != (ring)->tail ) { \
+ /* reset descriptor table ring head */ \
+ MACH64_WRITE( MACH64_BM_GUI_TABLE_CMD, \
+ ( (ring)->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB ) ); \
+ /* kick off the transfer */ \
+ MACH64_WRITE( MACH64_DST_HEIGHT_WIDTH, 0 ); \
+ DRM_DEBUG( "%s: new dispatch: head_addr: 0x%08x head: %d tail: %d space: %d\n", \
+ __FUNCTION__, \
+ (ring)->head_addr, (ring)->head, (ring)->tail, (ring)->space); \
+ } \
} while (0)
static inline void
@@ -579,8 +590,7 @@ do { \
* DMA descriptor ring macros
*/
-#define RING_LOCALS \
- int write; unsigned int tail_mask; u32 *ring;
+#define RING_LOCALS int tail, write; unsigned int mask; volatile u32 *ring;
#define RING_WRITE_OFS write
@@ -601,8 +611,8 @@ do { \
} \
dev_priv->ring.space -= (n) * sizeof(u32); \
ring = (u32 *) dev_priv->ring.start; \
- write = dev_priv->ring.tail; \
- tail_mask = dev_priv->ring.tail_mask; \
+ tail = write = dev_priv->ring.tail; \
+ mask = dev_priv->ring.tail_mask; \
} while (0)
#define OUT_RING( x ) \
@@ -612,41 +622,22 @@ do { \
(unsigned int)(x), write ); \
} \
ring[write++] = cpu_to_le32( x ); \
- write &= tail_mask; \
+ write &= mask; \
} while (0)
#define ADVANCE_RING() \
do { \
if ( MACH64_VERBOSE ) { \
DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \
- write, dev_priv->ring.tail ); \
+ write, tail ); \
} \
+ ring[(write - 2) & mask] |= cpu_to_le32( DMA_EOL ); \
+ wmb(); \
+ ring[(tail - 2) & mask] &= cpu_to_le32( ~DMA_EOL ); \
+ wmb(); \
dev_priv->ring.tail = write; \
} while (0)
-#define COMMIT_RING() \
-do { \
- int last_cmd_ofs; u32 last_cmd; \
- UPDATE_RING_HEAD( dev_priv, &dev_priv->ring ); \
- DRM_DEBUG("COMMIT_RING() head: %d tail: %d last_cmd_ofs: %d\n", \
- dev_priv->ring.head, dev_priv->ring.tail, \
- dev_priv->ring.last_cmd_ofs); \
- \
- last_cmd_ofs = dev_priv->ring.tail - 2; \
- if (last_cmd_ofs < 0) \
- last_cmd_ofs = dev_priv->ring.tail_mask - 1; \
- last_cmd = ring[last_cmd_ofs] & ~DMA_EOL; \
- /* set EOL flag */ \
- ring[last_cmd_ofs] = cpu_to_le32( last_cmd | DMA_EOL ); \
- wmb(); \
- /* clear EOL flag from previous ring tail */ \
- ring[dev_priv->ring.last_cmd_ofs] = \
- cpu_to_le32( dev_priv->ring.last_cmd ); \
- dev_priv->ring.last_cmd_ofs = last_cmd_ofs; \
- dev_priv->ring.last_cmd = last_cmd; \
- mach64_do_dma_flush( dev_priv ); \
-} while(0)
-
/* ================================================================
* DMA macros
@@ -690,8 +681,6 @@ do { \
buf->used += 8; \
} while (0)
-#if MACH64_NO_BATCH_DISPATCH
-
#define DMAADVANCE( dev_priv ) \
do { \
struct list_head *ptr; \
@@ -716,8 +705,6 @@ do { \
list_add_tail(ptr, &dev_priv->pending); \
\
ADD_BUF_TO_RING( dev_priv, entry ); \
- COMMIT_RING(); \
- \
} while (0)
#define ADD_BUF_TO_RING( dev_priv, entry ) \
@@ -757,44 +744,7 @@ do { \
OUT_RING( 0 ); \
\
ADVANCE_RING(); \
+ mach64_dma_start( dev_priv ); \
} while(0)
-#else
-
-#define DMAADVANCE( dev_priv ) \
-do { \
- struct list_head *ptr; \
- drm_mach64_freelist_t *entry; \
- \
- if ( MACH64_VERBOSE ) { \
- DRM_INFO( "DMAADVANCE() in %s\n", __FUNCTION__ ); \
- } \
- \
- if (list_empty(&dev_priv->placeholders)) { \
- DRM_ERROR( "%s: empty placeholder list in DMAADVANCE()\n", \
- __FUNCTION__ ); \
- return -EFAULT; \
- } \
- \
- /* Add the buffer to the DMA queue */ \
- ptr = dev_priv->placeholders.next; \
- list_del(ptr); \
- entry = list_entry(ptr, drm_mach64_freelist_t, list); \
- entry->buf = buf; \
- entry->buf->waiting = 1; \
- list_add_tail(ptr, &dev_priv->dma_queue); \
- \
-} while (0)
-#endif /* MACH64_NO_BATCH_DISPATCH */
-
-#define DMAFLUSH( dev_priv ) \
-do { \
- int ret; \
- if ( MACH64_VERBOSE ) { \
- DRM_INFO( "DMAFLUSH() in %s\n", __FUNCTION__ ); \
- } \
- if ((ret=mach64_do_dma_flush( dev_priv )) < 0) \
- return ret; \
-} while (0)
-
#endif /* __MACH64_DRV_H__ */