drm/radeon/kms: fix CS alignment checking for tiling (v2)
Covers depth, cb, and textures. Hopefully I got this right. v2: - fix bugs: https://bugs.freedesktop.org/show_bug.cgi?id=28327 https://bugs.freedesktop.org/show_bug.cgi?id=28381 - use ALIGNED(), IS_ALIGNED() macros Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
7f81337720
commit
40e2a5c15d
|
@ -25,6 +25,7 @@
|
||||||
* Alex Deucher
|
* Alex Deucher
|
||||||
* Jerome Glisse
|
* Jerome Glisse
|
||||||
*/
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include "drmP.h"
|
#include "drmP.h"
|
||||||
#include "radeon.h"
|
#include "radeon.h"
|
||||||
#include "r600d.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)
|
static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
|
||||||
{
|
{
|
||||||
struct r600_cs_track *track = p->track;
|
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;
|
volatile u32 *ib = p->ib->ptr;
|
||||||
|
|
||||||
if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
|
if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
|
||||||
|
@ -180,56 +181,57 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
|
||||||
i, track->cb_color_info[i]);
|
i, track->cb_color_info[i]);
|
||||||
return -EINVAL;
|
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;
|
slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1;
|
||||||
if (!pitch) {
|
height = size / (pitch * 8 * bpe);
|
||||||
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);
|
|
||||||
if (height > 8192)
|
if (height > 8192)
|
||||||
height = 8192;
|
height = 8192;
|
||||||
|
if (height > 7)
|
||||||
|
height &= ~0x7;
|
||||||
switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) {
|
switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) {
|
||||||
case V_0280A0_ARRAY_LINEAR_GENERAL:
|
case V_0280A0_ARRAY_LINEAR_GENERAL:
|
||||||
|
/* technically height & 0x7 */
|
||||||
|
break;
|
||||||
case V_0280A0_ARRAY_LINEAR_ALIGNED:
|
case V_0280A0_ARRAY_LINEAR_ALIGNED:
|
||||||
if (pitch & 0x3f) {
|
pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
|
||||||
dev_warn(p->dev, "%s:%d cb pitch (%d x %d = %d) invalid\n",
|
if (!IS_ALIGNED(pitch, pitch_align)) {
|
||||||
__func__, __LINE__, pitch, bpe, pitch * bpe);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if ((pitch * bpe) & (track->group_size - 1)) {
|
|
||||||
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
||||||
__func__, __LINE__, pitch);
|
__func__, __LINE__, pitch);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
if (!IS_ALIGNED(height, 8)) {
|
||||||
|
dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
|
||||||
|
__func__, __LINE__, height);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case V_0280A0_ARRAY_1D_TILED_THIN1:
|
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;
|
||||||
|
if (!IS_ALIGNED(pitch, pitch_align)) {
|
||||||
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
||||||
__func__, __LINE__, pitch);
|
__func__, __LINE__, pitch);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
height &= ~0x7;
|
if (!IS_ALIGNED(height, 8)) {
|
||||||
if (!height)
|
dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
|
||||||
height = 8;
|
__func__, __LINE__, height);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case V_0280A0_ARRAY_2D_TILED_THIN1:
|
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));
|
||||||
|
if (!IS_ALIGNED(pitch, pitch_align)) {
|
||||||
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
||||||
__func__, __LINE__, pitch);
|
__func__, __LINE__, pitch);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
tmp = pitch * 8 * bpe * track->nsamples;
|
if (!IS_ALIGNED((height / 8), track->nbanks)) {
|
||||||
tmp = tmp / track->nbanks;
|
dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
|
||||||
if (tmp & (track->group_size - 1)) {
|
__func__, __LINE__, height);
|
||||||
dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
|
|
||||||
__func__, __LINE__, pitch);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
height &= ~((16 * track->npipes) - 1);
|
|
||||||
if (!height)
|
|
||||||
height = 16 * track->npipes;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
|
dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
|
||||||
|
@ -238,16 +240,20 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
/* check offset */
|
/* check offset */
|
||||||
tmp = height * pitch;
|
tmp = height * pitch * 8 * bpe;
|
||||||
if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
|
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]);
|
dev_warn(p->dev, "%s offset[%d] %d too big\n", __func__, i, track->cb_color_bo_offset[i]);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) {
|
||||||
|
dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
/* limit max tile */
|
/* limit max tile */
|
||||||
tmp = (height * pitch) >> 6;
|
tmp = (height * pitch * 8) >> 6;
|
||||||
if (tmp < slice_tile_max)
|
if (tmp < slice_tile_max)
|
||||||
slice_tile_max = tmp;
|
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);
|
S_028060_SLICE_TILE_MAX(slice_tile_max - 1);
|
||||||
ib[track->cb_color_size_idx[i]] = tmp;
|
ib[track->cb_color_size_idx[i]] = tmp;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -289,7 +295,7 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
|
||||||
/* Check depth buffer */
|
/* Check depth buffer */
|
||||||
if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
|
if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
|
||||||
G_028800_Z_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) {
|
if (track->db_bo == NULL) {
|
||||||
dev_warn(p->dev, "z/stencil with no depth buffer\n");
|
dev_warn(p->dev, "z/stencil with no depth buffer\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -332,6 +338,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);
|
ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF);
|
||||||
} else {
|
} 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);
|
||||||
|
if (!IS_ALIGNED(pitch, pitch_align)) {
|
||||||
|
dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n",
|
||||||
|
__func__, __LINE__, pitch);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
if (!IS_ALIGNED(height, 8)) {
|
||||||
|
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));
|
||||||
|
if (!IS_ALIGNED(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 (!IS_ALIGNED(track->db_offset, track->group_size)) {
|
||||||
|
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;
|
ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
|
||||||
nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
|
nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1;
|
||||||
tmp = ntiles * bpe * 64 * nviews;
|
tmp = ntiles * bpe * 64 * nviews;
|
||||||
|
@ -983,6 +1034,7 @@ static inline unsigned minify(unsigned size, unsigned levels)
|
||||||
|
|
||||||
static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels,
|
static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels,
|
||||||
unsigned w0, unsigned h0, unsigned d0, unsigned bpe,
|
unsigned w0, unsigned h0, unsigned d0, unsigned bpe,
|
||||||
|
unsigned pitch_align,
|
||||||
unsigned *l0_size, unsigned *mipmap_size)
|
unsigned *l0_size, unsigned *mipmap_size)
|
||||||
{
|
{
|
||||||
unsigned offset, i, level, face;
|
unsigned offset, i, level, face;
|
||||||
|
@ -996,13 +1048,13 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels
|
||||||
height = minify(h0, i);
|
height = minify(h0, i);
|
||||||
depth = minify(d0, i);
|
depth = minify(d0, i);
|
||||||
for(face = 0; face < nfaces; face++) {
|
for(face = 0; face < nfaces; face++) {
|
||||||
rowstride = ((width * bpe) + 255) & ~255;
|
rowstride = ALIGN((width * bpe), pitch_align);
|
||||||
size = height * rowstride * depth;
|
size = height * rowstride * depth;
|
||||||
offset += size;
|
offset += size;
|
||||||
offset = (offset + 0x1f) & ~0x1f;
|
offset = (offset + 0x1f) & ~0x1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*l0_size = (((w0 * bpe) + 255) & ~255) * h0 * d0;
|
*l0_size = ALIGN((w0 * bpe), pitch_align) * h0 * d0;
|
||||||
*mipmap_size = offset;
|
*mipmap_size = offset;
|
||||||
if (!blevel)
|
if (!blevel)
|
||||||
*mipmap_size -= *l0_size;
|
*mipmap_size -= *l0_size;
|
||||||
|
@ -1025,8 +1077,9 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i
|
||||||
struct radeon_bo *mipmap,
|
struct radeon_bo *mipmap,
|
||||||
u32 tiling_flags)
|
u32 tiling_flags)
|
||||||
{
|
{
|
||||||
|
struct r600_cs_track *track = p->track;
|
||||||
u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0;
|
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 */
|
/* on legacy kernel we don't perform advanced check */
|
||||||
if (p->rdev == NULL)
|
if (p->rdev == NULL)
|
||||||
|
@ -1063,11 +1116,55 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i
|
||||||
__func__, __LINE__, G_038004_DATA_FORMAT(word1));
|
__func__, __LINE__, G_038004_DATA_FORMAT(word1));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pitch = G_038000_PITCH(word0) + 1;
|
||||||
|
switch (G_038000_TILE_MODE(word0)) {
|
||||||
|
case V_038000_ARRAY_LINEAR_GENERAL:
|
||||||
|
pitch_align = 1;
|
||||||
|
/* XXX check height align */
|
||||||
|
break;
|
||||||
|
case V_038000_ARRAY_LINEAR_ALIGNED:
|
||||||
|
pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8;
|
||||||
|
if (!IS_ALIGNED(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;
|
||||||
|
if (!IS_ALIGNED(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));
|
||||||
|
if (!IS_ALIGNED(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);
|
word0 = radeon_get_ib_value(p, idx + 4);
|
||||||
word1 = radeon_get_ib_value(p, idx + 5);
|
word1 = radeon_get_ib_value(p, idx + 5);
|
||||||
blevel = G_038010_BASE_LEVEL(word0);
|
blevel = G_038010_BASE_LEVEL(word0);
|
||||||
nlevels = G_038014_LAST_LEVEL(word1);
|
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),
|
||||||
|
&l0_size, &mipmap_size);
|
||||||
/* using get ib will give us the offset into the texture bo */
|
/* using get ib will give us the offset into the texture bo */
|
||||||
word0 = radeon_get_ib_value(p, idx + 2);
|
word0 = radeon_get_ib_value(p, idx + 2);
|
||||||
if ((l0_size + word0) > radeon_bo_size(texture)) {
|
if ((l0_size + word0) > radeon_bo_size(texture)) {
|
||||||
|
|
Loading…
Reference in New Issue