[PATCH 4/5] drm/radeon/kms: fix CS alignment checking for tiling

Alex Deucher alexdeucher at gmail.com
Tue May 25 16:05:40 PDT 2010


Covers, depth, cb, and textures. Hopefully I got this right.

Signed-off-by: Alex Deucher <alexdeucher at gmail.com>
---
 drivers/gpu/drm/radeon/r600_cs.c |  172 ++++++++++++++++++++++++++++++-------
 1 files changed, 139 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index 5cab1b4..133f0da 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -25,6 +25,7 @@
  *          Alex Deucher
  *          Jerome Glisse
  */
+#include <linux/kernel.h>
 #include "drmP.h"
 #include "radeon.h"
 #include "r600d.h"
@@ -166,7 +167,7 @@ static void r600_cs_track_init(struct r600_cs_track *track)
 static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
 {
 	struct r600_cs_track *track = p->track;
-	u32 bpe = 0, pitch, slice_tile_max, size, tmp, height;
+	u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align;
 	volatile u32 *ib = p->ib->ptr;
 
 	if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
@@ -180,56 +181,67 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
 			i, track->cb_color_info[i]);
 		return -EINVAL;
 	}
-	pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) << 3;
+	/* pitch is the number of 8x8 tiles per row */
+	pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1;
 	slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
 	if (!pitch) {
 		dev_warn(p->dev, "%s:%d cb pitch (%d) for %d invalid (0x%08X)\n",
 			__func__, __LINE__, pitch, i, track->cb_color_size[i]);
 		return -EINVAL;
 	}
-	height = size / (pitch * bpe);
+	height = size / (pitch * 8 * bpe);
 	if (height > 8192)
 		height = 8192;
+	height &= ~0x7;
+	if (!height)
+		height = 8;
 	switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) {
 	case V_0280A0_ARRAY_LINEAR_GENERAL:
-	case V_0280A0_ARRAY_LINEAR_ALIGNED:
-		if (pitch & 0x3f) {
-			dev_warn(p->dev, "%s:%d cb pitch (%d x %d = %d) invalid\n",
-				__func__, __LINE__, pitch, bpe, pitch * bpe);
+		if (height & 0x7) {
+			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+				 __func__, __LINE__, height);
 			return -EINVAL;
 		}
-		if ((pitch * bpe) & (track->group_size - 1)) {
+		break;
+	case V_0280A0_ARRAY_LINEAR_ALIGNED:
+		pitch_align = (max((u32)64, (u32)(track->group_size / bpe)) / 8) - 1;
+		if (pitch & pitch_align) {
 			dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-				__func__, __LINE__, pitch);
+				 __func__, __LINE__, pitch);
+			return -EINVAL;
+		}
+		if (height & 0x7) {
+			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+				 __func__, __LINE__, height);
 			return -EINVAL;
 		}
 		break;
 	case V_0280A0_ARRAY_1D_TILED_THIN1:
-		if ((pitch * 8 * bpe * track->nsamples) & (track->group_size - 1)) {
+		pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8) - 1;
+		if (pitch & pitch_align) {
 			dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-				__func__, __LINE__, pitch);
+				 __func__, __LINE__, pitch);
+			return -EINVAL;
+		}
+		if (height & 0x7) {
+			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+				 __func__, __LINE__, height);
 			return -EINVAL;
 		}
-		height &= ~0x7;
-		if (!height)
-			height = 8;
 		break;
 	case V_0280A0_ARRAY_2D_TILED_THIN1:
-		if (pitch & ((8 * track->nbanks) - 1)) {
+		pitch_align = max((u32)track->nbanks,
+				  (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) - 1;
+		if (pitch & pitch_align) {
 			dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
 				__func__, __LINE__, pitch);
 			return -EINVAL;
 		}
-		tmp = pitch * 8 * bpe * track->nsamples;
-		tmp = tmp / track->nbanks;
-		if (tmp & (track->group_size - 1)) {
-			dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
-				__func__, __LINE__, pitch);
+		if ((height / 8) & (track->nbanks - 1)) {
+			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
+				 __func__, __LINE__, height);
 			return -EINVAL;
 		}
-		height &= ~((16 * track->npipes) - 1);
-		if (!height)
-			height = 16 * track->npipes;
 		break;
 	default:
 		dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
@@ -238,16 +250,20 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
 		return -EINVAL;
 	}
 	/* check offset */
-	tmp = height * pitch;
+	tmp = height * pitch * 8;
 	if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
 		dev_warn(p->dev, "%s offset[%d] %d to big\n", __func__, i, track->cb_color_bo_offset[i]);
 		return -EINVAL;
 	}
+	if (track->cb_color_bo_offset[i] & (track->group_size - 1)) {
+		dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]);
+		return -EINVAL;
+	}
 	/* limit max tile */
-	tmp = (height * pitch) >> 6;
+	tmp = (height * pitch * 8) >> 6;
 	if (tmp < slice_tile_max)
 		slice_tile_max = tmp;
-	tmp = S_028060_PITCH_TILE_MAX((pitch >> 3) - 1) |
+	tmp = S_028060_PITCH_TILE_MAX(pitch - 1) |
 		S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
 	ib[track->cb_color_size_idx[i]] = tmp;
 	return 0;
@@ -289,7 +305,7 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
 	/* Check depth buffer */
 	if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
 		G_028800_Z_ENABLE(track->db_depth_control)) {
-		u32 nviews, bpe, ntiles;
+		u32 nviews, bpe, ntiles, pitch, pitch_align, height, size;
 		if (track->db_bo == NULL) {
 			dev_warn(p->dev, "z/stencil with no depth buffer\n");
 			return -EINVAL;
@@ -332,6 +348,51 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
 			}
 			ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
 		} else {
+			size = radeon_bo_size(track->db_bo);
+			pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1;
+			height = size / (pitch * 8 * bpe);
+			height &= ~0x7;
+			if (!height)
+				height = 8;
+
+			switch (G_028010_ARRAY_MODE(track->db_depth_info)) {
+			case V_028010_ARRAY_1D_TILED_THIN1:
+				pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8) - 1;
+				if (pitch & pitch_align) {
+					dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
+						 __func__, __LINE__, pitch);
+					return -EINVAL;
+				}
+				if (height & 0x7) {
+					dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
+						 __func__, __LINE__, height);
+					return -EINVAL;
+				}
+				break;
+			case V_028010_ARRAY_2D_TILED_THIN1:
+				pitch_align = max((u32)track->nbanks,
+						  (u32)(((track->group_size / 8) / bpe) * track->nbanks)) - 1;
+				if (pitch & pitch_align) {
+					dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
+						 __func__, __LINE__, pitch);
+					return -EINVAL;
+				}
+				if ((height / 8) & (track->nbanks - 1)) {
+					dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
+						 __func__, __LINE__, height);
+					return -EINVAL;
+				}
+				break;
+			default:
+				dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+					 G_028010_ARRAY_MODE(track->db_depth_info),
+					 track->db_depth_info);
+				return -EINVAL;
+			}
+			if (track->db_offset & (track->group_size - 1)) {
+				dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset);
+				return -EINVAL;
+			}
 			ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
 			nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
 			tmp = ntiles * bpe * 64 * nviews;
@@ -982,8 +1043,9 @@ static inline unsigned minify(unsigned size, unsigned levels)
 }
 
 static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels,
-				unsigned w0, unsigned h0, unsigned d0, unsigned bpe,
-				unsigned *l0_size, unsigned *mipmap_size)
+			      unsigned w0, unsigned h0, unsigned d0, unsigned bpe,
+			      unsigned pitch_align,
+			      unsigned *l0_size, unsigned *mipmap_size)
 {
 	unsigned offset, i, level, face;
 	unsigned width, height, depth, rowstride, size;
@@ -996,13 +1058,13 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels
 		height = minify(h0, i);
 		depth = minify(d0, i);
 		for(face = 0; face < nfaces; face++) {
-			rowstride = ((width * bpe) + 255) & ~255;
+			rowstride = ((width * bpe) + pitch_align) & ~pitch_align;
 			size = height * rowstride * depth;
 			offset += size;
 			offset = (offset + 0x1f) & ~0x1f;
 		}
 	}
-	*l0_size = (((w0 * bpe) + 255) & ~255) * h0 * d0;
+	*l0_size = (((w0 * bpe) + pitch_align) & ~pitch_align) * h0 * d0;
 	*mipmap_size = offset;
 	if (!blevel)
 		*mipmap_size -= *l0_size;
@@ -1025,8 +1087,9 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 i
 					      struct radeon_bo *mipmap,
 					      u32 tiling_flags)
 {
+	struct r600_cs_track *track = p->track;
 	u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0;
-	u32 word0, word1, l0_size, mipmap_size;
+	u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align;
 
 	/* on legacy kernel we don't perform advanced check */
 	if (p->rdev == NULL)
@@ -1063,11 +1126,54 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 i
 			 __func__, __LINE__, G_038004_DATA_FORMAT(word1));
 		return -EINVAL;
 	}
+
+	pitch = G_038000_PITCH(word0) + 1;
+	switch (G_038000_TILE_MODE(word0)) {
+	case V_038000_ARRAY_LINEAR_GENERAL:
+		/* XXX check height align */
+		break;
+	case V_038000_ARRAY_LINEAR_ALIGNED:
+		pitch_align = (max((u32)64, (u32)(track->group_size / bpe)) / 8) - 1;
+		if (pitch & pitch_align) {
+			dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
+				 __func__, __LINE__, pitch);
+			return -EINVAL;
+		}
+		/* XXX check height align */
+		break;
+	case V_038000_ARRAY_1D_TILED_THIN1:
+		pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8) - 1;
+		if (pitch & pitch_align) {
+			dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
+				 __func__, __LINE__, pitch);
+			return -EINVAL;
+		}
+		/* XXX check height align */
+		break;
+	case V_038000_ARRAY_2D_TILED_THIN1:
+		pitch_align = max((u32)track->nbanks,
+				  (u32)(((track->group_size / 8) / bpe) * track->nbanks)) - 1;
+		if (pitch & pitch_align) {
+			dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n",
+				__func__, __LINE__, pitch);
+			return -EINVAL;
+		}
+		/* XXX check height align */
+		break;
+	default:
+		dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__,
+			 G_038000_TILE_MODE(word0), word0);
+		return -EINVAL;
+	}
+	/* XXX check offset align */
+
 	word0 = radeon_get_ib_value(p, idx + 4);
 	word1 = radeon_get_ib_value(p, idx + 5);
 	blevel = G_038010_BASE_LEVEL(word0);
 	nlevels = G_038014_LAST_LEVEL(word1);
-	r600_texture_size(nfaces, blevel, nlevels, w0, h0, d0, bpe, &l0_size, &mipmap_size);
+	r600_texture_size(nfaces, blevel, nlevels, w0, h0, d0, bpe,
+			  (pitch_align * bpe) - 1,
+			  &l0_size, &mipmap_size);
 	/* using get ib will give us the offset into the texture bo */
 	word0 = radeon_get_ib_value(p, idx + 2);
 	if ((l0_size + word0) > radeon_bo_size(texture)) {
-- 
1.5.6.3



More information about the dri-devel mailing list