<commit_before>/*
 * Copyright 2008 Advanced Micro Devices, Inc.
 * Copyright 2008 Red Hat Inc.
 * Copyright 2009 <NAME>.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: <NAME>
 *          <NAME>
 *          <NAME>
 */
#include <linux/kernel.h>
#include "drmP.h"
#include "radeon.h"
#include "r600d.h"
#include "r600_reg_safe.h"

static int r600_cs_packet_next_reloc_mm(struct radeon_cs_parser *p,
					struct radeon_cs_reloc **cs_reloc);
static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p,
					struct radeon_cs_reloc **cs_reloc);
typedef int (*next_reloc_t)(struct radeon_cs_parser*, struct radeon_cs_reloc**);
static next_reloc_t r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_mm;
extern void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size);


struct r600_cs_track {
	/* configuration we miror so that we use same code btw kms/ums */
	u32			group_size;
	u32			nbanks;
	u32			npipes;
	/* value we track */
	u32			sq_config;
	u32			nsamples;
	u32			cb_color_base_last[8];
	struct radeon_bo	*cb_color_bo[8];
	u32			cb_color_bo_offset[8];
	struct radeon_bo	*cb_color_frag_bo[8];
	struct radeon_bo	*cb_color_tile_bo[8];
	u32			cb_color_info[8];
	u32			cb_color_size_idx[8];
	u32			cb_target_mask;
	u32			cb_shader_mask;
	u32			cb_color_size[8];
	u32			vgt_strmout_en;
	u32			vgt_strmout_buffer_en;
	u32			db_depth_control;
	u32			db_depth_info;
	u32			db_depth_size_idx;
	u32			db_depth_view;
	u32			db_depth_size;
	u32			db_offset;
	struct radeon_bo	*db_bo;
};

static inline int r600_bpe_from_format(u32 *bpe, u32 format)
{
	switch (format) {
	case V_038004_COLOR_8:
	case V_038004_COLOR_4_4:
	case V_038004_COLOR_3_3_2:
	case V_038004_FMT_1:
		*bpe = 1;
		break;
	case V_038004_COLOR_16:
	case V_038004_COLOR_16_FLOAT:
	case V_038004_COLOR_8_8:
	case V_038004_COLOR_5_6_5:
	case V_038004_COLOR_6_5_5:
	case V_038004_COLOR_1_5_5_5:
	case V_038004_COLOR_4_4_4_4:
	case V_038004_COLOR_5_5_5_1:
		*bpe = 2;
		break;
	case V_038004_FMT_8_8_8:
		*bpe = 3;
		break;
	case V_038004_COLOR_32:
	case V_038004_COLOR_32_FLOAT:
	case V_038004_COLOR_16_16:
	case V_038004_COLOR_16_16_FLOAT:
	case V_038004_COLOR_8_24:
	case V_038004_COLOR_8_24_FLOAT:
	case V_038004_COLOR_24_8:
	case V_038004_COLOR_24_8_FLOAT:
	case V_038004_COLOR_10_11_11:
	case V_038004_COLOR_10_11_11_FLOAT:
	case V_038004_COLOR_11_11_10:
	case V_038004_COLOR_11_11_10_FLOAT:
	case V_038004_COLOR_2_10_10_10:
	case V_038004_COLOR_8_8_8_8:
	case V_038004_COLOR_10_10_10_2:
	case V_038004_FMT_5_9_9_9_SHAREDEXP:
	case V_038004_FMT_32_AS_8:
	case V_038004_FMT_32_AS_8_8:
		*bpe = 4;
		break;
	case V_038004_COLOR_X24_8_32_FLOAT:
	case V_038004_COLOR_32_32:
	case V_038004_COLOR_32_32_FLOAT:
	case V_038004_COLOR_16_16_16_16:
	case V_038004_COLOR_16_16_16_16_FLOAT:
		*bpe = 8;
		break;
	case V_038004_FMT_16_16_16:
	case V_038004_FMT_16_16_16_FLOAT:
		*bpe = 6;
		break;
	case V_038004_FMT_32_32_32:
	case V_038004_FMT_32_32_32_FLOAT:
		*bpe = 12;
		break;
	case V_038004_COLOR_32_32_32_32:
	case V_038004_COLOR_32_32_32_32_FLOAT:
		*bpe = 16;
		break;
	case V_038004_FMT_GB_GR:
	case V_038004_FMT_BG_RG:
	case V_038004_COLOR_INVALID:
	default:
		*bpe = 16;
		return -EINVAL;
	}
	return 0;
}

static void r600_cs_track_init(struct r600_cs_track *track)
{
	int i;

	/* assume DX9 mode */
	track->sq_config = DX9_CONSTS;
	for (i = 0; i < 8; i++) {
		track->cb_color_base_last[i] = 0;
		track->cb_color_size[i] = 0;
		track->cb_color_size_idx[i] = 0;
		track->cb_color_info[i] = 0;
		track->cb_color_bo[i] = NULL;
		track->cb_color_bo_offset[i] = 0xFFFFFFFF;
	}
	track->cb_target_mask = 0xFFFFFFFF;
	track->cb_shader_mask = 0xFFFFFFFF;
	track->db_bo = NULL;
	/* assume the biggest format and that htile is enabled */
	track->db_depth_info = 7 | (1 << 25);
	track->db_depth_view = 0xFFFFC000;
	track->db_depth_size = 0xFFFFFFFF;
	track->db_depth_size_idx = 0;
	track->db_depth_control = 0xFFFFFFFF;
}

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, pitch_align;
	volatile u32 *ib = p->ib->ptr;
	unsigned array_mode;

	if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
		dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
		return -EINVAL;
	}
	size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i];
	if (r600_bpe_from_format(&bpe, G_0280A0_FORMAT(track->cb_color_info[i]))) {
		dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08X)\n",
			 __func__, __LINE__, G_0280A0_FORMAT(track->cb_color_info[i]),
			i, track->cb_color_info[i]);
		return -EINVAL;
	}
	/* 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 *= 64;
	height = slice_tile_max / (pitch * 8);
	if (height > 8192)
		height = 8192;
	array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]);
	switch (array_mode) {
	case V_0280A0_ARRAY_LINEAR_GENERAL:
		/* technically height & 0x7 */
		break;
	case V_0280A0_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 cb pitch (%d) invalid\n",
				 __func__, __LINE__, pitch);
			return -EINVAL;
		}
		if (!IS_ALIGNED(height, 8)) {
			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
				 __func__, __LINE__, height);
			return -EINVAL;
		}
		break;
	case V_0280A0_ARRAY_1D_TILED_THIN1:
		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",
				 __func__, __LINE__, pitch);
			return -EINVAL;
		}
		/* avoid breaking userspace */
		if (height > 7)
			height &= ~0x7;
		if (!IS_ALIGNED(height, 8)) {
			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
				 __func__, __LINE__, height);
			return -EINVAL;
		}
		break;
	case V_0280A0_ARRAY_2D_TILED_THIN1:
		pitch_align = max((u32)track->nbanks,
				  (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8;
		if (!IS_ALIGNED(pitch, pitch_align)) {
			dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
				__func__, __LINE__, pitch);
			return -EINVAL;
		}
		if (!IS_ALIGNED((height / 8), track->npipes)) {
			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
				 __func__, __LINE__, height);
			return -EINVAL;
		}
		break;
	default:
		dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
			G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i,
			track->cb_color_info[i]);
		return -EINVAL;
	}
	/* check offset */
	tmp = height * pitch * 8 * bpe;
	if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
		if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
			/* the initial DDX does bad things with the CB size occasionally */
			/* it rounds up height too far for slice tile max but the BO is smaller */
			tmp = (height - 7) * 8 * bpe;
			if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
				dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
				return -EINVAL;
			}
		} else {
			dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[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;
	}
	/* limit max tile */
	tmp = (height * pitch * 8) >> 6;
	if (tmp < slice_tile_max)
		slice_tile_max = tmp;
	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;
}

static int r600_cs_track_check(struct radeon_cs_parser *p)
{
	struct r600_cs_track *track = p->track;
	u32 tmp;
	int r, i;
	volatile u32 *ib = p->ib->ptr;

	/* on legacy kernel we don't perform advanced check */
	if (p->rdev == NULL)
		return 0;
	/* we don't support out buffer yet */
	if (track->vgt_strmout_en || track->vgt_strmout_buffer_en) {
		dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n");
		return -EINVAL;
	}
	/* check that we have a cb for each enabled target, we don't check
	 * shader_mask because it seems mesa isn't always setting it :(
	 */
	tmp = track->cb_target_mask;
	for (i = 0; i < 8; i++) {
		if ((tmp >> (i * 4)) & 0xF) {
			/* at least one component is enabled */
			if (track->cb_color_bo[i] == NULL) {
				dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
					__func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i);
				return -EINVAL;
			}
			/* perform rewrite of CB_COLOR[0-7]_SIZE */
			r = r600_cs_track_validate_cb(p, i);
			if (r)
				return r;
		}
	}
	/* Check depth buffer */
	if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
		G_028800_Z_ENABLE(track->db_depth_control)) {
		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;
		}
		if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) {
			dev_warn(p->dev, "this kernel doesn't support z/stencil htile\n");
			return -EINVAL;
		}
		switch (G_028010_FORMAT(track->db_depth_info)) {
		case V_028010_DEPTH_16:
			bpe = 2;
			break;
		case V_028010_DEPTH_X8_24:
		case V_028010_DEPTH_8_24:
		case V_028010_DEPTH_X8_24_FLOAT:
		case V_028010_DEPTH_8_24_FLOAT:
		case V_028010_DEPTH_32_FLOAT:
			bpe = 4;
			break;
		case V_028010_DEPTH_X24_8_32_FLOAT:
			bpe = 8;
			break;
		default:
			dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info));
			return -EINVAL;
		}
		if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
			if (!track->db_depth_size_idx) {
				dev_warn(p->dev, "z/stencil buffer size not set\n");
				return -EINVAL;
			}
			tmp = radeon_bo_size(track->db_bo) - track->db_offset;
			tmp = (tmp / bpe) >> 6;
			if (!tmp) {
				dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n",
						track->db_depth_size, bpe, track->db_offset,
						radeon_bo_size(track->db_bo));
				return -EINVAL;
			}
			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);
				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)) / 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), track->npipes)) {
					dev_warn(p->dev, "%s:%d db height (%d) invalid\n",<commit_msg>drm/radeon/kms: fix tiled db height calculation on 6xx/7xx<commit_after>/*
 * Copyright 2008 Advanced Micro Devices, Inc.
 * Copyright 2008 Red Hat Inc.
 * Copyright 2009 <NAME>.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: <NAME>
 *          <NAME>
 *          <NAME>
 */
#include <linux/kernel.h>
#include "drmP.h"
#include "radeon.h"
#include "r600d.h"
#include "r600_reg_safe.h"

static int r600_cs_packet_next_reloc_mm(struct radeon_cs_parser *p,
					struct radeon_cs_reloc **cs_reloc);
static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p,
					struct radeon_cs_reloc **cs_reloc);
typedef int (*next_reloc_t)(struct radeon_cs_parser*, struct radeon_cs_reloc**);
static next_reloc_t r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_mm;
extern void r600_cs_legacy_get_tiling_conf(struct drm_device *dev, u32 *npipes, u32 *nbanks, u32 *group_size);


struct r600_cs_track {
	/* configuration we miror so that we use same code btw kms/ums */
	u32			group_size;
	u32			nbanks;
	u32			npipes;
	/* value we track */
	u32			sq_config;
	u32			nsamples;
	u32			cb_color_base_last[8];
	struct radeon_bo	*cb_color_bo[8];
	u32			cb_color_bo_offset[8];
	struct radeon_bo	*cb_color_frag_bo[8];
	struct radeon_bo	*cb_color_tile_bo[8];
	u32			cb_color_info[8];
	u32			cb_color_size_idx[8];
	u32			cb_target_mask;
	u32			cb_shader_mask;
	u32			cb_color_size[8];
	u32			vgt_strmout_en;
	u32			vgt_strmout_buffer_en;
	u32			db_depth_control;
	u32			db_depth_info;
	u32			db_depth_size_idx;
	u32			db_depth_view;
	u32			db_depth_size;
	u32			db_offset;
	struct radeon_bo	*db_bo;
};

static inline int r600_bpe_from_format(u32 *bpe, u32 format)
{
	switch (format) {
	case V_038004_COLOR_8:
	case V_038004_COLOR_4_4:
	case V_038004_COLOR_3_3_2:
	case V_038004_FMT_1:
		*bpe = 1;
		break;
	case V_038004_COLOR_16:
	case V_038004_COLOR_16_FLOAT:
	case V_038004_COLOR_8_8:
	case V_038004_COLOR_5_6_5:
	case V_038004_COLOR_6_5_5:
	case V_038004_COLOR_1_5_5_5:
	case V_038004_COLOR_4_4_4_4:
	case V_038004_COLOR_5_5_5_1:
		*bpe = 2;
		break;
	case V_038004_FMT_8_8_8:
		*bpe = 3;
		break;
	case V_038004_COLOR_32:
	case V_038004_COLOR_32_FLOAT:
	case V_038004_COLOR_16_16:
	case V_038004_COLOR_16_16_FLOAT:
	case V_038004_COLOR_8_24:
	case V_038004_COLOR_8_24_FLOAT:
	case V_038004_COLOR_24_8:
	case V_038004_COLOR_24_8_FLOAT:
	case V_038004_COLOR_10_11_11:
	case V_038004_COLOR_10_11_11_FLOAT:
	case V_038004_COLOR_11_11_10:
	case V_038004_COLOR_11_11_10_FLOAT:
	case V_038004_COLOR_2_10_10_10:
	case V_038004_COLOR_8_8_8_8:
	case V_038004_COLOR_10_10_10_2:
	case V_038004_FMT_5_9_9_9_SHAREDEXP:
	case V_038004_FMT_32_AS_8:
	case V_038004_FMT_32_AS_8_8:
		*bpe = 4;
		break;
	case V_038004_COLOR_X24_8_32_FLOAT:
	case V_038004_COLOR_32_32:
	case V_038004_COLOR_32_32_FLOAT:
	case V_038004_COLOR_16_16_16_16:
	case V_038004_COLOR_16_16_16_16_FLOAT:
		*bpe = 8;
		break;
	case V_038004_FMT_16_16_16:
	case V_038004_FMT_16_16_16_FLOAT:
		*bpe = 6;
		break;
	case V_038004_FMT_32_32_32:
	case V_038004_FMT_32_32_32_FLOAT:
		*bpe = 12;
		break;
	case V_038004_COLOR_32_32_32_32:
	case V_038004_COLOR_32_32_32_32_FLOAT:
		*bpe = 16;
		break;
	case V_038004_FMT_GB_GR:
	case V_038004_FMT_BG_RG:
	case V_038004_COLOR_INVALID:
	default:
		*bpe = 16;
		return -EINVAL;
	}
	return 0;
}

static void r600_cs_track_init(struct r600_cs_track *track)
{
	int i;

	/* assume DX9 mode */
	track->sq_config = DX9_CONSTS;
	for (i = 0; i < 8; i++) {
		track->cb_color_base_last[i] = 0;
		track->cb_color_size[i] = 0;
		track->cb_color_size_idx[i] = 0;
		track->cb_color_info[i] = 0;
		track->cb_color_bo[i] = NULL;
		track->cb_color_bo_offset[i] = 0xFFFFFFFF;
	}
	track->cb_target_mask = 0xFFFFFFFF;
	track->cb_shader_mask = 0xFFFFFFFF;
	track->db_bo = NULL;
	/* assume the biggest format and that htile is enabled */
	track->db_depth_info = 7 | (1 << 25);
	track->db_depth_view = 0xFFFFC000;
	track->db_depth_size = 0xFFFFFFFF;
	track->db_depth_size_idx = 0;
	track->db_depth_control = 0xFFFFFFFF;
}

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, pitch_align;
	volatile u32 *ib = p->ib->ptr;
	unsigned array_mode;

	if (G_0280A0_TILE_MODE(track->cb_color_info[i])) {
		dev_warn(p->dev, "FMASK or CMASK buffer are not supported by this kernel\n");
		return -EINVAL;
	}
	size = radeon_bo_size(track->cb_color_bo[i]) - track->cb_color_bo_offset[i];
	if (r600_bpe_from_format(&bpe, G_0280A0_FORMAT(track->cb_color_info[i]))) {
		dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08X)\n",
			 __func__, __LINE__, G_0280A0_FORMAT(track->cb_color_info[i]),
			i, track->cb_color_info[i]);
		return -EINVAL;
	}
	/* 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 *= 64;
	height = slice_tile_max / (pitch * 8);
	if (height > 8192)
		height = 8192;
	array_mode = G_0280A0_ARRAY_MODE(track->cb_color_info[i]);
	switch (array_mode) {
	case V_0280A0_ARRAY_LINEAR_GENERAL:
		/* technically height & 0x7 */
		break;
	case V_0280A0_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 cb pitch (%d) invalid\n",
				 __func__, __LINE__, pitch);
			return -EINVAL;
		}
		if (!IS_ALIGNED(height, 8)) {
			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
				 __func__, __LINE__, height);
			return -EINVAL;
		}
		break;
	case V_0280A0_ARRAY_1D_TILED_THIN1:
		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",
				 __func__, __LINE__, pitch);
			return -EINVAL;
		}
		/* avoid breaking userspace */
		if (height > 7)
			height &= ~0x7;
		if (!IS_ALIGNED(height, 8)) {
			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
				 __func__, __LINE__, height);
			return -EINVAL;
		}
		break;
	case V_0280A0_ARRAY_2D_TILED_THIN1:
		pitch_align = max((u32)track->nbanks,
				  (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)) / 8;
		if (!IS_ALIGNED(pitch, pitch_align)) {
			dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n",
				__func__, __LINE__, pitch);
			return -EINVAL;
		}
		if (!IS_ALIGNED((height / 8), track->npipes)) {
			dev_warn(p->dev, "%s:%d cb height (%d) invalid\n",
				 __func__, __LINE__, height);
			return -EINVAL;
		}
		break;
	default:
		dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__,
			G_0280A0_ARRAY_MODE(track->cb_color_info[i]), i,
			track->cb_color_info[i]);
		return -EINVAL;
	}
	/* check offset */
	tmp = height * pitch * 8 * bpe;
	if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
		if (array_mode == V_0280A0_ARRAY_LINEAR_GENERAL) {
			/* the initial DDX does bad things with the CB size occasionally */
			/* it rounds up height too far for slice tile max but the BO is smaller */
			tmp = (height - 7) * 8 * bpe;
			if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) {
				dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[i]));
				return -EINVAL;
			}
		} else {
			dev_warn(p->dev, "%s offset[%d] %d %d %lu too big\n", __func__, i, track->cb_color_bo_offset[i], tmp, radeon_bo_size(track->cb_color_bo[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;
	}
	/* limit max tile */
	tmp = (height * pitch * 8) >> 6;
	if (tmp < slice_tile_max)
		slice_tile_max = tmp;
	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;
}

static int r600_cs_track_check(struct radeon_cs_parser *p)
{
	struct r600_cs_track *track = p->track;
	u32 tmp;
	int r, i;
	volatile u32 *ib = p->ib->ptr;

	/* on legacy kernel we don't perform advanced check */
	if (p->rdev == NULL)
		return 0;
	/* we don't support out buffer yet */
	if (track->vgt_strmout_en || track->vgt_strmout_buffer_en) {
		dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n");
		return -EINVAL;
	}
	/* check that we have a cb for each enabled target, we don't check
	 * shader_mask because it seems mesa isn't always setting it :(
	 */
	tmp = track->cb_target_mask;
	for (i = 0; i < 8; i++) {
		if ((tmp >> (i * 4)) & 0xF) {
			/* at least one component is enabled */
			if (track->cb_color_bo[i] == NULL) {
				dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
					__func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i);
				return -EINVAL;
			}
			/* perform rewrite of CB_COLOR[0-7]_SIZE */
			r = r600_cs_track_validate_cb(p, i);
			if (r)
				return r;
		}
	}
	/* Check depth buffer */
	if (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
		G_028800_Z_ENABLE(track->db_depth_control)) {
		u32 nviews, bpe, ntiles, pitch, pitch_align, height, size, slice_tile_max;
		if (track->db_bo == NULL) {
			dev_warn(p->dev, "z/stencil with no depth buffer\n");
			return -EINVAL;
		}
		if (G_028010_TILE_SURFACE_ENABLE(track->db_depth_info)) {
			dev_warn(p->dev, "this kernel doesn't support z/stencil htile\n");
			return -EINVAL;
		}
		switch (G_028010_FORMAT(track->db_depth_info)) {
		case V_028010_DEPTH_16:
			bpe = 2;
			break;
		case V_028010_DEPTH_X8_24:
		case V_028010_DEPTH_8_24:
		case V_028010_DEPTH_X8_24_FLOAT:
		case V_028010_DEPTH_8_24_FLOAT:
		case V_028010_DEPTH_32_FLOAT:
			bpe = 4;
			break;
		case V_028010_DEPTH_X24_8_32_FLOAT:
			bpe = 8;
			break;
		default:
			dev_warn(p->dev, "z/stencil with invalid format %d\n", G_028010_FORMAT(track->db_depth_info));
			return -EINVAL;
		}
		if ((track->db_depth_size & 0xFFFFFC00) == 0xFFFFFC00) {
			if (!track->db_depth_size_idx) {
				dev_warn(p->dev, "z/stencil buffer size not set\n");
				return -EINVAL;
			}
			tmp = radeon_bo_size(track->db_bo) - track->db_offset;
			tmp = (tmp / bpe) >> 6;
			if (!tmp) {
				dev_warn(p->dev, "z/stencil buffer too small (0x%08X %d %d %ld)\n",
						track->db_depth_size, bpe, track->db_offset,
						radeon_bo_size(track->db_bo));
				return -EINVAL;
			}
			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;
			slice_tile_max = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1;
			slice_tile_max *= 64;
			height = slice_tile_max / (pitch * 8);
			if (height > 8192)
				height = 8192;
			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;
				}
				/* don't break userspace */
				height &= ~0x7;
				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)) / 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), track->npipes)) {
					dev_warn(p->dev, "%s:%d db height (%d) invalid\n",
{'fraction_non_alphanumeric': 0.12626659335480322, 'fraction_numerical': 0.07359987432251984, 'mean_word_length': 4.17751118340789, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 245, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 10, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7298019', 'n_tokens_mistral': 12530, 'n_tokens_neox': 10541, 'n_words': 2335}