From 4247ca942a16745da3d09c58996b276d02655a72 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 20 Feb 2009 13:28:34 +1000 Subject: [PATCH] drm/radeon: align ring writes to 16 dwords boundaries. On some radeon GPUs this appears to introduce another level of stability around interacting with the ring. Its pretty much what fglrx appears to do. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cp.c | 32 +++++++++++++++++++++++++++++ drivers/gpu/drm/radeon/radeon_drv.h | 20 ++++++++---------- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index a18b3688a7f0..78a058fc039f 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -1950,3 +1950,35 @@ int radeon_driver_unload(struct drm_device *dev) dev->dev_private = NULL; return 0; } + +void radeon_commit_ring(drm_radeon_private_t *dev_priv) +{ + int i; + u32 *ring; + int tail_aligned; + + /* check if the ring is padded out to 16-dword alignment */ + + tail_aligned = dev_priv->ring.tail & 0xf; + if (tail_aligned) { + int num_p2 = 16 - tail_aligned; + + ring = dev_priv->ring.start; + /* pad with some CP_PACKET2 */ + for (i = 0; i < num_p2; i++) + ring[dev_priv->ring.tail + i] = CP_PACKET2(); + + dev_priv->ring.tail += i; + + dev_priv->ring.space -= num_p2 * sizeof(u32); + } + + dev_priv->ring.tail &= dev_priv->ring.tail_mask; + + DRM_MEMORYBARRIER(); + GET_RING_HEAD( dev_priv ); + + RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail ); + /* read from PCI bus to ensure correct posting */ + RADEON_READ( RADEON_CP_RB_RPTR ); +} diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index ecfd414bb99c..aa078cbe38f3 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -1376,15 +1376,16 @@ do { \ #define RADEON_VERBOSE 0 -#define RING_LOCALS int write, _nr; unsigned int mask; u32 *ring; +#define RING_LOCALS int write, _nr, _align_nr; unsigned int mask; u32 *ring; #define BEGIN_RING( n ) do { \ if ( RADEON_VERBOSE ) { \ DRM_INFO( "BEGIN_RING( %d )\n", (n)); \ } \ - if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \ + _align_nr = (n + 0xf) & ~0xf; \ + if (dev_priv->ring.space <= (_align_nr * sizeof(u32))) { \ COMMIT_RING(); \ - radeon_wait_ring( dev_priv, (n) * sizeof(u32) ); \ + radeon_wait_ring( dev_priv, _align_nr * sizeof(u32)); \ } \ _nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \ ring = dev_priv->ring.start; \ @@ -1401,19 +1402,16 @@ do { \ DRM_ERROR( \ "ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n", \ ((dev_priv->ring.tail + _nr) & mask), \ - write, __LINE__); \ + write, __LINE__); \ } else \ dev_priv->ring.tail = write; \ } while (0) +extern void radeon_commit_ring(drm_radeon_private_t *dev_priv); + #define COMMIT_RING() do { \ - /* Flush writes to ring */ \ - DRM_MEMORYBARRIER(); \ - GET_RING_HEAD( dev_priv ); \ - RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail ); \ - /* read from PCI bus to ensure correct posting */ \ - RADEON_READ( RADEON_CP_RB_RPTR ); \ -} while (0) + radeon_commit_ring(dev_priv); \ + } while(0) #define OUT_RING( x ) do { \ if ( RADEON_VERBOSE ) { \ -- 2.20.1