瀏覽代碼

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 <airlied@redhat.com>
Dave Airlie 16 年之前
父節點
當前提交
4247ca942a
共有 2 個文件被更改,包括 41 次插入11 次删除
  1. 32 0
      drivers/gpu/drm/radeon/radeon_cp.c
  2. 9 11
      drivers/gpu/drm/radeon/radeon_drv.h

+ 32 - 0
drivers/gpu/drm/radeon/radeon_cp.c

@@ -1950,3 +1950,35 @@ int radeon_driver_unload(struct drm_device *dev)
 	dev->dev_private = NULL;
 	dev->dev_private = NULL;
 	return 0;
 	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 );
+}

+ 9 - 11
drivers/gpu/drm/radeon/radeon_drv.h

@@ -1376,15 +1376,16 @@ do {								\
 
 
 #define RADEON_VERBOSE	0
 #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 {						\
 #define BEGIN_RING( n ) do {						\
 	if ( RADEON_VERBOSE ) {						\
 	if ( RADEON_VERBOSE ) {						\
 		DRM_INFO( "BEGIN_RING( %d )\n", (n));			\
 		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();						\
                 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);		\
 	_nr = n; dev_priv->ring.space -= (n) * sizeof(u32);		\
 	ring = dev_priv->ring.start;					\
 	ring = dev_priv->ring.start;					\
@@ -1401,19 +1402,16 @@ do {								\
 		DRM_ERROR(						\
 		DRM_ERROR(						\
 			"ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n",	\
 			"ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n",	\
 			((dev_priv->ring.tail + _nr) & mask),		\
 			((dev_priv->ring.tail + _nr) & mask),		\
-			write, __LINE__);						\
+			write, __LINE__);				\
 	} else								\
 	} else								\
 		dev_priv->ring.tail = write;				\
 		dev_priv->ring.tail = write;				\
 } while (0)
 } while (0)
 
 
+extern void radeon_commit_ring(drm_radeon_private_t *dev_priv);
+
 #define COMMIT_RING() do {						\
 #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 {						\
 #define OUT_RING( x ) do {						\
 	if ( RADEON_VERBOSE ) {						\
 	if ( RADEON_VERBOSE ) {						\