evergreen_cs.c revision 261455
1254885Sdumbbell/*
2254885Sdumbbell * Copyright 2010 Advanced Micro Devices, Inc.
3254885Sdumbbell * Copyright 2008 Red Hat Inc.
4254885Sdumbbell * Copyright 2009 Jerome Glisse.
5254885Sdumbbell *
6254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a
7254885Sdumbbell * copy of this software and associated documentation files (the "Software"),
8254885Sdumbbell * to deal in the Software without restriction, including without limitation
9254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the
11254885Sdumbbell * Software is furnished to do so, subject to the following conditions:
12254885Sdumbbell *
13254885Sdumbbell * The above copyright notice and this permission notice shall be included in
14254885Sdumbbell * all copies or substantial portions of the Software.
15254885Sdumbbell *
16254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19254885Sdumbbell * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22254885Sdumbbell * OTHER DEALINGS IN THE SOFTWARE.
23254885Sdumbbell *
24254885Sdumbbell * Authors: Dave Airlie
25254885Sdumbbell *          Alex Deucher
26254885Sdumbbell *          Jerome Glisse
27254885Sdumbbell */
28254885Sdumbbell
29254885Sdumbbell#include <sys/cdefs.h>
30254885Sdumbbell__FBSDID("$FreeBSD: stable/10/sys/dev/drm2/radeon/evergreen_cs.c 261455 2014-02-04 03:36:42Z eadler $");
31254885Sdumbbell
32254885Sdumbbell#include <dev/drm2/drmP.h>
33254885Sdumbbell#include "radeon.h"
34254885Sdumbbell#include "radeon_asic.h"
35254885Sdumbbell#include "evergreend.h"
36254885Sdumbbell#include "evergreen_reg_safe.h"
37254885Sdumbbell#include "cayman_reg_safe.h"
38254885Sdumbbell#include "r600_cs.h"
39254885Sdumbbell
40254885Sdumbbell#define MAX(a,b)                   (((a)>(b))?(a):(b))
41254885Sdumbbell#define MIN(a,b)                   (((a)<(b))?(a):(b))
42254885Sdumbbell
43254885Sdumbbellstatic int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p,
44254885Sdumbbell					  struct radeon_cs_reloc **cs_reloc);
45254885Sdumbbell
46254885Sdumbbellstruct evergreen_cs_track {
47254885Sdumbbell	u32			group_size;
48254885Sdumbbell	u32			nbanks;
49254885Sdumbbell	u32			npipes;
50254885Sdumbbell	u32			row_size;
51254885Sdumbbell	/* value we track */
52254885Sdumbbell	u32			nsamples;		/* unused */
53254885Sdumbbell	struct radeon_bo	*cb_color_bo[12];
54254885Sdumbbell	u32			cb_color_bo_offset[12];
55254885Sdumbbell	struct radeon_bo	*cb_color_fmask_bo[8];	/* unused */
56254885Sdumbbell	struct radeon_bo	*cb_color_cmask_bo[8];	/* unused */
57254885Sdumbbell	u32			cb_color_info[12];
58254885Sdumbbell	u32			cb_color_view[12];
59254885Sdumbbell	u32			cb_color_pitch[12];
60254885Sdumbbell	u32			cb_color_slice[12];
61254885Sdumbbell	u32			cb_color_slice_idx[12];
62254885Sdumbbell	u32			cb_color_attrib[12];
63254885Sdumbbell	u32			cb_color_cmask_slice[8];/* unused */
64254885Sdumbbell	u32			cb_color_fmask_slice[8];/* unused */
65254885Sdumbbell	u32			cb_target_mask;
66254885Sdumbbell	u32			cb_shader_mask; /* unused */
67254885Sdumbbell	u32			vgt_strmout_config;
68254885Sdumbbell	u32			vgt_strmout_buffer_config;
69254885Sdumbbell	struct radeon_bo	*vgt_strmout_bo[4];
70254885Sdumbbell	u32			vgt_strmout_bo_offset[4];
71254885Sdumbbell	u32			vgt_strmout_size[4];
72254885Sdumbbell	u32			db_depth_control;
73254885Sdumbbell	u32			db_depth_view;
74254885Sdumbbell	u32			db_depth_slice;
75254885Sdumbbell	u32			db_depth_size;
76254885Sdumbbell	u32			db_z_info;
77254885Sdumbbell	u32			db_z_read_offset;
78254885Sdumbbell	u32			db_z_write_offset;
79254885Sdumbbell	struct radeon_bo	*db_z_read_bo;
80254885Sdumbbell	struct radeon_bo	*db_z_write_bo;
81254885Sdumbbell	u32			db_s_info;
82254885Sdumbbell	u32			db_s_read_offset;
83254885Sdumbbell	u32			db_s_write_offset;
84254885Sdumbbell	struct radeon_bo	*db_s_read_bo;
85254885Sdumbbell	struct radeon_bo	*db_s_write_bo;
86254885Sdumbbell	bool			sx_misc_kill_all_prims;
87254885Sdumbbell	bool			cb_dirty;
88254885Sdumbbell	bool			db_dirty;
89254885Sdumbbell	bool			streamout_dirty;
90254885Sdumbbell	u32			htile_offset;
91254885Sdumbbell	u32			htile_surface;
92254885Sdumbbell	struct radeon_bo	*htile_bo;
93254885Sdumbbell};
94254885Sdumbbell
95254885Sdumbbellstatic u32 evergreen_cs_get_aray_mode(u32 tiling_flags)
96254885Sdumbbell{
97254885Sdumbbell	if (tiling_flags & RADEON_TILING_MACRO)
98254885Sdumbbell		return ARRAY_2D_TILED_THIN1;
99254885Sdumbbell	else if (tiling_flags & RADEON_TILING_MICRO)
100254885Sdumbbell		return ARRAY_1D_TILED_THIN1;
101254885Sdumbbell	else
102254885Sdumbbell		return ARRAY_LINEAR_GENERAL;
103254885Sdumbbell}
104254885Sdumbbell
105254885Sdumbbellstatic u32 evergreen_cs_get_num_banks(u32 nbanks)
106254885Sdumbbell{
107254885Sdumbbell	switch (nbanks) {
108254885Sdumbbell	case 2:
109254885Sdumbbell		return ADDR_SURF_2_BANK;
110254885Sdumbbell	case 4:
111254885Sdumbbell		return ADDR_SURF_4_BANK;
112254885Sdumbbell	case 8:
113254885Sdumbbell	default:
114254885Sdumbbell		return ADDR_SURF_8_BANK;
115254885Sdumbbell	case 16:
116254885Sdumbbell		return ADDR_SURF_16_BANK;
117254885Sdumbbell	}
118254885Sdumbbell}
119254885Sdumbbell
120254885Sdumbbellstatic void evergreen_cs_track_init(struct evergreen_cs_track *track)
121254885Sdumbbell{
122254885Sdumbbell	int i;
123254885Sdumbbell
124254885Sdumbbell	for (i = 0; i < 8; i++) {
125254885Sdumbbell		track->cb_color_fmask_bo[i] = NULL;
126254885Sdumbbell		track->cb_color_cmask_bo[i] = NULL;
127254885Sdumbbell		track->cb_color_cmask_slice[i] = 0;
128254885Sdumbbell		track->cb_color_fmask_slice[i] = 0;
129254885Sdumbbell	}
130254885Sdumbbell
131254885Sdumbbell	for (i = 0; i < 12; i++) {
132254885Sdumbbell		track->cb_color_bo[i] = NULL;
133254885Sdumbbell		track->cb_color_bo_offset[i] = 0xFFFFFFFF;
134254885Sdumbbell		track->cb_color_info[i] = 0;
135254885Sdumbbell		track->cb_color_view[i] = 0xFFFFFFFF;
136254885Sdumbbell		track->cb_color_pitch[i] = 0;
137254885Sdumbbell		track->cb_color_slice[i] = 0xfffffff;
138254885Sdumbbell		track->cb_color_slice_idx[i] = 0;
139254885Sdumbbell	}
140254885Sdumbbell	track->cb_target_mask = 0xFFFFFFFF;
141254885Sdumbbell	track->cb_shader_mask = 0xFFFFFFFF;
142254885Sdumbbell	track->cb_dirty = true;
143254885Sdumbbell
144254885Sdumbbell	track->db_depth_slice = 0xffffffff;
145254885Sdumbbell	track->db_depth_view = 0xFFFFC000;
146254885Sdumbbell	track->db_depth_size = 0xFFFFFFFF;
147254885Sdumbbell	track->db_depth_control = 0xFFFFFFFF;
148254885Sdumbbell	track->db_z_info = 0xFFFFFFFF;
149254885Sdumbbell	track->db_z_read_offset = 0xFFFFFFFF;
150254885Sdumbbell	track->db_z_write_offset = 0xFFFFFFFF;
151254885Sdumbbell	track->db_z_read_bo = NULL;
152254885Sdumbbell	track->db_z_write_bo = NULL;
153254885Sdumbbell	track->db_s_info = 0xFFFFFFFF;
154254885Sdumbbell	track->db_s_read_offset = 0xFFFFFFFF;
155254885Sdumbbell	track->db_s_write_offset = 0xFFFFFFFF;
156254885Sdumbbell	track->db_s_read_bo = NULL;
157254885Sdumbbell	track->db_s_write_bo = NULL;
158254885Sdumbbell	track->db_dirty = true;
159254885Sdumbbell	track->htile_bo = NULL;
160254885Sdumbbell	track->htile_offset = 0xFFFFFFFF;
161254885Sdumbbell	track->htile_surface = 0;
162254885Sdumbbell
163254885Sdumbbell	for (i = 0; i < 4; i++) {
164254885Sdumbbell		track->vgt_strmout_size[i] = 0;
165254885Sdumbbell		track->vgt_strmout_bo[i] = NULL;
166254885Sdumbbell		track->vgt_strmout_bo_offset[i] = 0xFFFFFFFF;
167254885Sdumbbell	}
168254885Sdumbbell	track->streamout_dirty = true;
169254885Sdumbbell	track->sx_misc_kill_all_prims = false;
170254885Sdumbbell}
171254885Sdumbbell
172254885Sdumbbellstruct eg_surface {
173254885Sdumbbell	/* value gathered from cs */
174254885Sdumbbell	unsigned	nbx;
175254885Sdumbbell	unsigned	nby;
176254885Sdumbbell	unsigned	format;
177254885Sdumbbell	unsigned	mode;
178254885Sdumbbell	unsigned	nbanks;
179254885Sdumbbell	unsigned	bankw;
180254885Sdumbbell	unsigned	bankh;
181254885Sdumbbell	unsigned	tsplit;
182254885Sdumbbell	unsigned	mtilea;
183254885Sdumbbell	unsigned	nsamples;
184254885Sdumbbell	/* output value */
185254885Sdumbbell	unsigned	bpe;
186254885Sdumbbell	unsigned	layer_size;
187254885Sdumbbell	unsigned	palign;
188254885Sdumbbell	unsigned	halign;
189254885Sdumbbell	unsigned long	base_align;
190254885Sdumbbell};
191254885Sdumbbell
192254885Sdumbbellstatic int evergreen_surface_check_linear(struct radeon_cs_parser *p,
193254885Sdumbbell					  struct eg_surface *surf,
194254885Sdumbbell					  const char *prefix)
195254885Sdumbbell{
196254885Sdumbbell	surf->layer_size = surf->nbx * surf->nby * surf->bpe * surf->nsamples;
197254885Sdumbbell	surf->base_align = surf->bpe;
198254885Sdumbbell	surf->palign = 1;
199254885Sdumbbell	surf->halign = 1;
200254885Sdumbbell	return 0;
201254885Sdumbbell}
202254885Sdumbbell
203254885Sdumbbellstatic int evergreen_surface_check_linear_aligned(struct radeon_cs_parser *p,
204254885Sdumbbell						  struct eg_surface *surf,
205254885Sdumbbell						  const char *prefix)
206254885Sdumbbell{
207254885Sdumbbell	struct evergreen_cs_track *track = p->track;
208254885Sdumbbell	unsigned palign;
209254885Sdumbbell
210254885Sdumbbell	palign = MAX(64, track->group_size / surf->bpe);
211254885Sdumbbell	surf->layer_size = surf->nbx * surf->nby * surf->bpe * surf->nsamples;
212254885Sdumbbell	surf->base_align = track->group_size;
213254885Sdumbbell	surf->palign = palign;
214254885Sdumbbell	surf->halign = 1;
215254885Sdumbbell	if (surf->nbx & (palign - 1)) {
216254885Sdumbbell		if (prefix) {
217254885Sdumbbell			dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d\n",
218254885Sdumbbell				 __func__, __LINE__, prefix, surf->nbx, palign);
219254885Sdumbbell		}
220254885Sdumbbell		return -EINVAL;
221254885Sdumbbell	}
222254885Sdumbbell	return 0;
223254885Sdumbbell}
224254885Sdumbbell
225254885Sdumbbellstatic int evergreen_surface_check_1d(struct radeon_cs_parser *p,
226254885Sdumbbell				      struct eg_surface *surf,
227254885Sdumbbell				      const char *prefix)
228254885Sdumbbell{
229254885Sdumbbell	struct evergreen_cs_track *track = p->track;
230254885Sdumbbell	unsigned palign;
231254885Sdumbbell
232254885Sdumbbell	palign = track->group_size / (8 * surf->bpe * surf->nsamples);
233254885Sdumbbell	palign = MAX(8, palign);
234254885Sdumbbell	surf->layer_size = surf->nbx * surf->nby * surf->bpe;
235254885Sdumbbell	surf->base_align = track->group_size;
236254885Sdumbbell	surf->palign = palign;
237254885Sdumbbell	surf->halign = 8;
238254885Sdumbbell	if ((surf->nbx & (palign - 1))) {
239254885Sdumbbell		if (prefix) {
240254885Sdumbbell			dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d (%d %d %d)\n",
241254885Sdumbbell				 __func__, __LINE__, prefix, surf->nbx, palign,
242254885Sdumbbell				 track->group_size, surf->bpe, surf->nsamples);
243254885Sdumbbell		}
244254885Sdumbbell		return -EINVAL;
245254885Sdumbbell	}
246254885Sdumbbell	if ((surf->nby & (8 - 1))) {
247254885Sdumbbell		if (prefix) {
248254885Sdumbbell			dev_warn(p->dev, "%s:%d %s height %d invalid must be aligned with 8\n",
249254885Sdumbbell				 __func__, __LINE__, prefix, surf->nby);
250254885Sdumbbell		}
251254885Sdumbbell		return -EINVAL;
252254885Sdumbbell	}
253254885Sdumbbell	return 0;
254254885Sdumbbell}
255254885Sdumbbell
256254885Sdumbbellstatic int evergreen_surface_check_2d(struct radeon_cs_parser *p,
257254885Sdumbbell				      struct eg_surface *surf,
258254885Sdumbbell				      const char *prefix)
259254885Sdumbbell{
260254885Sdumbbell	struct evergreen_cs_track *track = p->track;
261254885Sdumbbell	unsigned palign, halign, tileb, slice_pt;
262254885Sdumbbell	unsigned mtile_pr, mtile_ps, mtileb;
263254885Sdumbbell
264254885Sdumbbell	tileb = 64 * surf->bpe * surf->nsamples;
265254885Sdumbbell	slice_pt = 1;
266254885Sdumbbell	if (tileb > surf->tsplit) {
267254885Sdumbbell		slice_pt = tileb / surf->tsplit;
268254885Sdumbbell	}
269254885Sdumbbell	tileb = tileb / slice_pt;
270254885Sdumbbell	/* macro tile width & height */
271254885Sdumbbell	palign = (8 * surf->bankw * track->npipes) * surf->mtilea;
272254885Sdumbbell	halign = (8 * surf->bankh * surf->nbanks) / surf->mtilea;
273254885Sdumbbell	mtileb = (palign / 8) * (halign / 8) * tileb;
274254885Sdumbbell	mtile_pr = surf->nbx / palign;
275254885Sdumbbell	mtile_ps = (mtile_pr * surf->nby) / halign;
276254885Sdumbbell	surf->layer_size = mtile_ps * mtileb * slice_pt;
277254885Sdumbbell	surf->base_align = (palign / 8) * (halign / 8) * tileb;
278254885Sdumbbell	surf->palign = palign;
279254885Sdumbbell	surf->halign = halign;
280254885Sdumbbell
281254885Sdumbbell	if ((surf->nbx & (palign - 1))) {
282254885Sdumbbell		if (prefix) {
283254885Sdumbbell			dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d\n",
284254885Sdumbbell				 __func__, __LINE__, prefix, surf->nbx, palign);
285254885Sdumbbell		}
286254885Sdumbbell		return -EINVAL;
287254885Sdumbbell	}
288254885Sdumbbell	if ((surf->nby & (halign - 1))) {
289254885Sdumbbell		if (prefix) {
290254885Sdumbbell			dev_warn(p->dev, "%s:%d %s height %d invalid must be aligned with %d\n",
291254885Sdumbbell				 __func__, __LINE__, prefix, surf->nby, halign);
292254885Sdumbbell		}
293254885Sdumbbell		return -EINVAL;
294254885Sdumbbell	}
295254885Sdumbbell
296254885Sdumbbell	return 0;
297254885Sdumbbell}
298254885Sdumbbell
299254885Sdumbbellstatic int evergreen_surface_check(struct radeon_cs_parser *p,
300254885Sdumbbell				   struct eg_surface *surf,
301254885Sdumbbell				   const char *prefix)
302254885Sdumbbell{
303254885Sdumbbell	/* some common value computed here */
304254885Sdumbbell	surf->bpe = r600_fmt_get_blocksize(surf->format);
305254885Sdumbbell
306254885Sdumbbell	switch (surf->mode) {
307254885Sdumbbell	case ARRAY_LINEAR_GENERAL:
308254885Sdumbbell		return evergreen_surface_check_linear(p, surf, prefix);
309254885Sdumbbell	case ARRAY_LINEAR_ALIGNED:
310254885Sdumbbell		return evergreen_surface_check_linear_aligned(p, surf, prefix);
311254885Sdumbbell	case ARRAY_1D_TILED_THIN1:
312254885Sdumbbell		return evergreen_surface_check_1d(p, surf, prefix);
313254885Sdumbbell	case ARRAY_2D_TILED_THIN1:
314254885Sdumbbell		return evergreen_surface_check_2d(p, surf, prefix);
315254885Sdumbbell	default:
316254885Sdumbbell		dev_warn(p->dev, "%s:%d %s invalid array mode %d\n",
317254885Sdumbbell				__func__, __LINE__, prefix, surf->mode);
318254885Sdumbbell		return -EINVAL;
319254885Sdumbbell	}
320254885Sdumbbell	return -EINVAL;
321254885Sdumbbell}
322254885Sdumbbell
323254885Sdumbbellstatic int evergreen_surface_value_conv_check(struct radeon_cs_parser *p,
324254885Sdumbbell					      struct eg_surface *surf,
325254885Sdumbbell					      const char *prefix)
326254885Sdumbbell{
327254885Sdumbbell	switch (surf->mode) {
328254885Sdumbbell	case ARRAY_2D_TILED_THIN1:
329254885Sdumbbell		break;
330254885Sdumbbell	case ARRAY_LINEAR_GENERAL:
331254885Sdumbbell	case ARRAY_LINEAR_ALIGNED:
332254885Sdumbbell	case ARRAY_1D_TILED_THIN1:
333254885Sdumbbell		return 0;
334254885Sdumbbell	default:
335254885Sdumbbell		dev_warn(p->dev, "%s:%d %s invalid array mode %d\n",
336254885Sdumbbell				__func__, __LINE__, prefix, surf->mode);
337254885Sdumbbell		return -EINVAL;
338254885Sdumbbell	}
339254885Sdumbbell
340254885Sdumbbell	switch (surf->nbanks) {
341254885Sdumbbell	case 0: surf->nbanks = 2; break;
342254885Sdumbbell	case 1: surf->nbanks = 4; break;
343254885Sdumbbell	case 2: surf->nbanks = 8; break;
344254885Sdumbbell	case 3: surf->nbanks = 16; break;
345254885Sdumbbell	default:
346254885Sdumbbell		dev_warn(p->dev, "%s:%d %s invalid number of banks %d\n",
347254885Sdumbbell			 __func__, __LINE__, prefix, surf->nbanks);
348254885Sdumbbell		return -EINVAL;
349254885Sdumbbell	}
350254885Sdumbbell	switch (surf->bankw) {
351254885Sdumbbell	case 0: surf->bankw = 1; break;
352254885Sdumbbell	case 1: surf->bankw = 2; break;
353254885Sdumbbell	case 2: surf->bankw = 4; break;
354254885Sdumbbell	case 3: surf->bankw = 8; break;
355254885Sdumbbell	default:
356254885Sdumbbell		dev_warn(p->dev, "%s:%d %s invalid bankw %d\n",
357254885Sdumbbell			 __func__, __LINE__, prefix, surf->bankw);
358254885Sdumbbell		return -EINVAL;
359254885Sdumbbell	}
360254885Sdumbbell	switch (surf->bankh) {
361254885Sdumbbell	case 0: surf->bankh = 1; break;
362254885Sdumbbell	case 1: surf->bankh = 2; break;
363254885Sdumbbell	case 2: surf->bankh = 4; break;
364254885Sdumbbell	case 3: surf->bankh = 8; break;
365254885Sdumbbell	default:
366254885Sdumbbell		dev_warn(p->dev, "%s:%d %s invalid bankh %d\n",
367254885Sdumbbell			 __func__, __LINE__, prefix, surf->bankh);
368254885Sdumbbell		return -EINVAL;
369254885Sdumbbell	}
370254885Sdumbbell	switch (surf->mtilea) {
371254885Sdumbbell	case 0: surf->mtilea = 1; break;
372254885Sdumbbell	case 1: surf->mtilea = 2; break;
373254885Sdumbbell	case 2: surf->mtilea = 4; break;
374254885Sdumbbell	case 3: surf->mtilea = 8; break;
375254885Sdumbbell	default:
376254885Sdumbbell		dev_warn(p->dev, "%s:%d %s invalid macro tile aspect %d\n",
377254885Sdumbbell			 __func__, __LINE__, prefix, surf->mtilea);
378254885Sdumbbell		return -EINVAL;
379254885Sdumbbell	}
380254885Sdumbbell	switch (surf->tsplit) {
381254885Sdumbbell	case 0: surf->tsplit = 64; break;
382254885Sdumbbell	case 1: surf->tsplit = 128; break;
383254885Sdumbbell	case 2: surf->tsplit = 256; break;
384254885Sdumbbell	case 3: surf->tsplit = 512; break;
385254885Sdumbbell	case 4: surf->tsplit = 1024; break;
386254885Sdumbbell	case 5: surf->tsplit = 2048; break;
387254885Sdumbbell	case 6: surf->tsplit = 4096; break;
388254885Sdumbbell	default:
389254885Sdumbbell		dev_warn(p->dev, "%s:%d %s invalid tile split %d\n",
390254885Sdumbbell			 __func__, __LINE__, prefix, surf->tsplit);
391254885Sdumbbell		return -EINVAL;
392254885Sdumbbell	}
393254885Sdumbbell	return 0;
394254885Sdumbbell}
395254885Sdumbbell
396254885Sdumbbellstatic int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned id)
397254885Sdumbbell{
398254885Sdumbbell	struct evergreen_cs_track *track = p->track;
399254885Sdumbbell	struct eg_surface surf;
400254885Sdumbbell	unsigned pitch, slice, mslice;
401254885Sdumbbell	unsigned long offset;
402254885Sdumbbell	int r;
403254885Sdumbbell
404254885Sdumbbell	mslice = G_028C6C_SLICE_MAX(track->cb_color_view[id]) + 1;
405254885Sdumbbell	pitch = track->cb_color_pitch[id];
406254885Sdumbbell	slice = track->cb_color_slice[id];
407254885Sdumbbell	surf.nbx = (pitch + 1) * 8;
408254885Sdumbbell	surf.nby = ((slice + 1) * 64) / surf.nbx;
409254885Sdumbbell	surf.mode = G_028C70_ARRAY_MODE(track->cb_color_info[id]);
410254885Sdumbbell	surf.format = G_028C70_FORMAT(track->cb_color_info[id]);
411254885Sdumbbell	surf.tsplit = G_028C74_TILE_SPLIT(track->cb_color_attrib[id]);
412254885Sdumbbell	surf.nbanks = G_028C74_NUM_BANKS(track->cb_color_attrib[id]);
413254885Sdumbbell	surf.bankw = G_028C74_BANK_WIDTH(track->cb_color_attrib[id]);
414254885Sdumbbell	surf.bankh = G_028C74_BANK_HEIGHT(track->cb_color_attrib[id]);
415254885Sdumbbell	surf.mtilea = G_028C74_MACRO_TILE_ASPECT(track->cb_color_attrib[id]);
416254885Sdumbbell	surf.nsamples = 1;
417254885Sdumbbell
418254885Sdumbbell	if (!r600_fmt_is_valid_color(surf.format)) {
419254885Sdumbbell		dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08x)\n",
420254885Sdumbbell			 __func__, __LINE__, surf.format,
421254885Sdumbbell			id, track->cb_color_info[id]);
422254885Sdumbbell		return -EINVAL;
423254885Sdumbbell	}
424254885Sdumbbell
425254885Sdumbbell	r = evergreen_surface_value_conv_check(p, &surf, "cb");
426254885Sdumbbell	if (r) {
427254885Sdumbbell		return r;
428254885Sdumbbell	}
429254885Sdumbbell
430254885Sdumbbell	r = evergreen_surface_check(p, &surf, "cb");
431254885Sdumbbell	if (r) {
432254885Sdumbbell		dev_warn(p->dev, "%s:%d cb[%d] invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
433254885Sdumbbell			 __func__, __LINE__, id, track->cb_color_pitch[id],
434254885Sdumbbell			 track->cb_color_slice[id], track->cb_color_attrib[id],
435254885Sdumbbell			 track->cb_color_info[id]);
436254885Sdumbbell		return r;
437254885Sdumbbell	}
438254885Sdumbbell
439254885Sdumbbell	offset = track->cb_color_bo_offset[id] << 8;
440254885Sdumbbell	if (offset & (surf.base_align - 1)) {
441254885Sdumbbell		dev_warn(p->dev, "%s:%d cb[%d] bo base %ld not aligned with %ld\n",
442254885Sdumbbell			 __func__, __LINE__, id, offset, surf.base_align);
443254885Sdumbbell		return -EINVAL;
444254885Sdumbbell	}
445254885Sdumbbell
446254885Sdumbbell	offset += surf.layer_size * mslice;
447254885Sdumbbell	if (offset > radeon_bo_size(track->cb_color_bo[id])) {
448254885Sdumbbell		/* old ddx are broken they allocate bo with w*h*bpp but
449254885Sdumbbell		 * program slice with ALIGN(h, 8), catch this and patch
450254885Sdumbbell		 * command stream.
451254885Sdumbbell		 */
452254885Sdumbbell		if (!surf.mode) {
453254885Sdumbbell			volatile u32 *ib = p->ib.ptr;
454254885Sdumbbell			unsigned long tmp, nby, bsize, size, min = 0;
455254885Sdumbbell
456254885Sdumbbell			/* find the height the ddx wants */
457254885Sdumbbell			if (surf.nby > 8) {
458254885Sdumbbell				min = surf.nby - 8;
459254885Sdumbbell			}
460254885Sdumbbell			bsize = radeon_bo_size(track->cb_color_bo[id]);
461254885Sdumbbell			tmp = track->cb_color_bo_offset[id] << 8;
462254885Sdumbbell			for (nby = surf.nby; nby > min; nby--) {
463254885Sdumbbell				size = nby * surf.nbx * surf.bpe * surf.nsamples;
464254885Sdumbbell				if ((tmp + size * mslice) <= bsize) {
465254885Sdumbbell					break;
466254885Sdumbbell				}
467254885Sdumbbell			}
468254885Sdumbbell			if (nby > min) {
469254885Sdumbbell				surf.nby = nby;
470254885Sdumbbell				slice = ((nby * surf.nbx) / 64) - 1;
471254885Sdumbbell				if (!evergreen_surface_check(p, &surf, "cb")) {
472254885Sdumbbell					/* check if this one works */
473254885Sdumbbell					tmp += surf.layer_size * mslice;
474254885Sdumbbell					if (tmp <= bsize) {
475254885Sdumbbell						ib[track->cb_color_slice_idx[id]] = slice;
476254885Sdumbbell						goto old_ddx_ok;
477254885Sdumbbell					}
478254885Sdumbbell				}
479254885Sdumbbell			}
480254885Sdumbbell		}
481254885Sdumbbell		dev_warn(p->dev, "%s:%d cb[%d] bo too small (layer size %d, "
482254885Sdumbbell			 "offset %d, max layer %d, bo size %ld, slice %d)\n",
483254885Sdumbbell			 __func__, __LINE__, id, surf.layer_size,
484254885Sdumbbell			track->cb_color_bo_offset[id] << 8, mslice,
485254885Sdumbbell			radeon_bo_size(track->cb_color_bo[id]), slice);
486254885Sdumbbell		dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n",
487254885Sdumbbell			 __func__, __LINE__, surf.nbx, surf.nby,
488254885Sdumbbell			surf.mode, surf.bpe, surf.nsamples,
489254885Sdumbbell			surf.bankw, surf.bankh,
490254885Sdumbbell			surf.tsplit, surf.mtilea);
491254885Sdumbbell		return -EINVAL;
492254885Sdumbbell	}
493254885Sdumbbellold_ddx_ok:
494254885Sdumbbell
495254885Sdumbbell	return 0;
496254885Sdumbbell}
497254885Sdumbbell
498254885Sdumbbellstatic int evergreen_cs_track_validate_htile(struct radeon_cs_parser *p,
499254885Sdumbbell						unsigned nbx, unsigned nby)
500254885Sdumbbell{
501254885Sdumbbell	struct evergreen_cs_track *track = p->track;
502254885Sdumbbell	unsigned long size;
503254885Sdumbbell
504254885Sdumbbell	if (track->htile_bo == NULL) {
505254885Sdumbbell		dev_warn(p->dev, "%s:%d htile enabled without htile surface 0x%08x\n",
506254885Sdumbbell				__func__, __LINE__, track->db_z_info);
507254885Sdumbbell		return -EINVAL;
508254885Sdumbbell	}
509254885Sdumbbell
510254885Sdumbbell	if (G_028ABC_LINEAR(track->htile_surface)) {
511254885Sdumbbell		/* pitch must be 16 htiles aligned == 16 * 8 pixel aligned */
512254885Sdumbbell		nbx = roundup(nbx, 16 * 8);
513254885Sdumbbell		/* height is npipes htiles aligned == npipes * 8 pixel aligned */
514254885Sdumbbell		nby = roundup(nby, track->npipes * 8);
515254885Sdumbbell	} else {
516254885Sdumbbell		/* always assume 8x8 htile */
517254885Sdumbbell		/* align is htile align * 8, htile align vary according to
518254885Sdumbbell		 * number of pipe and tile width and nby
519254885Sdumbbell		 */
520254885Sdumbbell		switch (track->npipes) {
521254885Sdumbbell		case 8:
522254885Sdumbbell			/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
523254885Sdumbbell			nbx = roundup(nbx, 64 * 8);
524254885Sdumbbell			nby = roundup(nby, 64 * 8);
525254885Sdumbbell			break;
526254885Sdumbbell		case 4:
527254885Sdumbbell			/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
528254885Sdumbbell			nbx = roundup(nbx, 64 * 8);
529254885Sdumbbell			nby = roundup(nby, 32 * 8);
530254885Sdumbbell			break;
531254885Sdumbbell		case 2:
532254885Sdumbbell			/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
533254885Sdumbbell			nbx = roundup(nbx, 32 * 8);
534254885Sdumbbell			nby = roundup(nby, 32 * 8);
535254885Sdumbbell			break;
536254885Sdumbbell		case 1:
537254885Sdumbbell			/* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
538254885Sdumbbell			nbx = roundup(nbx, 32 * 8);
539254885Sdumbbell			nby = roundup(nby, 16 * 8);
540254885Sdumbbell			break;
541254885Sdumbbell		default:
542254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid num pipes %d\n",
543254885Sdumbbell					__func__, __LINE__, track->npipes);
544254885Sdumbbell			return -EINVAL;
545254885Sdumbbell		}
546254885Sdumbbell	}
547254885Sdumbbell	/* compute number of htile */
548254885Sdumbbell	nbx = nbx >> 3;
549254885Sdumbbell	nby = nby >> 3;
550254885Sdumbbell	/* size must be aligned on npipes * 2K boundary */
551254885Sdumbbell	size = roundup(nbx * nby * 4, track->npipes * (2 << 10));
552254885Sdumbbell	size += track->htile_offset;
553254885Sdumbbell
554254885Sdumbbell	if (size > radeon_bo_size(track->htile_bo)) {
555254885Sdumbbell		dev_warn(p->dev, "%s:%d htile surface too small %ld for %ld (%d %d)\n",
556254885Sdumbbell				__func__, __LINE__, radeon_bo_size(track->htile_bo),
557254885Sdumbbell				size, nbx, nby);
558254885Sdumbbell		return -EINVAL;
559254885Sdumbbell	}
560254885Sdumbbell	return 0;
561254885Sdumbbell}
562254885Sdumbbell
563254885Sdumbbellstatic int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p)
564254885Sdumbbell{
565254885Sdumbbell	struct evergreen_cs_track *track = p->track;
566254885Sdumbbell	struct eg_surface surf;
567254885Sdumbbell	unsigned pitch, slice, mslice;
568254885Sdumbbell	unsigned long offset;
569254885Sdumbbell	int r;
570254885Sdumbbell
571254885Sdumbbell	mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1;
572254885Sdumbbell	pitch = G_028058_PITCH_TILE_MAX(track->db_depth_size);
573254885Sdumbbell	slice = track->db_depth_slice;
574254885Sdumbbell	surf.nbx = (pitch + 1) * 8;
575254885Sdumbbell	surf.nby = ((slice + 1) * 64) / surf.nbx;
576254885Sdumbbell	surf.mode = G_028040_ARRAY_MODE(track->db_z_info);
577254885Sdumbbell	surf.format = G_028044_FORMAT(track->db_s_info);
578254885Sdumbbell	surf.tsplit = G_028044_TILE_SPLIT(track->db_s_info);
579254885Sdumbbell	surf.nbanks = G_028040_NUM_BANKS(track->db_z_info);
580254885Sdumbbell	surf.bankw = G_028040_BANK_WIDTH(track->db_z_info);
581254885Sdumbbell	surf.bankh = G_028040_BANK_HEIGHT(track->db_z_info);
582254885Sdumbbell	surf.mtilea = G_028040_MACRO_TILE_ASPECT(track->db_z_info);
583254885Sdumbbell	surf.nsamples = 1;
584254885Sdumbbell
585254885Sdumbbell	if (surf.format != 1) {
586254885Sdumbbell		dev_warn(p->dev, "%s:%d stencil invalid format %d\n",
587254885Sdumbbell			 __func__, __LINE__, surf.format);
588254885Sdumbbell		return -EINVAL;
589254885Sdumbbell	}
590254885Sdumbbell	/* replace by color format so we can use same code */
591254885Sdumbbell	surf.format = V_028C70_COLOR_8;
592254885Sdumbbell
593254885Sdumbbell	r = evergreen_surface_value_conv_check(p, &surf, "stencil");
594254885Sdumbbell	if (r) {
595254885Sdumbbell		return r;
596254885Sdumbbell	}
597254885Sdumbbell
598254885Sdumbbell	r = evergreen_surface_check(p, &surf, NULL);
599254885Sdumbbell	if (r) {
600254885Sdumbbell		/* old userspace doesn't compute proper depth/stencil alignment
601254885Sdumbbell		 * check that alignment against a bigger byte per elements and
602254885Sdumbbell		 * only report if that alignment is wrong too.
603254885Sdumbbell		 */
604254885Sdumbbell		surf.format = V_028C70_COLOR_8_8_8_8;
605254885Sdumbbell		r = evergreen_surface_check(p, &surf, "stencil");
606254885Sdumbbell		if (r) {
607254885Sdumbbell			dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
608254885Sdumbbell				 __func__, __LINE__, track->db_depth_size,
609254885Sdumbbell				 track->db_depth_slice, track->db_s_info, track->db_z_info);
610254885Sdumbbell		}
611254885Sdumbbell		return r;
612254885Sdumbbell	}
613254885Sdumbbell
614254885Sdumbbell	offset = track->db_s_read_offset << 8;
615254885Sdumbbell	if (offset & (surf.base_align - 1)) {
616254885Sdumbbell		dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n",
617254885Sdumbbell			 __func__, __LINE__, offset, surf.base_align);
618254885Sdumbbell		return -EINVAL;
619254885Sdumbbell	}
620254885Sdumbbell	offset += surf.layer_size * mslice;
621254885Sdumbbell	if (offset > radeon_bo_size(track->db_s_read_bo)) {
622254885Sdumbbell		dev_warn(p->dev, "%s:%d stencil read bo too small (layer size %d, "
623254885Sdumbbell			 "offset %ld, max layer %d, bo size %ld)\n",
624254885Sdumbbell			 __func__, __LINE__, surf.layer_size,
625254885Sdumbbell			(unsigned long)track->db_s_read_offset << 8, mslice,
626254885Sdumbbell			radeon_bo_size(track->db_s_read_bo));
627254885Sdumbbell		dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
628254885Sdumbbell			 __func__, __LINE__, track->db_depth_size,
629254885Sdumbbell			 track->db_depth_slice, track->db_s_info, track->db_z_info);
630254885Sdumbbell		return -EINVAL;
631254885Sdumbbell	}
632254885Sdumbbell
633254885Sdumbbell	offset = track->db_s_write_offset << 8;
634254885Sdumbbell	if (offset & (surf.base_align - 1)) {
635254885Sdumbbell		dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n",
636254885Sdumbbell			 __func__, __LINE__, offset, surf.base_align);
637254885Sdumbbell		return -EINVAL;
638254885Sdumbbell	}
639254885Sdumbbell	offset += surf.layer_size * mslice;
640254885Sdumbbell	if (offset > radeon_bo_size(track->db_s_write_bo)) {
641254885Sdumbbell		dev_warn(p->dev, "%s:%d stencil write bo too small (layer size %d, "
642254885Sdumbbell			 "offset %ld, max layer %d, bo size %ld)\n",
643254885Sdumbbell			 __func__, __LINE__, surf.layer_size,
644254885Sdumbbell			(unsigned long)track->db_s_write_offset << 8, mslice,
645254885Sdumbbell			radeon_bo_size(track->db_s_write_bo));
646254885Sdumbbell		return -EINVAL;
647254885Sdumbbell	}
648254885Sdumbbell
649254885Sdumbbell	/* hyperz */
650254885Sdumbbell	if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) {
651254885Sdumbbell		r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby);
652254885Sdumbbell		if (r) {
653254885Sdumbbell			return r;
654254885Sdumbbell		}
655254885Sdumbbell	}
656254885Sdumbbell
657254885Sdumbbell	return 0;
658254885Sdumbbell}
659254885Sdumbbell
660254885Sdumbbellstatic int evergreen_cs_track_validate_depth(struct radeon_cs_parser *p)
661254885Sdumbbell{
662254885Sdumbbell	struct evergreen_cs_track *track = p->track;
663254885Sdumbbell	struct eg_surface surf;
664254885Sdumbbell	unsigned pitch, slice, mslice;
665254885Sdumbbell	unsigned long offset;
666254885Sdumbbell	int r;
667254885Sdumbbell
668254885Sdumbbell	mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1;
669254885Sdumbbell	pitch = G_028058_PITCH_TILE_MAX(track->db_depth_size);
670254885Sdumbbell	slice = track->db_depth_slice;
671254885Sdumbbell	surf.nbx = (pitch + 1) * 8;
672254885Sdumbbell	surf.nby = ((slice + 1) * 64) / surf.nbx;
673254885Sdumbbell	surf.mode = G_028040_ARRAY_MODE(track->db_z_info);
674254885Sdumbbell	surf.format = G_028040_FORMAT(track->db_z_info);
675254885Sdumbbell	surf.tsplit = G_028040_TILE_SPLIT(track->db_z_info);
676254885Sdumbbell	surf.nbanks = G_028040_NUM_BANKS(track->db_z_info);
677254885Sdumbbell	surf.bankw = G_028040_BANK_WIDTH(track->db_z_info);
678254885Sdumbbell	surf.bankh = G_028040_BANK_HEIGHT(track->db_z_info);
679254885Sdumbbell	surf.mtilea = G_028040_MACRO_TILE_ASPECT(track->db_z_info);
680254885Sdumbbell	surf.nsamples = 1;
681254885Sdumbbell
682254885Sdumbbell	switch (surf.format) {
683254885Sdumbbell	case V_028040_Z_16:
684254885Sdumbbell		surf.format = V_028C70_COLOR_16;
685254885Sdumbbell		break;
686254885Sdumbbell	case V_028040_Z_24:
687254885Sdumbbell	case V_028040_Z_32_FLOAT:
688254885Sdumbbell		surf.format = V_028C70_COLOR_8_8_8_8;
689254885Sdumbbell		break;
690254885Sdumbbell	default:
691254885Sdumbbell		dev_warn(p->dev, "%s:%d depth invalid format %d\n",
692254885Sdumbbell			 __func__, __LINE__, surf.format);
693254885Sdumbbell		return -EINVAL;
694254885Sdumbbell	}
695254885Sdumbbell
696254885Sdumbbell	r = evergreen_surface_value_conv_check(p, &surf, "depth");
697254885Sdumbbell	if (r) {
698254885Sdumbbell		dev_warn(p->dev, "%s:%d depth invalid (0x%08x 0x%08x 0x%08x)\n",
699254885Sdumbbell			 __func__, __LINE__, track->db_depth_size,
700254885Sdumbbell			 track->db_depth_slice, track->db_z_info);
701254885Sdumbbell		return r;
702254885Sdumbbell	}
703254885Sdumbbell
704254885Sdumbbell	r = evergreen_surface_check(p, &surf, "depth");
705254885Sdumbbell	if (r) {
706254885Sdumbbell		dev_warn(p->dev, "%s:%d depth invalid (0x%08x 0x%08x 0x%08x)\n",
707254885Sdumbbell			 __func__, __LINE__, track->db_depth_size,
708254885Sdumbbell			 track->db_depth_slice, track->db_z_info);
709254885Sdumbbell		return r;
710254885Sdumbbell	}
711254885Sdumbbell
712254885Sdumbbell	offset = track->db_z_read_offset << 8;
713254885Sdumbbell	if (offset & (surf.base_align - 1)) {
714254885Sdumbbell		dev_warn(p->dev, "%s:%d stencil read bo base %ld not aligned with %ld\n",
715254885Sdumbbell			 __func__, __LINE__, offset, surf.base_align);
716254885Sdumbbell		return -EINVAL;
717254885Sdumbbell	}
718254885Sdumbbell	offset += surf.layer_size * mslice;
719254885Sdumbbell	if (offset > radeon_bo_size(track->db_z_read_bo)) {
720254885Sdumbbell		dev_warn(p->dev, "%s:%d depth read bo too small (layer size %d, "
721254885Sdumbbell			 "offset %ld, max layer %d, bo size %ld)\n",
722254885Sdumbbell			 __func__, __LINE__, surf.layer_size,
723254885Sdumbbell			(unsigned long)track->db_z_read_offset << 8, mslice,
724254885Sdumbbell			radeon_bo_size(track->db_z_read_bo));
725254885Sdumbbell		return -EINVAL;
726254885Sdumbbell	}
727254885Sdumbbell
728254885Sdumbbell	offset = track->db_z_write_offset << 8;
729254885Sdumbbell	if (offset & (surf.base_align - 1)) {
730254885Sdumbbell		dev_warn(p->dev, "%s:%d stencil write bo base %ld not aligned with %ld\n",
731254885Sdumbbell			 __func__, __LINE__, offset, surf.base_align);
732254885Sdumbbell		return -EINVAL;
733254885Sdumbbell	}
734254885Sdumbbell	offset += surf.layer_size * mslice;
735254885Sdumbbell	if (offset > radeon_bo_size(track->db_z_write_bo)) {
736254885Sdumbbell		dev_warn(p->dev, "%s:%d depth write bo too small (layer size %d, "
737254885Sdumbbell			 "offset %ld, max layer %d, bo size %ld)\n",
738254885Sdumbbell			 __func__, __LINE__, surf.layer_size,
739254885Sdumbbell			(unsigned long)track->db_z_write_offset << 8, mslice,
740254885Sdumbbell			radeon_bo_size(track->db_z_write_bo));
741254885Sdumbbell		return -EINVAL;
742254885Sdumbbell	}
743254885Sdumbbell
744254885Sdumbbell	/* hyperz */
745254885Sdumbbell	if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) {
746254885Sdumbbell		r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby);
747254885Sdumbbell		if (r) {
748254885Sdumbbell			return r;
749254885Sdumbbell		}
750254885Sdumbbell	}
751254885Sdumbbell
752254885Sdumbbell	return 0;
753254885Sdumbbell}
754254885Sdumbbell
755254885Sdumbbellstatic int evergreen_cs_track_validate_texture(struct radeon_cs_parser *p,
756254885Sdumbbell					       struct radeon_bo *texture,
757254885Sdumbbell					       struct radeon_bo *mipmap,
758254885Sdumbbell					       unsigned idx)
759254885Sdumbbell{
760254885Sdumbbell	struct eg_surface surf;
761254885Sdumbbell	unsigned long toffset, moffset;
762254885Sdumbbell	unsigned dim, llevel, mslice, width, height, depth, i;
763254885Sdumbbell	u32 texdw[8];
764254885Sdumbbell	int r;
765254885Sdumbbell
766254885Sdumbbell	texdw[0] = radeon_get_ib_value(p, idx + 0);
767254885Sdumbbell	texdw[1] = radeon_get_ib_value(p, idx + 1);
768254885Sdumbbell	texdw[2] = radeon_get_ib_value(p, idx + 2);
769254885Sdumbbell	texdw[3] = radeon_get_ib_value(p, idx + 3);
770254885Sdumbbell	texdw[4] = radeon_get_ib_value(p, idx + 4);
771254885Sdumbbell	texdw[5] = radeon_get_ib_value(p, idx + 5);
772254885Sdumbbell	texdw[6] = radeon_get_ib_value(p, idx + 6);
773254885Sdumbbell	texdw[7] = radeon_get_ib_value(p, idx + 7);
774254885Sdumbbell	dim = G_030000_DIM(texdw[0]);
775254885Sdumbbell	llevel = G_030014_LAST_LEVEL(texdw[5]);
776254885Sdumbbell	mslice = G_030014_LAST_ARRAY(texdw[5]) + 1;
777254885Sdumbbell	width = G_030000_TEX_WIDTH(texdw[0]) + 1;
778254885Sdumbbell	height =  G_030004_TEX_HEIGHT(texdw[1]) + 1;
779254885Sdumbbell	depth = G_030004_TEX_DEPTH(texdw[1]) + 1;
780254885Sdumbbell	surf.format = G_03001C_DATA_FORMAT(texdw[7]);
781254885Sdumbbell	surf.nbx = (G_030000_PITCH(texdw[0]) + 1) * 8;
782254885Sdumbbell	surf.nbx = r600_fmt_get_nblocksx(surf.format, surf.nbx);
783254885Sdumbbell	surf.nby = r600_fmt_get_nblocksy(surf.format, height);
784254885Sdumbbell	surf.mode = G_030004_ARRAY_MODE(texdw[1]);
785254885Sdumbbell	surf.tsplit = G_030018_TILE_SPLIT(texdw[6]);
786254885Sdumbbell	surf.nbanks = G_03001C_NUM_BANKS(texdw[7]);
787254885Sdumbbell	surf.bankw = G_03001C_BANK_WIDTH(texdw[7]);
788254885Sdumbbell	surf.bankh = G_03001C_BANK_HEIGHT(texdw[7]);
789254885Sdumbbell	surf.mtilea = G_03001C_MACRO_TILE_ASPECT(texdw[7]);
790254885Sdumbbell	surf.nsamples = 1;
791254885Sdumbbell	toffset = texdw[2] << 8;
792254885Sdumbbell	moffset = texdw[3] << 8;
793254885Sdumbbell
794254885Sdumbbell	if (!r600_fmt_is_valid_texture(surf.format, p->family)) {
795254885Sdumbbell		dev_warn(p->dev, "%s:%d texture invalid format %d\n",
796254885Sdumbbell			 __func__, __LINE__, surf.format);
797254885Sdumbbell		return -EINVAL;
798254885Sdumbbell	}
799254885Sdumbbell	switch (dim) {
800254885Sdumbbell	case V_030000_SQ_TEX_DIM_1D:
801254885Sdumbbell	case V_030000_SQ_TEX_DIM_2D:
802254885Sdumbbell	case V_030000_SQ_TEX_DIM_CUBEMAP:
803254885Sdumbbell	case V_030000_SQ_TEX_DIM_1D_ARRAY:
804254885Sdumbbell	case V_030000_SQ_TEX_DIM_2D_ARRAY:
805254885Sdumbbell		depth = 1;
806254885Sdumbbell		break;
807254885Sdumbbell	case V_030000_SQ_TEX_DIM_2D_MSAA:
808254885Sdumbbell	case V_030000_SQ_TEX_DIM_2D_ARRAY_MSAA:
809254885Sdumbbell		surf.nsamples = 1 << llevel;
810254885Sdumbbell		llevel = 0;
811254885Sdumbbell		depth = 1;
812254885Sdumbbell		break;
813254885Sdumbbell	case V_030000_SQ_TEX_DIM_3D:
814254885Sdumbbell		break;
815254885Sdumbbell	default:
816254885Sdumbbell		dev_warn(p->dev, "%s:%d texture invalid dimension %d\n",
817254885Sdumbbell			 __func__, __LINE__, dim);
818254885Sdumbbell		return -EINVAL;
819254885Sdumbbell	}
820254885Sdumbbell
821254885Sdumbbell	r = evergreen_surface_value_conv_check(p, &surf, "texture");
822254885Sdumbbell	if (r) {
823254885Sdumbbell		return r;
824254885Sdumbbell	}
825254885Sdumbbell
826254885Sdumbbell	/* align height */
827254885Sdumbbell	evergreen_surface_check(p, &surf, NULL);
828254885Sdumbbell	surf.nby = roundup(surf.nby, surf.halign);
829254885Sdumbbell
830254885Sdumbbell	r = evergreen_surface_check(p, &surf, "texture");
831254885Sdumbbell	if (r) {
832254885Sdumbbell		dev_warn(p->dev, "%s:%d texture invalid 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
833254885Sdumbbell			 __func__, __LINE__, texdw[0], texdw[1], texdw[4],
834254885Sdumbbell			 texdw[5], texdw[6], texdw[7]);
835254885Sdumbbell		return r;
836254885Sdumbbell	}
837254885Sdumbbell
838254885Sdumbbell	/* check texture size */
839254885Sdumbbell	if (toffset & (surf.base_align - 1)) {
840254885Sdumbbell		dev_warn(p->dev, "%s:%d texture bo base %ld not aligned with %ld\n",
841254885Sdumbbell			 __func__, __LINE__, toffset, surf.base_align);
842254885Sdumbbell		return -EINVAL;
843254885Sdumbbell	}
844254885Sdumbbell	if (moffset & (surf.base_align - 1)) {
845254885Sdumbbell		dev_warn(p->dev, "%s:%d mipmap bo base %ld not aligned with %ld\n",
846254885Sdumbbell			 __func__, __LINE__, moffset, surf.base_align);
847254885Sdumbbell		return -EINVAL;
848254885Sdumbbell	}
849254885Sdumbbell	if (dim == SQ_TEX_DIM_3D) {
850254885Sdumbbell		toffset += surf.layer_size * depth;
851254885Sdumbbell	} else {
852254885Sdumbbell		toffset += surf.layer_size * mslice;
853254885Sdumbbell	}
854254885Sdumbbell	if (toffset > radeon_bo_size(texture)) {
855254885Sdumbbell		dev_warn(p->dev, "%s:%d texture bo too small (layer size %d, "
856254885Sdumbbell			 "offset %ld, max layer %d, depth %d, bo size %ld) (%d %d)\n",
857254885Sdumbbell			 __func__, __LINE__, surf.layer_size,
858254885Sdumbbell			(unsigned long)texdw[2] << 8, mslice,
859254885Sdumbbell			depth, radeon_bo_size(texture),
860254885Sdumbbell			surf.nbx, surf.nby);
861254885Sdumbbell		return -EINVAL;
862254885Sdumbbell	}
863254885Sdumbbell
864254885Sdumbbell	if (!mipmap) {
865254885Sdumbbell		if (llevel) {
866254885Sdumbbell			dev_warn(p->dev, "%s:%i got NULL MIP_ADDRESS relocation\n",
867254885Sdumbbell				 __func__, __LINE__);
868254885Sdumbbell			return -EINVAL;
869254885Sdumbbell		} else {
870254885Sdumbbell			return 0; /* everything's ok */
871254885Sdumbbell		}
872254885Sdumbbell	}
873254885Sdumbbell
874254885Sdumbbell	/* check mipmap size */
875254885Sdumbbell	for (i = 1; i <= llevel; i++) {
876254885Sdumbbell		unsigned w, h, d;
877254885Sdumbbell
878254885Sdumbbell		w = r600_mip_minify(width, i);
879254885Sdumbbell		h = r600_mip_minify(height, i);
880254885Sdumbbell		d = r600_mip_minify(depth, i);
881254885Sdumbbell		surf.nbx = r600_fmt_get_nblocksx(surf.format, w);
882254885Sdumbbell		surf.nby = r600_fmt_get_nblocksy(surf.format, h);
883254885Sdumbbell
884254885Sdumbbell		switch (surf.mode) {
885254885Sdumbbell		case ARRAY_2D_TILED_THIN1:
886254885Sdumbbell			if (surf.nbx < surf.palign || surf.nby < surf.halign) {
887254885Sdumbbell				surf.mode = ARRAY_1D_TILED_THIN1;
888254885Sdumbbell			}
889254885Sdumbbell			/* recompute alignment */
890254885Sdumbbell			evergreen_surface_check(p, &surf, NULL);
891254885Sdumbbell			break;
892254885Sdumbbell		case ARRAY_LINEAR_GENERAL:
893254885Sdumbbell		case ARRAY_LINEAR_ALIGNED:
894254885Sdumbbell		case ARRAY_1D_TILED_THIN1:
895254885Sdumbbell			break;
896254885Sdumbbell		default:
897254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid array mode %d\n",
898254885Sdumbbell				 __func__, __LINE__, surf.mode);
899254885Sdumbbell			return -EINVAL;
900254885Sdumbbell		}
901254885Sdumbbell		surf.nbx = roundup(surf.nbx, surf.palign);
902254885Sdumbbell		surf.nby = roundup(surf.nby, surf.halign);
903254885Sdumbbell
904254885Sdumbbell		r = evergreen_surface_check(p, &surf, "mipmap");
905254885Sdumbbell		if (r) {
906254885Sdumbbell			return r;
907254885Sdumbbell		}
908254885Sdumbbell
909254885Sdumbbell		if (dim == SQ_TEX_DIM_3D) {
910254885Sdumbbell			moffset += surf.layer_size * d;
911254885Sdumbbell		} else {
912254885Sdumbbell			moffset += surf.layer_size * mslice;
913254885Sdumbbell		}
914254885Sdumbbell		if (moffset > radeon_bo_size(mipmap)) {
915254885Sdumbbell			dev_warn(p->dev, "%s:%d mipmap [%d] bo too small (layer size %d, "
916254885Sdumbbell					"offset %ld, coffset %ld, max layer %d, depth %d, "
917254885Sdumbbell					"bo size %ld) level0 (%d %d %d)\n",
918254885Sdumbbell					__func__, __LINE__, i, surf.layer_size,
919254885Sdumbbell					(unsigned long)texdw[3] << 8, moffset, mslice,
920254885Sdumbbell					d, radeon_bo_size(mipmap),
921254885Sdumbbell					width, height, depth);
922254885Sdumbbell			dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n",
923254885Sdumbbell				 __func__, __LINE__, surf.nbx, surf.nby,
924254885Sdumbbell				surf.mode, surf.bpe, surf.nsamples,
925254885Sdumbbell				surf.bankw, surf.bankh,
926254885Sdumbbell				surf.tsplit, surf.mtilea);
927254885Sdumbbell			return -EINVAL;
928254885Sdumbbell		}
929254885Sdumbbell	}
930254885Sdumbbell
931254885Sdumbbell	return 0;
932254885Sdumbbell}
933254885Sdumbbell
934254885Sdumbbellstatic int evergreen_cs_track_check(struct radeon_cs_parser *p)
935254885Sdumbbell{
936254885Sdumbbell	struct evergreen_cs_track *track = p->track;
937254885Sdumbbell	unsigned tmp, i;
938254885Sdumbbell	int r;
939254885Sdumbbell	unsigned buffer_mask = 0;
940254885Sdumbbell
941254885Sdumbbell	/* check streamout */
942254885Sdumbbell	if (track->streamout_dirty && track->vgt_strmout_config) {
943254885Sdumbbell		for (i = 0; i < 4; i++) {
944254885Sdumbbell			if (track->vgt_strmout_config & (1 << i)) {
945254885Sdumbbell				buffer_mask |= (track->vgt_strmout_buffer_config >> (i * 4)) & 0xf;
946254885Sdumbbell			}
947254885Sdumbbell		}
948254885Sdumbbell
949254885Sdumbbell		for (i = 0; i < 4; i++) {
950254885Sdumbbell			if (buffer_mask & (1 << i)) {
951254885Sdumbbell				if (track->vgt_strmout_bo[i]) {
952254885Sdumbbell					u64 offset = (u64)track->vgt_strmout_bo_offset[i] +
953254885Sdumbbell							(u64)track->vgt_strmout_size[i];
954254885Sdumbbell					if (offset > radeon_bo_size(track->vgt_strmout_bo[i])) {
955254885Sdumbbell						DRM_ERROR("streamout %d bo too small: 0x%jx, 0x%lx\n",
956254885Sdumbbell							  i, (uintmax_t)offset,
957254885Sdumbbell							  radeon_bo_size(track->vgt_strmout_bo[i]));
958254885Sdumbbell						return -EINVAL;
959254885Sdumbbell					}
960254885Sdumbbell				} else {
961254885Sdumbbell					dev_warn(p->dev, "No buffer for streamout %d\n", i);
962254885Sdumbbell					return -EINVAL;
963254885Sdumbbell				}
964254885Sdumbbell			}
965254885Sdumbbell		}
966254885Sdumbbell		track->streamout_dirty = false;
967254885Sdumbbell	}
968254885Sdumbbell
969254885Sdumbbell	if (track->sx_misc_kill_all_prims)
970254885Sdumbbell		return 0;
971254885Sdumbbell
972254885Sdumbbell	/* check that we have a cb for each enabled target
973254885Sdumbbell	 */
974254885Sdumbbell	if (track->cb_dirty) {
975254885Sdumbbell		tmp = track->cb_target_mask;
976254885Sdumbbell		for (i = 0; i < 8; i++) {
977254885Sdumbbell			if ((tmp >> (i * 4)) & 0xF) {
978254885Sdumbbell				/* at least one component is enabled */
979254885Sdumbbell				if (track->cb_color_bo[i] == NULL) {
980254885Sdumbbell					dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
981254885Sdumbbell						__func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i);
982254885Sdumbbell					return -EINVAL;
983254885Sdumbbell				}
984254885Sdumbbell				/* check cb */
985254885Sdumbbell				r = evergreen_cs_track_validate_cb(p, i);
986254885Sdumbbell				if (r) {
987254885Sdumbbell					return r;
988254885Sdumbbell				}
989254885Sdumbbell			}
990254885Sdumbbell		}
991254885Sdumbbell		track->cb_dirty = false;
992254885Sdumbbell	}
993254885Sdumbbell
994254885Sdumbbell	if (track->db_dirty) {
995254885Sdumbbell		/* Check stencil buffer */
996254885Sdumbbell		if (G_028044_FORMAT(track->db_s_info) != V_028044_STENCIL_INVALID &&
997254885Sdumbbell		    G_028800_STENCIL_ENABLE(track->db_depth_control)) {
998254885Sdumbbell			r = evergreen_cs_track_validate_stencil(p);
999254885Sdumbbell			if (r)
1000254885Sdumbbell				return r;
1001254885Sdumbbell		}
1002254885Sdumbbell		/* Check depth buffer */
1003254885Sdumbbell		if (G_028040_FORMAT(track->db_z_info) != V_028040_Z_INVALID &&
1004254885Sdumbbell		    G_028800_Z_ENABLE(track->db_depth_control)) {
1005254885Sdumbbell			r = evergreen_cs_track_validate_depth(p);
1006254885Sdumbbell			if (r)
1007254885Sdumbbell				return r;
1008254885Sdumbbell		}
1009254885Sdumbbell		track->db_dirty = false;
1010254885Sdumbbell	}
1011254885Sdumbbell
1012254885Sdumbbell	return 0;
1013254885Sdumbbell}
1014254885Sdumbbell
1015254885Sdumbbell/**
1016254885Sdumbbell * evergreen_cs_packet_parse() - parse cp packet and point ib index to next packet
1017254885Sdumbbell * @parser:	parser structure holding parsing context.
1018254885Sdumbbell * @pkt:	where to store packet informations
1019254885Sdumbbell *
1020254885Sdumbbell * Assume that chunk_ib_index is properly set. Will return -EINVAL
1021254885Sdumbbell * if packet is bigger than remaining ib size. or if packets is unknown.
1022254885Sdumbbell **/
1023254885Sdumbbellstatic int evergreen_cs_packet_parse(struct radeon_cs_parser *p,
1024254885Sdumbbell			      struct radeon_cs_packet *pkt,
1025254885Sdumbbell			      unsigned idx)
1026254885Sdumbbell{
1027254885Sdumbbell	struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx];
1028254885Sdumbbell	uint32_t header;
1029254885Sdumbbell
1030254885Sdumbbell	if (idx >= ib_chunk->length_dw) {
1031254885Sdumbbell		DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
1032254885Sdumbbell			  idx, ib_chunk->length_dw);
1033254885Sdumbbell		return -EINVAL;
1034254885Sdumbbell	}
1035254885Sdumbbell	header = radeon_get_ib_value(p, idx);
1036254885Sdumbbell	pkt->idx = idx;
1037254885Sdumbbell	pkt->type = CP_PACKET_GET_TYPE(header);
1038254885Sdumbbell	pkt->count = CP_PACKET_GET_COUNT(header);
1039254885Sdumbbell	pkt->one_reg_wr = 0;
1040254885Sdumbbell	switch (pkt->type) {
1041254885Sdumbbell	case PACKET_TYPE0:
1042254885Sdumbbell		pkt->reg = CP_PACKET0_GET_REG(header);
1043254885Sdumbbell		break;
1044254885Sdumbbell	case PACKET_TYPE3:
1045254885Sdumbbell		pkt->opcode = CP_PACKET3_GET_OPCODE(header);
1046254885Sdumbbell		break;
1047254885Sdumbbell	case PACKET_TYPE2:
1048254885Sdumbbell		pkt->count = -1;
1049254885Sdumbbell		break;
1050254885Sdumbbell	default:
1051254885Sdumbbell		DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx);
1052254885Sdumbbell		return -EINVAL;
1053254885Sdumbbell	}
1054254885Sdumbbell	if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) {
1055254885Sdumbbell		DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n",
1056254885Sdumbbell			  pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw);
1057254885Sdumbbell		return -EINVAL;
1058254885Sdumbbell	}
1059254885Sdumbbell	return 0;
1060254885Sdumbbell}
1061254885Sdumbbell
1062254885Sdumbbell/**
1063254885Sdumbbell * evergreen_cs_packet_next_reloc() - parse next packet which should be reloc packet3
1064254885Sdumbbell * @parser:		parser structure holding parsing context.
1065254885Sdumbbell * @data:		pointer to relocation data
1066254885Sdumbbell * @offset_start:	starting offset
1067254885Sdumbbell * @offset_mask:	offset mask (to align start offset on)
1068254885Sdumbbell * @reloc:		reloc informations
1069254885Sdumbbell *
1070254885Sdumbbell * Check next packet is relocation packet3, do bo validation and compute
1071254885Sdumbbell * GPU offset using the provided start.
1072254885Sdumbbell **/
1073254885Sdumbbellstatic int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p,
1074254885Sdumbbell					  struct radeon_cs_reloc **cs_reloc)
1075254885Sdumbbell{
1076254885Sdumbbell	struct radeon_cs_chunk *relocs_chunk;
1077254885Sdumbbell	struct radeon_cs_packet p3reloc;
1078254885Sdumbbell	unsigned idx;
1079254885Sdumbbell	int r;
1080254885Sdumbbell
1081254885Sdumbbell	if (p->chunk_relocs_idx == -1) {
1082254885Sdumbbell		DRM_ERROR("No relocation chunk !\n");
1083254885Sdumbbell		return -EINVAL;
1084254885Sdumbbell	}
1085254885Sdumbbell	*cs_reloc = NULL;
1086254885Sdumbbell	relocs_chunk = &p->chunks[p->chunk_relocs_idx];
1087254885Sdumbbell	r = evergreen_cs_packet_parse(p, &p3reloc, p->idx);
1088254885Sdumbbell	if (r) {
1089254885Sdumbbell		return r;
1090254885Sdumbbell	}
1091254885Sdumbbell	p->idx += p3reloc.count + 2;
1092254885Sdumbbell	if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) {
1093254885Sdumbbell		DRM_ERROR("No packet3 for relocation for packet at %d.\n",
1094254885Sdumbbell			  p3reloc.idx);
1095254885Sdumbbell		return -EINVAL;
1096254885Sdumbbell	}
1097254885Sdumbbell	idx = radeon_get_ib_value(p, p3reloc.idx + 1);
1098254885Sdumbbell	if (idx >= relocs_chunk->length_dw) {
1099254885Sdumbbell		DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
1100254885Sdumbbell			  idx, relocs_chunk->length_dw);
1101254885Sdumbbell		return -EINVAL;
1102254885Sdumbbell	}
1103254885Sdumbbell	/* FIXME: we assume reloc size is 4 dwords */
1104254885Sdumbbell	*cs_reloc = p->relocs_ptr[(idx / 4)];
1105254885Sdumbbell	return 0;
1106254885Sdumbbell}
1107254885Sdumbbell
1108254885Sdumbbell/**
1109254885Sdumbbell * evergreen_cs_packet_next_is_pkt3_nop() - test if the next packet is NOP
1110254885Sdumbbell * @p:		structure holding the parser context.
1111254885Sdumbbell *
1112254885Sdumbbell * Check if the next packet is a relocation packet3.
1113254885Sdumbbell **/
1114254885Sdumbbellstatic bool evergreen_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p)
1115254885Sdumbbell{
1116254885Sdumbbell	struct radeon_cs_packet p3reloc;
1117254885Sdumbbell	int r;
1118254885Sdumbbell
1119254885Sdumbbell	r = evergreen_cs_packet_parse(p, &p3reloc, p->idx);
1120254885Sdumbbell	if (r) {
1121254885Sdumbbell		return false;
1122254885Sdumbbell	}
1123254885Sdumbbell	if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) {
1124254885Sdumbbell		return false;
1125254885Sdumbbell	}
1126254885Sdumbbell	return true;
1127254885Sdumbbell}
1128254885Sdumbbell
1129254885Sdumbbell/**
1130254885Sdumbbell * evergreen_cs_packet_next_vline() - parse userspace VLINE packet
1131254885Sdumbbell * @parser:		parser structure holding parsing context.
1132254885Sdumbbell *
1133254885Sdumbbell * Userspace sends a special sequence for VLINE waits.
1134254885Sdumbbell * PACKET0 - VLINE_START_END + value
1135254885Sdumbbell * PACKET3 - WAIT_REG_MEM poll vline status reg
1136254885Sdumbbell * RELOC (P3) - crtc_id in reloc.
1137254885Sdumbbell *
1138254885Sdumbbell * This function parses this and relocates the VLINE START END
1139254885Sdumbbell * and WAIT_REG_MEM packets to the correct crtc.
1140254885Sdumbbell * It also detects a switched off crtc and nulls out the
1141254885Sdumbbell * wait in that case.
1142254885Sdumbbell */
1143254885Sdumbbellstatic int evergreen_cs_packet_parse_vline(struct radeon_cs_parser *p)
1144254885Sdumbbell{
1145254885Sdumbbell	struct drm_mode_object *obj;
1146254885Sdumbbell	struct drm_crtc *crtc;
1147254885Sdumbbell	struct radeon_crtc *radeon_crtc;
1148254885Sdumbbell	struct radeon_cs_packet p3reloc, wait_reg_mem;
1149254885Sdumbbell	int crtc_id;
1150254885Sdumbbell	int r;
1151254885Sdumbbell	uint32_t header, h_idx, reg, wait_reg_mem_info;
1152254885Sdumbbell	volatile uint32_t *ib;
1153254885Sdumbbell
1154254885Sdumbbell	ib = p->ib.ptr;
1155254885Sdumbbell
1156254885Sdumbbell	/* parse the WAIT_REG_MEM */
1157254885Sdumbbell	r = evergreen_cs_packet_parse(p, &wait_reg_mem, p->idx);
1158254885Sdumbbell	if (r)
1159254885Sdumbbell		return r;
1160254885Sdumbbell
1161254885Sdumbbell	/* check its a WAIT_REG_MEM */
1162254885Sdumbbell	if (wait_reg_mem.type != PACKET_TYPE3 ||
1163254885Sdumbbell	    wait_reg_mem.opcode != PACKET3_WAIT_REG_MEM) {
1164254885Sdumbbell		DRM_ERROR("vline wait missing WAIT_REG_MEM segment\n");
1165254885Sdumbbell		return -EINVAL;
1166254885Sdumbbell	}
1167254885Sdumbbell
1168254885Sdumbbell	wait_reg_mem_info = radeon_get_ib_value(p, wait_reg_mem.idx + 1);
1169254885Sdumbbell	/* bit 4 is reg (0) or mem (1) */
1170254885Sdumbbell	if (wait_reg_mem_info & 0x10) {
1171254885Sdumbbell		DRM_ERROR("vline WAIT_REG_MEM waiting on MEM rather than REG\n");
1172254885Sdumbbell		return -EINVAL;
1173254885Sdumbbell	}
1174254885Sdumbbell	/* waiting for value to be equal */
1175254885Sdumbbell	if ((wait_reg_mem_info & 0x7) != 0x3) {
1176254885Sdumbbell		DRM_ERROR("vline WAIT_REG_MEM function not equal\n");
1177254885Sdumbbell		return -EINVAL;
1178254885Sdumbbell	}
1179254885Sdumbbell	if ((radeon_get_ib_value(p, wait_reg_mem.idx + 2) << 2) != EVERGREEN_VLINE_STATUS) {
1180254885Sdumbbell		DRM_ERROR("vline WAIT_REG_MEM bad reg\n");
1181254885Sdumbbell		return -EINVAL;
1182254885Sdumbbell	}
1183254885Sdumbbell
1184254885Sdumbbell	if (radeon_get_ib_value(p, wait_reg_mem.idx + 5) != EVERGREEN_VLINE_STAT) {
1185254885Sdumbbell		DRM_ERROR("vline WAIT_REG_MEM bad bit mask\n");
1186254885Sdumbbell		return -EINVAL;
1187254885Sdumbbell	}
1188254885Sdumbbell
1189254885Sdumbbell	/* jump over the NOP */
1190254885Sdumbbell	r = evergreen_cs_packet_parse(p, &p3reloc, p->idx + wait_reg_mem.count + 2);
1191254885Sdumbbell	if (r)
1192254885Sdumbbell		return r;
1193254885Sdumbbell
1194254885Sdumbbell	h_idx = p->idx - 2;
1195254885Sdumbbell	p->idx += wait_reg_mem.count + 2;
1196254885Sdumbbell	p->idx += p3reloc.count + 2;
1197254885Sdumbbell
1198254885Sdumbbell	header = radeon_get_ib_value(p, h_idx);
1199254885Sdumbbell	crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1);
1200254885Sdumbbell	reg = CP_PACKET0_GET_REG(header);
1201254885Sdumbbell	obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
1202254885Sdumbbell	if (!obj) {
1203254885Sdumbbell		DRM_ERROR("cannot find crtc %d\n", crtc_id);
1204254885Sdumbbell		return -EINVAL;
1205254885Sdumbbell	}
1206254885Sdumbbell	crtc = obj_to_crtc(obj);
1207254885Sdumbbell	radeon_crtc = to_radeon_crtc(crtc);
1208254885Sdumbbell	crtc_id = radeon_crtc->crtc_id;
1209254885Sdumbbell
1210254885Sdumbbell	if (!crtc->enabled) {
1211254885Sdumbbell		/* if the CRTC isn't enabled - we need to nop out the WAIT_REG_MEM */
1212254885Sdumbbell		ib[h_idx + 2] = PACKET2(0);
1213254885Sdumbbell		ib[h_idx + 3] = PACKET2(0);
1214254885Sdumbbell		ib[h_idx + 4] = PACKET2(0);
1215254885Sdumbbell		ib[h_idx + 5] = PACKET2(0);
1216254885Sdumbbell		ib[h_idx + 6] = PACKET2(0);
1217254885Sdumbbell		ib[h_idx + 7] = PACKET2(0);
1218254885Sdumbbell		ib[h_idx + 8] = PACKET2(0);
1219254885Sdumbbell	} else {
1220254885Sdumbbell		switch (reg) {
1221254885Sdumbbell		case EVERGREEN_VLINE_START_END:
1222254885Sdumbbell			header &= ~R600_CP_PACKET0_REG_MASK;
1223254885Sdumbbell			header |= (EVERGREEN_VLINE_START_END + radeon_crtc->crtc_offset) >> 2;
1224254885Sdumbbell			ib[h_idx] = header;
1225254885Sdumbbell			ib[h_idx + 4] = (EVERGREEN_VLINE_STATUS + radeon_crtc->crtc_offset) >> 2;
1226254885Sdumbbell			break;
1227254885Sdumbbell		default:
1228254885Sdumbbell			DRM_ERROR("unknown crtc reloc\n");
1229254885Sdumbbell			return -EINVAL;
1230254885Sdumbbell		}
1231254885Sdumbbell	}
1232254885Sdumbbell	return 0;
1233254885Sdumbbell}
1234254885Sdumbbell
1235254885Sdumbbellstatic int evergreen_packet0_check(struct radeon_cs_parser *p,
1236254885Sdumbbell				   struct radeon_cs_packet *pkt,
1237254885Sdumbbell				   unsigned idx, unsigned reg)
1238254885Sdumbbell{
1239254885Sdumbbell	int r;
1240254885Sdumbbell
1241254885Sdumbbell	switch (reg) {
1242254885Sdumbbell	case EVERGREEN_VLINE_START_END:
1243254885Sdumbbell		r = evergreen_cs_packet_parse_vline(p);
1244254885Sdumbbell		if (r) {
1245254885Sdumbbell			DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
1246254885Sdumbbell					idx, reg);
1247254885Sdumbbell			return r;
1248254885Sdumbbell		}
1249254885Sdumbbell		break;
1250254885Sdumbbell	default:
1251254885Sdumbbell		DRM_ERROR("Forbidden register 0x%04X in cs at %d\n",
1252254885Sdumbbell		       reg, idx);
1253254885Sdumbbell		return -EINVAL;
1254254885Sdumbbell	}
1255254885Sdumbbell	return 0;
1256254885Sdumbbell}
1257254885Sdumbbell
1258254885Sdumbbellstatic int evergreen_cs_parse_packet0(struct radeon_cs_parser *p,
1259254885Sdumbbell				      struct radeon_cs_packet *pkt)
1260254885Sdumbbell{
1261254885Sdumbbell	unsigned reg, i;
1262254885Sdumbbell	unsigned idx;
1263254885Sdumbbell	int r;
1264254885Sdumbbell
1265254885Sdumbbell	idx = pkt->idx + 1;
1266254885Sdumbbell	reg = pkt->reg;
1267254885Sdumbbell	for (i = 0; i <= pkt->count; i++, idx++, reg += 4) {
1268254885Sdumbbell		r = evergreen_packet0_check(p, pkt, idx, reg);
1269254885Sdumbbell		if (r) {
1270254885Sdumbbell			return r;
1271254885Sdumbbell		}
1272254885Sdumbbell	}
1273254885Sdumbbell	return 0;
1274254885Sdumbbell}
1275254885Sdumbbell
1276254885Sdumbbell/**
1277254885Sdumbbell * evergreen_cs_check_reg() - check if register is authorized or not
1278254885Sdumbbell * @parser: parser structure holding parsing context
1279254885Sdumbbell * @reg: register we are testing
1280254885Sdumbbell * @idx: index into the cs buffer
1281254885Sdumbbell *
1282254885Sdumbbell * This function will test against evergreen_reg_safe_bm and return 0
1283254885Sdumbbell * if register is safe. If register is not flag as safe this function
1284254885Sdumbbell * will test it against a list of register needind special handling.
1285254885Sdumbbell */
1286254885Sdumbbellstatic int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
1287254885Sdumbbell{
1288254885Sdumbbell	struct evergreen_cs_track *track = (struct evergreen_cs_track *)p->track;
1289254885Sdumbbell	struct radeon_cs_reloc *reloc;
1290254885Sdumbbell	u32 last_reg;
1291254885Sdumbbell	u32 m, i, tmp, *ib;
1292254885Sdumbbell	int r;
1293254885Sdumbbell
1294254885Sdumbbell	if (p->rdev->family >= CHIP_CAYMAN)
1295254885Sdumbbell		last_reg = DRM_ARRAY_SIZE(cayman_reg_safe_bm);
1296254885Sdumbbell	else
1297254885Sdumbbell		last_reg = DRM_ARRAY_SIZE(evergreen_reg_safe_bm);
1298254885Sdumbbell
1299254885Sdumbbell	i = (reg >> 7);
1300254885Sdumbbell	if (i >= last_reg) {
1301254885Sdumbbell		dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
1302254885Sdumbbell		return -EINVAL;
1303254885Sdumbbell	}
1304254885Sdumbbell	m = 1 << ((reg >> 2) & 31);
1305254885Sdumbbell	if (p->rdev->family >= CHIP_CAYMAN) {
1306254885Sdumbbell		if (!(cayman_reg_safe_bm[i] & m))
1307254885Sdumbbell			return 0;
1308254885Sdumbbell	} else {
1309254885Sdumbbell		if (!(evergreen_reg_safe_bm[i] & m))
1310254885Sdumbbell			return 0;
1311254885Sdumbbell	}
1312254885Sdumbbell	ib = p->ib.ptr;
1313254885Sdumbbell	switch (reg) {
1314254885Sdumbbell	/* force following reg to 0 in an attempt to disable out buffer
1315254885Sdumbbell	 * which will need us to better understand how it works to perform
1316254885Sdumbbell	 * security check on it (Jerome)
1317254885Sdumbbell	 */
1318254885Sdumbbell	case SQ_ESGS_RING_SIZE:
1319254885Sdumbbell	case SQ_GSVS_RING_SIZE:
1320254885Sdumbbell	case SQ_ESTMP_RING_SIZE:
1321254885Sdumbbell	case SQ_GSTMP_RING_SIZE:
1322254885Sdumbbell	case SQ_HSTMP_RING_SIZE:
1323254885Sdumbbell	case SQ_LSTMP_RING_SIZE:
1324254885Sdumbbell	case SQ_PSTMP_RING_SIZE:
1325254885Sdumbbell	case SQ_VSTMP_RING_SIZE:
1326254885Sdumbbell	case SQ_ESGS_RING_ITEMSIZE:
1327254885Sdumbbell	case SQ_ESTMP_RING_ITEMSIZE:
1328254885Sdumbbell	case SQ_GSTMP_RING_ITEMSIZE:
1329254885Sdumbbell	case SQ_GSVS_RING_ITEMSIZE:
1330254885Sdumbbell	case SQ_GS_VERT_ITEMSIZE:
1331254885Sdumbbell	case SQ_GS_VERT_ITEMSIZE_1:
1332254885Sdumbbell	case SQ_GS_VERT_ITEMSIZE_2:
1333254885Sdumbbell	case SQ_GS_VERT_ITEMSIZE_3:
1334254885Sdumbbell	case SQ_GSVS_RING_OFFSET_1:
1335254885Sdumbbell	case SQ_GSVS_RING_OFFSET_2:
1336254885Sdumbbell	case SQ_GSVS_RING_OFFSET_3:
1337254885Sdumbbell	case SQ_HSTMP_RING_ITEMSIZE:
1338254885Sdumbbell	case SQ_LSTMP_RING_ITEMSIZE:
1339254885Sdumbbell	case SQ_PSTMP_RING_ITEMSIZE:
1340254885Sdumbbell	case SQ_VSTMP_RING_ITEMSIZE:
1341254885Sdumbbell	case VGT_TF_RING_SIZE:
1342254885Sdumbbell		/* get value to populate the IB don't remove */
1343254885Sdumbbell		/*tmp =radeon_get_ib_value(p, idx);
1344254885Sdumbbell		  ib[idx] = 0;*/
1345254885Sdumbbell		break;
1346254885Sdumbbell	case SQ_ESGS_RING_BASE:
1347254885Sdumbbell	case SQ_GSVS_RING_BASE:
1348254885Sdumbbell	case SQ_ESTMP_RING_BASE:
1349254885Sdumbbell	case SQ_GSTMP_RING_BASE:
1350254885Sdumbbell	case SQ_HSTMP_RING_BASE:
1351254885Sdumbbell	case SQ_LSTMP_RING_BASE:
1352254885Sdumbbell	case SQ_PSTMP_RING_BASE:
1353254885Sdumbbell	case SQ_VSTMP_RING_BASE:
1354254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1355254885Sdumbbell		if (r) {
1356254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1357254885Sdumbbell					"0x%04X\n", reg);
1358254885Sdumbbell			return -EINVAL;
1359254885Sdumbbell		}
1360254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1361254885Sdumbbell		break;
1362254885Sdumbbell	case DB_DEPTH_CONTROL:
1363254885Sdumbbell		track->db_depth_control = radeon_get_ib_value(p, idx);
1364254885Sdumbbell		track->db_dirty = true;
1365254885Sdumbbell		break;
1366254885Sdumbbell	case CAYMAN_DB_EQAA:
1367254885Sdumbbell		if (p->rdev->family < CHIP_CAYMAN) {
1368254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1369254885Sdumbbell				 "0x%04X\n", reg);
1370254885Sdumbbell			return -EINVAL;
1371254885Sdumbbell		}
1372254885Sdumbbell		break;
1373254885Sdumbbell	case CAYMAN_DB_DEPTH_INFO:
1374254885Sdumbbell		if (p->rdev->family < CHIP_CAYMAN) {
1375254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1376254885Sdumbbell				 "0x%04X\n", reg);
1377254885Sdumbbell			return -EINVAL;
1378254885Sdumbbell		}
1379254885Sdumbbell		break;
1380254885Sdumbbell	case DB_Z_INFO:
1381254885Sdumbbell		track->db_z_info = radeon_get_ib_value(p, idx);
1382254885Sdumbbell		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
1383254885Sdumbbell			r = evergreen_cs_packet_next_reloc(p, &reloc);
1384254885Sdumbbell			if (r) {
1385254885Sdumbbell				dev_warn(p->dev, "bad SET_CONTEXT_REG "
1386254885Sdumbbell						"0x%04X\n", reg);
1387254885Sdumbbell				return -EINVAL;
1388254885Sdumbbell			}
1389254885Sdumbbell			ib[idx] &= ~Z_ARRAY_MODE(0xf);
1390254885Sdumbbell			track->db_z_info &= ~Z_ARRAY_MODE(0xf);
1391254885Sdumbbell			ib[idx] |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
1392254885Sdumbbell			track->db_z_info |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
1393254885Sdumbbell			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
1394254885Sdumbbell				unsigned bankw, bankh, mtaspect, tile_split;
1395254885Sdumbbell
1396254885Sdumbbell				evergreen_tiling_fields(reloc->lobj.tiling_flags,
1397254885Sdumbbell							&bankw, &bankh, &mtaspect,
1398254885Sdumbbell							&tile_split);
1399254885Sdumbbell				ib[idx] |= DB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
1400254885Sdumbbell				ib[idx] |= DB_TILE_SPLIT(tile_split) |
1401254885Sdumbbell						DB_BANK_WIDTH(bankw) |
1402254885Sdumbbell						DB_BANK_HEIGHT(bankh) |
1403254885Sdumbbell						DB_MACRO_TILE_ASPECT(mtaspect);
1404254885Sdumbbell			}
1405254885Sdumbbell		}
1406254885Sdumbbell		track->db_dirty = true;
1407254885Sdumbbell		break;
1408254885Sdumbbell	case DB_STENCIL_INFO:
1409254885Sdumbbell		track->db_s_info = radeon_get_ib_value(p, idx);
1410254885Sdumbbell		track->db_dirty = true;
1411254885Sdumbbell		break;
1412254885Sdumbbell	case DB_DEPTH_VIEW:
1413254885Sdumbbell		track->db_depth_view = radeon_get_ib_value(p, idx);
1414254885Sdumbbell		track->db_dirty = true;
1415254885Sdumbbell		break;
1416254885Sdumbbell	case DB_DEPTH_SIZE:
1417254885Sdumbbell		track->db_depth_size = radeon_get_ib_value(p, idx);
1418254885Sdumbbell		track->db_dirty = true;
1419254885Sdumbbell		break;
1420254885Sdumbbell	case R_02805C_DB_DEPTH_SLICE:
1421254885Sdumbbell		track->db_depth_slice = radeon_get_ib_value(p, idx);
1422254885Sdumbbell		track->db_dirty = true;
1423254885Sdumbbell		break;
1424254885Sdumbbell	case DB_Z_READ_BASE:
1425254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1426254885Sdumbbell		if (r) {
1427254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1428254885Sdumbbell					"0x%04X\n", reg);
1429254885Sdumbbell			return -EINVAL;
1430254885Sdumbbell		}
1431254885Sdumbbell		track->db_z_read_offset = radeon_get_ib_value(p, idx);
1432254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1433254885Sdumbbell		track->db_z_read_bo = reloc->robj;
1434254885Sdumbbell		track->db_dirty = true;
1435254885Sdumbbell		break;
1436254885Sdumbbell	case DB_Z_WRITE_BASE:
1437254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1438254885Sdumbbell		if (r) {
1439254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1440254885Sdumbbell					"0x%04X\n", reg);
1441254885Sdumbbell			return -EINVAL;
1442254885Sdumbbell		}
1443254885Sdumbbell		track->db_z_write_offset = radeon_get_ib_value(p, idx);
1444254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1445254885Sdumbbell		track->db_z_write_bo = reloc->robj;
1446254885Sdumbbell		track->db_dirty = true;
1447254885Sdumbbell		break;
1448254885Sdumbbell	case DB_STENCIL_READ_BASE:
1449254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1450254885Sdumbbell		if (r) {
1451254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1452254885Sdumbbell					"0x%04X\n", reg);
1453254885Sdumbbell			return -EINVAL;
1454254885Sdumbbell		}
1455254885Sdumbbell		track->db_s_read_offset = radeon_get_ib_value(p, idx);
1456254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1457254885Sdumbbell		track->db_s_read_bo = reloc->robj;
1458254885Sdumbbell		track->db_dirty = true;
1459254885Sdumbbell		break;
1460254885Sdumbbell	case DB_STENCIL_WRITE_BASE:
1461254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1462254885Sdumbbell		if (r) {
1463254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1464254885Sdumbbell					"0x%04X\n", reg);
1465254885Sdumbbell			return -EINVAL;
1466254885Sdumbbell		}
1467254885Sdumbbell		track->db_s_write_offset = radeon_get_ib_value(p, idx);
1468254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1469254885Sdumbbell		track->db_s_write_bo = reloc->robj;
1470254885Sdumbbell		track->db_dirty = true;
1471254885Sdumbbell		break;
1472254885Sdumbbell	case VGT_STRMOUT_CONFIG:
1473254885Sdumbbell		track->vgt_strmout_config = radeon_get_ib_value(p, idx);
1474254885Sdumbbell		track->streamout_dirty = true;
1475254885Sdumbbell		break;
1476254885Sdumbbell	case VGT_STRMOUT_BUFFER_CONFIG:
1477254885Sdumbbell		track->vgt_strmout_buffer_config = radeon_get_ib_value(p, idx);
1478254885Sdumbbell		track->streamout_dirty = true;
1479254885Sdumbbell		break;
1480254885Sdumbbell	case VGT_STRMOUT_BUFFER_BASE_0:
1481254885Sdumbbell	case VGT_STRMOUT_BUFFER_BASE_1:
1482254885Sdumbbell	case VGT_STRMOUT_BUFFER_BASE_2:
1483254885Sdumbbell	case VGT_STRMOUT_BUFFER_BASE_3:
1484254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1485254885Sdumbbell		if (r) {
1486254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1487254885Sdumbbell					"0x%04X\n", reg);
1488254885Sdumbbell			return -EINVAL;
1489254885Sdumbbell		}
1490254885Sdumbbell		tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16;
1491254885Sdumbbell		track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
1492254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1493254885Sdumbbell		track->vgt_strmout_bo[tmp] = reloc->robj;
1494254885Sdumbbell		track->streamout_dirty = true;
1495254885Sdumbbell		break;
1496254885Sdumbbell	case VGT_STRMOUT_BUFFER_SIZE_0:
1497254885Sdumbbell	case VGT_STRMOUT_BUFFER_SIZE_1:
1498254885Sdumbbell	case VGT_STRMOUT_BUFFER_SIZE_2:
1499254885Sdumbbell	case VGT_STRMOUT_BUFFER_SIZE_3:
1500254885Sdumbbell		tmp = (reg - VGT_STRMOUT_BUFFER_SIZE_0) / 16;
1501254885Sdumbbell		/* size in register is DWs, convert to bytes */
1502254885Sdumbbell		track->vgt_strmout_size[tmp] = radeon_get_ib_value(p, idx) * 4;
1503254885Sdumbbell		track->streamout_dirty = true;
1504254885Sdumbbell		break;
1505254885Sdumbbell	case CP_COHER_BASE:
1506254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1507254885Sdumbbell		if (r) {
1508254885Sdumbbell			dev_warn(p->dev, "missing reloc for CP_COHER_BASE "
1509254885Sdumbbell					"0x%04X\n", reg);
1510254885Sdumbbell			return -EINVAL;
1511254885Sdumbbell		}
1512254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1513254885Sdumbbell	case CB_TARGET_MASK:
1514254885Sdumbbell		track->cb_target_mask = radeon_get_ib_value(p, idx);
1515254885Sdumbbell		track->cb_dirty = true;
1516254885Sdumbbell		break;
1517254885Sdumbbell	case CB_SHADER_MASK:
1518254885Sdumbbell		track->cb_shader_mask = radeon_get_ib_value(p, idx);
1519254885Sdumbbell		track->cb_dirty = true;
1520254885Sdumbbell		break;
1521254885Sdumbbell	case PA_SC_AA_CONFIG:
1522254885Sdumbbell		if (p->rdev->family >= CHIP_CAYMAN) {
1523254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1524254885Sdumbbell				 "0x%04X\n", reg);
1525254885Sdumbbell			return -EINVAL;
1526254885Sdumbbell		}
1527254885Sdumbbell		tmp = radeon_get_ib_value(p, idx) & MSAA_NUM_SAMPLES_MASK;
1528254885Sdumbbell		track->nsamples = 1 << tmp;
1529254885Sdumbbell		break;
1530254885Sdumbbell	case CAYMAN_PA_SC_AA_CONFIG:
1531254885Sdumbbell		if (p->rdev->family < CHIP_CAYMAN) {
1532254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1533254885Sdumbbell				 "0x%04X\n", reg);
1534254885Sdumbbell			return -EINVAL;
1535254885Sdumbbell		}
1536254885Sdumbbell		tmp = radeon_get_ib_value(p, idx) & CAYMAN_MSAA_NUM_SAMPLES_MASK;
1537254885Sdumbbell		track->nsamples = 1 << tmp;
1538254885Sdumbbell		break;
1539254885Sdumbbell	case CB_COLOR0_VIEW:
1540254885Sdumbbell	case CB_COLOR1_VIEW:
1541254885Sdumbbell	case CB_COLOR2_VIEW:
1542254885Sdumbbell	case CB_COLOR3_VIEW:
1543254885Sdumbbell	case CB_COLOR4_VIEW:
1544254885Sdumbbell	case CB_COLOR5_VIEW:
1545254885Sdumbbell	case CB_COLOR6_VIEW:
1546254885Sdumbbell	case CB_COLOR7_VIEW:
1547254885Sdumbbell		tmp = (reg - CB_COLOR0_VIEW) / 0x3c;
1548254885Sdumbbell		track->cb_color_view[tmp] = radeon_get_ib_value(p, idx);
1549254885Sdumbbell		track->cb_dirty = true;
1550254885Sdumbbell		break;
1551254885Sdumbbell	case CB_COLOR8_VIEW:
1552254885Sdumbbell	case CB_COLOR9_VIEW:
1553254885Sdumbbell	case CB_COLOR10_VIEW:
1554254885Sdumbbell	case CB_COLOR11_VIEW:
1555254885Sdumbbell		tmp = ((reg - CB_COLOR8_VIEW) / 0x1c) + 8;
1556254885Sdumbbell		track->cb_color_view[tmp] = radeon_get_ib_value(p, idx);
1557254885Sdumbbell		track->cb_dirty = true;
1558254885Sdumbbell		break;
1559254885Sdumbbell	case CB_COLOR0_INFO:
1560254885Sdumbbell	case CB_COLOR1_INFO:
1561254885Sdumbbell	case CB_COLOR2_INFO:
1562254885Sdumbbell	case CB_COLOR3_INFO:
1563254885Sdumbbell	case CB_COLOR4_INFO:
1564254885Sdumbbell	case CB_COLOR5_INFO:
1565254885Sdumbbell	case CB_COLOR6_INFO:
1566254885Sdumbbell	case CB_COLOR7_INFO:
1567254885Sdumbbell		tmp = (reg - CB_COLOR0_INFO) / 0x3c;
1568254885Sdumbbell		track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
1569254885Sdumbbell		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
1570254885Sdumbbell			r = evergreen_cs_packet_next_reloc(p, &reloc);
1571254885Sdumbbell			if (r) {
1572254885Sdumbbell				dev_warn(p->dev, "bad SET_CONTEXT_REG "
1573254885Sdumbbell						"0x%04X\n", reg);
1574254885Sdumbbell				return -EINVAL;
1575254885Sdumbbell			}
1576254885Sdumbbell			ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
1577254885Sdumbbell			track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
1578254885Sdumbbell		}
1579254885Sdumbbell		track->cb_dirty = true;
1580254885Sdumbbell		break;
1581254885Sdumbbell	case CB_COLOR8_INFO:
1582254885Sdumbbell	case CB_COLOR9_INFO:
1583254885Sdumbbell	case CB_COLOR10_INFO:
1584254885Sdumbbell	case CB_COLOR11_INFO:
1585254885Sdumbbell		tmp = ((reg - CB_COLOR8_INFO) / 0x1c) + 8;
1586254885Sdumbbell		track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
1587254885Sdumbbell		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
1588254885Sdumbbell			r = evergreen_cs_packet_next_reloc(p, &reloc);
1589254885Sdumbbell			if (r) {
1590254885Sdumbbell				dev_warn(p->dev, "bad SET_CONTEXT_REG "
1591254885Sdumbbell						"0x%04X\n", reg);
1592254885Sdumbbell				return -EINVAL;
1593254885Sdumbbell			}
1594254885Sdumbbell			ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
1595254885Sdumbbell			track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
1596254885Sdumbbell		}
1597254885Sdumbbell		track->cb_dirty = true;
1598254885Sdumbbell		break;
1599254885Sdumbbell	case CB_COLOR0_PITCH:
1600254885Sdumbbell	case CB_COLOR1_PITCH:
1601254885Sdumbbell	case CB_COLOR2_PITCH:
1602254885Sdumbbell	case CB_COLOR3_PITCH:
1603254885Sdumbbell	case CB_COLOR4_PITCH:
1604254885Sdumbbell	case CB_COLOR5_PITCH:
1605254885Sdumbbell	case CB_COLOR6_PITCH:
1606254885Sdumbbell	case CB_COLOR7_PITCH:
1607254885Sdumbbell		tmp = (reg - CB_COLOR0_PITCH) / 0x3c;
1608254885Sdumbbell		track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx);
1609254885Sdumbbell		track->cb_dirty = true;
1610254885Sdumbbell		break;
1611254885Sdumbbell	case CB_COLOR8_PITCH:
1612254885Sdumbbell	case CB_COLOR9_PITCH:
1613254885Sdumbbell	case CB_COLOR10_PITCH:
1614254885Sdumbbell	case CB_COLOR11_PITCH:
1615254885Sdumbbell		tmp = ((reg - CB_COLOR8_PITCH) / 0x1c) + 8;
1616254885Sdumbbell		track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx);
1617254885Sdumbbell		track->cb_dirty = true;
1618254885Sdumbbell		break;
1619254885Sdumbbell	case CB_COLOR0_SLICE:
1620254885Sdumbbell	case CB_COLOR1_SLICE:
1621254885Sdumbbell	case CB_COLOR2_SLICE:
1622254885Sdumbbell	case CB_COLOR3_SLICE:
1623254885Sdumbbell	case CB_COLOR4_SLICE:
1624254885Sdumbbell	case CB_COLOR5_SLICE:
1625254885Sdumbbell	case CB_COLOR6_SLICE:
1626254885Sdumbbell	case CB_COLOR7_SLICE:
1627254885Sdumbbell		tmp = (reg - CB_COLOR0_SLICE) / 0x3c;
1628254885Sdumbbell		track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx);
1629254885Sdumbbell		track->cb_color_slice_idx[tmp] = idx;
1630254885Sdumbbell		track->cb_dirty = true;
1631254885Sdumbbell		break;
1632254885Sdumbbell	case CB_COLOR8_SLICE:
1633254885Sdumbbell	case CB_COLOR9_SLICE:
1634254885Sdumbbell	case CB_COLOR10_SLICE:
1635254885Sdumbbell	case CB_COLOR11_SLICE:
1636254885Sdumbbell		tmp = ((reg - CB_COLOR8_SLICE) / 0x1c) + 8;
1637254885Sdumbbell		track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx);
1638254885Sdumbbell		track->cb_color_slice_idx[tmp] = idx;
1639254885Sdumbbell		track->cb_dirty = true;
1640254885Sdumbbell		break;
1641254885Sdumbbell	case CB_COLOR0_ATTRIB:
1642254885Sdumbbell	case CB_COLOR1_ATTRIB:
1643254885Sdumbbell	case CB_COLOR2_ATTRIB:
1644254885Sdumbbell	case CB_COLOR3_ATTRIB:
1645254885Sdumbbell	case CB_COLOR4_ATTRIB:
1646254885Sdumbbell	case CB_COLOR5_ATTRIB:
1647254885Sdumbbell	case CB_COLOR6_ATTRIB:
1648254885Sdumbbell	case CB_COLOR7_ATTRIB:
1649254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1650254885Sdumbbell		if (r) {
1651254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1652254885Sdumbbell					"0x%04X\n", reg);
1653254885Sdumbbell			return -EINVAL;
1654254885Sdumbbell		}
1655254885Sdumbbell		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
1656254885Sdumbbell			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
1657254885Sdumbbell				unsigned bankw, bankh, mtaspect, tile_split;
1658254885Sdumbbell
1659254885Sdumbbell				evergreen_tiling_fields(reloc->lobj.tiling_flags,
1660254885Sdumbbell							&bankw, &bankh, &mtaspect,
1661254885Sdumbbell							&tile_split);
1662254885Sdumbbell				ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
1663254885Sdumbbell				ib[idx] |= CB_TILE_SPLIT(tile_split) |
1664254885Sdumbbell					   CB_BANK_WIDTH(bankw) |
1665254885Sdumbbell					   CB_BANK_HEIGHT(bankh) |
1666254885Sdumbbell					   CB_MACRO_TILE_ASPECT(mtaspect);
1667254885Sdumbbell			}
1668254885Sdumbbell		}
1669254885Sdumbbell		tmp = ((reg - CB_COLOR0_ATTRIB) / 0x3c);
1670254885Sdumbbell		track->cb_color_attrib[tmp] = ib[idx];
1671254885Sdumbbell		track->cb_dirty = true;
1672254885Sdumbbell		break;
1673254885Sdumbbell	case CB_COLOR8_ATTRIB:
1674254885Sdumbbell	case CB_COLOR9_ATTRIB:
1675254885Sdumbbell	case CB_COLOR10_ATTRIB:
1676254885Sdumbbell	case CB_COLOR11_ATTRIB:
1677254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1678254885Sdumbbell		if (r) {
1679254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1680254885Sdumbbell					"0x%04X\n", reg);
1681254885Sdumbbell			return -EINVAL;
1682254885Sdumbbell		}
1683254885Sdumbbell		if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
1684254885Sdumbbell			if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
1685254885Sdumbbell				unsigned bankw, bankh, mtaspect, tile_split;
1686254885Sdumbbell
1687254885Sdumbbell				evergreen_tiling_fields(reloc->lobj.tiling_flags,
1688254885Sdumbbell							&bankw, &bankh, &mtaspect,
1689254885Sdumbbell							&tile_split);
1690254885Sdumbbell				ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
1691254885Sdumbbell				ib[idx] |= CB_TILE_SPLIT(tile_split) |
1692254885Sdumbbell					   CB_BANK_WIDTH(bankw) |
1693254885Sdumbbell					   CB_BANK_HEIGHT(bankh) |
1694254885Sdumbbell					   CB_MACRO_TILE_ASPECT(mtaspect);
1695254885Sdumbbell			}
1696254885Sdumbbell		}
1697254885Sdumbbell		tmp = ((reg - CB_COLOR8_ATTRIB) / 0x1c) + 8;
1698254885Sdumbbell		track->cb_color_attrib[tmp] = ib[idx];
1699254885Sdumbbell		track->cb_dirty = true;
1700254885Sdumbbell		break;
1701254885Sdumbbell	case CB_COLOR0_FMASK:
1702254885Sdumbbell	case CB_COLOR1_FMASK:
1703254885Sdumbbell	case CB_COLOR2_FMASK:
1704254885Sdumbbell	case CB_COLOR3_FMASK:
1705254885Sdumbbell	case CB_COLOR4_FMASK:
1706254885Sdumbbell	case CB_COLOR5_FMASK:
1707254885Sdumbbell	case CB_COLOR6_FMASK:
1708254885Sdumbbell	case CB_COLOR7_FMASK:
1709254885Sdumbbell		tmp = (reg - CB_COLOR0_FMASK) / 0x3c;
1710254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1711254885Sdumbbell		if (r) {
1712254885Sdumbbell			dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
1713254885Sdumbbell			return -EINVAL;
1714254885Sdumbbell		}
1715254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1716254885Sdumbbell		track->cb_color_fmask_bo[tmp] = reloc->robj;
1717254885Sdumbbell		break;
1718254885Sdumbbell	case CB_COLOR0_CMASK:
1719254885Sdumbbell	case CB_COLOR1_CMASK:
1720254885Sdumbbell	case CB_COLOR2_CMASK:
1721254885Sdumbbell	case CB_COLOR3_CMASK:
1722254885Sdumbbell	case CB_COLOR4_CMASK:
1723254885Sdumbbell	case CB_COLOR5_CMASK:
1724254885Sdumbbell	case CB_COLOR6_CMASK:
1725254885Sdumbbell	case CB_COLOR7_CMASK:
1726254885Sdumbbell		tmp = (reg - CB_COLOR0_CMASK) / 0x3c;
1727254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1728254885Sdumbbell		if (r) {
1729254885Sdumbbell			dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
1730254885Sdumbbell			return -EINVAL;
1731254885Sdumbbell		}
1732254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1733254885Sdumbbell		track->cb_color_cmask_bo[tmp] = reloc->robj;
1734254885Sdumbbell		break;
1735254885Sdumbbell	case CB_COLOR0_FMASK_SLICE:
1736254885Sdumbbell	case CB_COLOR1_FMASK_SLICE:
1737254885Sdumbbell	case CB_COLOR2_FMASK_SLICE:
1738254885Sdumbbell	case CB_COLOR3_FMASK_SLICE:
1739254885Sdumbbell	case CB_COLOR4_FMASK_SLICE:
1740254885Sdumbbell	case CB_COLOR5_FMASK_SLICE:
1741254885Sdumbbell	case CB_COLOR6_FMASK_SLICE:
1742254885Sdumbbell	case CB_COLOR7_FMASK_SLICE:
1743254885Sdumbbell		tmp = (reg - CB_COLOR0_FMASK_SLICE) / 0x3c;
1744254885Sdumbbell		track->cb_color_fmask_slice[tmp] = radeon_get_ib_value(p, idx);
1745254885Sdumbbell		break;
1746254885Sdumbbell	case CB_COLOR0_CMASK_SLICE:
1747254885Sdumbbell	case CB_COLOR1_CMASK_SLICE:
1748254885Sdumbbell	case CB_COLOR2_CMASK_SLICE:
1749254885Sdumbbell	case CB_COLOR3_CMASK_SLICE:
1750254885Sdumbbell	case CB_COLOR4_CMASK_SLICE:
1751254885Sdumbbell	case CB_COLOR5_CMASK_SLICE:
1752254885Sdumbbell	case CB_COLOR6_CMASK_SLICE:
1753254885Sdumbbell	case CB_COLOR7_CMASK_SLICE:
1754254885Sdumbbell		tmp = (reg - CB_COLOR0_CMASK_SLICE) / 0x3c;
1755254885Sdumbbell		track->cb_color_cmask_slice[tmp] = radeon_get_ib_value(p, idx);
1756254885Sdumbbell		break;
1757254885Sdumbbell	case CB_COLOR0_BASE:
1758254885Sdumbbell	case CB_COLOR1_BASE:
1759254885Sdumbbell	case CB_COLOR2_BASE:
1760254885Sdumbbell	case CB_COLOR3_BASE:
1761254885Sdumbbell	case CB_COLOR4_BASE:
1762254885Sdumbbell	case CB_COLOR5_BASE:
1763254885Sdumbbell	case CB_COLOR6_BASE:
1764254885Sdumbbell	case CB_COLOR7_BASE:
1765254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1766254885Sdumbbell		if (r) {
1767254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1768254885Sdumbbell					"0x%04X\n", reg);
1769254885Sdumbbell			return -EINVAL;
1770254885Sdumbbell		}
1771254885Sdumbbell		tmp = (reg - CB_COLOR0_BASE) / 0x3c;
1772254885Sdumbbell		track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
1773254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1774254885Sdumbbell		track->cb_color_bo[tmp] = reloc->robj;
1775254885Sdumbbell		track->cb_dirty = true;
1776254885Sdumbbell		break;
1777254885Sdumbbell	case CB_COLOR8_BASE:
1778254885Sdumbbell	case CB_COLOR9_BASE:
1779254885Sdumbbell	case CB_COLOR10_BASE:
1780254885Sdumbbell	case CB_COLOR11_BASE:
1781254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1782254885Sdumbbell		if (r) {
1783254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1784254885Sdumbbell					"0x%04X\n", reg);
1785254885Sdumbbell			return -EINVAL;
1786254885Sdumbbell		}
1787254885Sdumbbell		tmp = ((reg - CB_COLOR8_BASE) / 0x1c) + 8;
1788254885Sdumbbell		track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
1789254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1790254885Sdumbbell		track->cb_color_bo[tmp] = reloc->robj;
1791254885Sdumbbell		track->cb_dirty = true;
1792254885Sdumbbell		break;
1793254885Sdumbbell	case DB_HTILE_DATA_BASE:
1794254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1795254885Sdumbbell		if (r) {
1796254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1797254885Sdumbbell					"0x%04X\n", reg);
1798254885Sdumbbell			return -EINVAL;
1799254885Sdumbbell		}
1800254885Sdumbbell		track->htile_offset = radeon_get_ib_value(p, idx);
1801254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1802254885Sdumbbell		track->htile_bo = reloc->robj;
1803254885Sdumbbell		track->db_dirty = true;
1804254885Sdumbbell		break;
1805254885Sdumbbell	case DB_HTILE_SURFACE:
1806254885Sdumbbell		/* 8x8 only */
1807254885Sdumbbell		track->htile_surface = radeon_get_ib_value(p, idx);
1808254885Sdumbbell		/* force 8x8 htile width and height */
1809254885Sdumbbell		ib[idx] |= 3;
1810254885Sdumbbell		track->db_dirty = true;
1811254885Sdumbbell		break;
1812254885Sdumbbell	case CB_IMMED0_BASE:
1813254885Sdumbbell	case CB_IMMED1_BASE:
1814254885Sdumbbell	case CB_IMMED2_BASE:
1815254885Sdumbbell	case CB_IMMED3_BASE:
1816254885Sdumbbell	case CB_IMMED4_BASE:
1817254885Sdumbbell	case CB_IMMED5_BASE:
1818254885Sdumbbell	case CB_IMMED6_BASE:
1819254885Sdumbbell	case CB_IMMED7_BASE:
1820254885Sdumbbell	case CB_IMMED8_BASE:
1821254885Sdumbbell	case CB_IMMED9_BASE:
1822254885Sdumbbell	case CB_IMMED10_BASE:
1823254885Sdumbbell	case CB_IMMED11_BASE:
1824254885Sdumbbell	case SQ_PGM_START_FS:
1825254885Sdumbbell	case SQ_PGM_START_ES:
1826254885Sdumbbell	case SQ_PGM_START_VS:
1827254885Sdumbbell	case SQ_PGM_START_GS:
1828254885Sdumbbell	case SQ_PGM_START_PS:
1829254885Sdumbbell	case SQ_PGM_START_HS:
1830254885Sdumbbell	case SQ_PGM_START_LS:
1831254885Sdumbbell	case SQ_CONST_MEM_BASE:
1832254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_0:
1833254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_1:
1834254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_2:
1835254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_3:
1836254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_4:
1837254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_5:
1838254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_6:
1839254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_7:
1840254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_8:
1841254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_9:
1842254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_10:
1843254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_11:
1844254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_12:
1845254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_13:
1846254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_14:
1847254885Sdumbbell	case SQ_ALU_CONST_CACHE_GS_15:
1848254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_0:
1849254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_1:
1850254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_2:
1851254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_3:
1852254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_4:
1853254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_5:
1854254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_6:
1855254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_7:
1856254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_8:
1857254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_9:
1858254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_10:
1859254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_11:
1860254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_12:
1861254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_13:
1862254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_14:
1863254885Sdumbbell	case SQ_ALU_CONST_CACHE_PS_15:
1864254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_0:
1865254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_1:
1866254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_2:
1867254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_3:
1868254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_4:
1869254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_5:
1870254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_6:
1871254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_7:
1872254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_8:
1873254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_9:
1874254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_10:
1875254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_11:
1876254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_12:
1877254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_13:
1878254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_14:
1879254885Sdumbbell	case SQ_ALU_CONST_CACHE_VS_15:
1880254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_0:
1881254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_1:
1882254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_2:
1883254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_3:
1884254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_4:
1885254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_5:
1886254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_6:
1887254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_7:
1888254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_8:
1889254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_9:
1890254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_10:
1891254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_11:
1892254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_12:
1893254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_13:
1894254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_14:
1895254885Sdumbbell	case SQ_ALU_CONST_CACHE_HS_15:
1896254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_0:
1897254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_1:
1898254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_2:
1899254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_3:
1900254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_4:
1901254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_5:
1902254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_6:
1903254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_7:
1904254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_8:
1905254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_9:
1906254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_10:
1907254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_11:
1908254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_12:
1909254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_13:
1910254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_14:
1911254885Sdumbbell	case SQ_ALU_CONST_CACHE_LS_15:
1912254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1913254885Sdumbbell		if (r) {
1914254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1915254885Sdumbbell					"0x%04X\n", reg);
1916254885Sdumbbell			return -EINVAL;
1917254885Sdumbbell		}
1918254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1919254885Sdumbbell		break;
1920254885Sdumbbell	case SX_MEMORY_EXPORT_BASE:
1921254885Sdumbbell		if (p->rdev->family >= CHIP_CAYMAN) {
1922254885Sdumbbell			dev_warn(p->dev, "bad SET_CONFIG_REG "
1923254885Sdumbbell				 "0x%04X\n", reg);
1924254885Sdumbbell			return -EINVAL;
1925254885Sdumbbell		}
1926254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1927254885Sdumbbell		if (r) {
1928254885Sdumbbell			dev_warn(p->dev, "bad SET_CONFIG_REG "
1929254885Sdumbbell					"0x%04X\n", reg);
1930254885Sdumbbell			return -EINVAL;
1931254885Sdumbbell		}
1932254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1933254885Sdumbbell		break;
1934254885Sdumbbell	case CAYMAN_SX_SCATTER_EXPORT_BASE:
1935254885Sdumbbell		if (p->rdev->family < CHIP_CAYMAN) {
1936254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1937254885Sdumbbell				 "0x%04X\n", reg);
1938254885Sdumbbell			return -EINVAL;
1939254885Sdumbbell		}
1940254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
1941254885Sdumbbell		if (r) {
1942254885Sdumbbell			dev_warn(p->dev, "bad SET_CONTEXT_REG "
1943254885Sdumbbell					"0x%04X\n", reg);
1944254885Sdumbbell			return -EINVAL;
1945254885Sdumbbell		}
1946254885Sdumbbell		ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
1947254885Sdumbbell		break;
1948254885Sdumbbell	case SX_MISC:
1949254885Sdumbbell		track->sx_misc_kill_all_prims = (radeon_get_ib_value(p, idx) & 0x1) != 0;
1950254885Sdumbbell		break;
1951254885Sdumbbell	default:
1952254885Sdumbbell		dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
1953254885Sdumbbell		return -EINVAL;
1954254885Sdumbbell	}
1955254885Sdumbbell	return 0;
1956254885Sdumbbell}
1957254885Sdumbbell
1958254885Sdumbbellstatic bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
1959254885Sdumbbell{
1960254885Sdumbbell	u32 last_reg, m, i;
1961254885Sdumbbell
1962254885Sdumbbell	if (p->rdev->family >= CHIP_CAYMAN)
1963254885Sdumbbell		last_reg = DRM_ARRAY_SIZE(cayman_reg_safe_bm);
1964254885Sdumbbell	else
1965254885Sdumbbell		last_reg = DRM_ARRAY_SIZE(evergreen_reg_safe_bm);
1966254885Sdumbbell
1967254885Sdumbbell	i = (reg >> 7);
1968254885Sdumbbell	if (i >= last_reg) {
1969254885Sdumbbell		dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
1970254885Sdumbbell		return false;
1971254885Sdumbbell	}
1972254885Sdumbbell	m = 1 << ((reg >> 2) & 31);
1973254885Sdumbbell	if (p->rdev->family >= CHIP_CAYMAN) {
1974254885Sdumbbell		if (!(cayman_reg_safe_bm[i] & m))
1975254885Sdumbbell			return true;
1976254885Sdumbbell	} else {
1977254885Sdumbbell		if (!(evergreen_reg_safe_bm[i] & m))
1978254885Sdumbbell			return true;
1979254885Sdumbbell	}
1980254885Sdumbbell	dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
1981254885Sdumbbell	return false;
1982254885Sdumbbell}
1983254885Sdumbbell
1984254885Sdumbbellstatic int evergreen_packet3_check(struct radeon_cs_parser *p,
1985254885Sdumbbell				   struct radeon_cs_packet *pkt)
1986254885Sdumbbell{
1987254885Sdumbbell	struct radeon_cs_reloc *reloc;
1988254885Sdumbbell	struct evergreen_cs_track *track;
1989254885Sdumbbell	volatile u32 *ib;
1990254885Sdumbbell	unsigned idx;
1991254885Sdumbbell	unsigned i;
1992254885Sdumbbell	unsigned start_reg, end_reg, reg;
1993254885Sdumbbell	int r;
1994254885Sdumbbell	u32 idx_value;
1995254885Sdumbbell
1996254885Sdumbbell	track = (struct evergreen_cs_track *)p->track;
1997254885Sdumbbell	ib = p->ib.ptr;
1998254885Sdumbbell	idx = pkt->idx + 1;
1999254885Sdumbbell	idx_value = radeon_get_ib_value(p, idx);
2000254885Sdumbbell
2001254885Sdumbbell	switch (pkt->opcode) {
2002254885Sdumbbell	case PACKET3_SET_PREDICATION:
2003254885Sdumbbell	{
2004254885Sdumbbell		int pred_op;
2005254885Sdumbbell		int tmp;
2006254885Sdumbbell		uint64_t offset;
2007254885Sdumbbell
2008254885Sdumbbell		if (pkt->count != 1) {
2009254885Sdumbbell			DRM_ERROR("bad SET PREDICATION\n");
2010254885Sdumbbell			return -EINVAL;
2011254885Sdumbbell		}
2012254885Sdumbbell
2013254885Sdumbbell		tmp = radeon_get_ib_value(p, idx + 1);
2014254885Sdumbbell		pred_op = (tmp >> 16) & 0x7;
2015254885Sdumbbell
2016254885Sdumbbell		/* for the clear predicate operation */
2017254885Sdumbbell		if (pred_op == 0)
2018254885Sdumbbell			return 0;
2019254885Sdumbbell
2020254885Sdumbbell		if (pred_op > 2) {
2021254885Sdumbbell			DRM_ERROR("bad SET PREDICATION operation %d\n", pred_op);
2022254885Sdumbbell			return -EINVAL;
2023254885Sdumbbell		}
2024254885Sdumbbell
2025254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
2026254885Sdumbbell		if (r) {
2027254885Sdumbbell			DRM_ERROR("bad SET PREDICATION\n");
2028254885Sdumbbell			return -EINVAL;
2029254885Sdumbbell		}
2030254885Sdumbbell
2031254885Sdumbbell		offset = reloc->lobj.gpu_offset +
2032254885Sdumbbell		         (idx_value & 0xfffffff0) +
2033254885Sdumbbell		         ((u64)(tmp & 0xff) << 32);
2034254885Sdumbbell
2035254885Sdumbbell		ib[idx + 0] = offset;
2036254885Sdumbbell		ib[idx + 1] = (tmp & 0xffffff00) | (upper_32_bits(offset) & 0xff);
2037254885Sdumbbell	}
2038254885Sdumbbell	break;
2039254885Sdumbbell	case PACKET3_CONTEXT_CONTROL:
2040254885Sdumbbell		if (pkt->count != 1) {
2041254885Sdumbbell			DRM_ERROR("bad CONTEXT_CONTROL\n");
2042254885Sdumbbell			return -EINVAL;
2043254885Sdumbbell		}
2044254885Sdumbbell		break;
2045254885Sdumbbell	case PACKET3_INDEX_TYPE:
2046254885Sdumbbell	case PACKET3_NUM_INSTANCES:
2047254885Sdumbbell	case PACKET3_CLEAR_STATE:
2048254885Sdumbbell		if (pkt->count) {
2049254885Sdumbbell			DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES/CLEAR_STATE\n");
2050254885Sdumbbell			return -EINVAL;
2051254885Sdumbbell		}
2052254885Sdumbbell		break;
2053254885Sdumbbell	case CAYMAN_PACKET3_DEALLOC_STATE:
2054254885Sdumbbell		if (p->rdev->family < CHIP_CAYMAN) {
2055254885Sdumbbell			DRM_ERROR("bad PACKET3_DEALLOC_STATE\n");
2056254885Sdumbbell			return -EINVAL;
2057254885Sdumbbell		}
2058254885Sdumbbell		if (pkt->count) {
2059254885Sdumbbell			DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES/CLEAR_STATE\n");
2060254885Sdumbbell			return -EINVAL;
2061254885Sdumbbell		}
2062254885Sdumbbell		break;
2063254885Sdumbbell	case PACKET3_INDEX_BASE:
2064254885Sdumbbell	{
2065254885Sdumbbell		uint64_t offset;
2066254885Sdumbbell
2067254885Sdumbbell		if (pkt->count != 1) {
2068254885Sdumbbell			DRM_ERROR("bad INDEX_BASE\n");
2069254885Sdumbbell			return -EINVAL;
2070254885Sdumbbell		}
2071254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
2072254885Sdumbbell		if (r) {
2073254885Sdumbbell			DRM_ERROR("bad INDEX_BASE\n");
2074254885Sdumbbell			return -EINVAL;
2075254885Sdumbbell		}
2076254885Sdumbbell
2077254885Sdumbbell		offset = reloc->lobj.gpu_offset +
2078254885Sdumbbell		         idx_value +
2079254885Sdumbbell		         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
2080254885Sdumbbell
2081254885Sdumbbell		ib[idx+0] = offset;
2082254885Sdumbbell		ib[idx+1] = upper_32_bits(offset) & 0xff;
2083254885Sdumbbell
2084254885Sdumbbell		r = evergreen_cs_track_check(p);
2085254885Sdumbbell		if (r) {
2086254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
2087254885Sdumbbell			return r;
2088254885Sdumbbell		}
2089254885Sdumbbell		break;
2090254885Sdumbbell	}
2091254885Sdumbbell	case PACKET3_DRAW_INDEX:
2092254885Sdumbbell	{
2093254885Sdumbbell		uint64_t offset;
2094254885Sdumbbell		if (pkt->count != 3) {
2095254885Sdumbbell			DRM_ERROR("bad DRAW_INDEX\n");
2096254885Sdumbbell			return -EINVAL;
2097254885Sdumbbell		}
2098254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
2099254885Sdumbbell		if (r) {
2100254885Sdumbbell			DRM_ERROR("bad DRAW_INDEX\n");
2101254885Sdumbbell			return -EINVAL;
2102254885Sdumbbell		}
2103254885Sdumbbell
2104254885Sdumbbell		offset = reloc->lobj.gpu_offset +
2105254885Sdumbbell		         idx_value +
2106254885Sdumbbell		         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
2107254885Sdumbbell
2108254885Sdumbbell		ib[idx+0] = offset;
2109254885Sdumbbell		ib[idx+1] = upper_32_bits(offset) & 0xff;
2110254885Sdumbbell
2111254885Sdumbbell		r = evergreen_cs_track_check(p);
2112254885Sdumbbell		if (r) {
2113254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
2114254885Sdumbbell			return r;
2115254885Sdumbbell		}
2116254885Sdumbbell		break;
2117254885Sdumbbell	}
2118254885Sdumbbell	case PACKET3_DRAW_INDEX_2:
2119254885Sdumbbell	{
2120254885Sdumbbell		uint64_t offset;
2121254885Sdumbbell
2122254885Sdumbbell		if (pkt->count != 4) {
2123254885Sdumbbell			DRM_ERROR("bad DRAW_INDEX_2\n");
2124254885Sdumbbell			return -EINVAL;
2125254885Sdumbbell		}
2126254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
2127254885Sdumbbell		if (r) {
2128254885Sdumbbell			DRM_ERROR("bad DRAW_INDEX_2\n");
2129254885Sdumbbell			return -EINVAL;
2130254885Sdumbbell		}
2131254885Sdumbbell
2132254885Sdumbbell		offset = reloc->lobj.gpu_offset +
2133254885Sdumbbell		         radeon_get_ib_value(p, idx+1) +
2134254885Sdumbbell		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
2135254885Sdumbbell
2136254885Sdumbbell		ib[idx+1] = offset;
2137254885Sdumbbell		ib[idx+2] = upper_32_bits(offset) & 0xff;
2138254885Sdumbbell
2139254885Sdumbbell		r = evergreen_cs_track_check(p);
2140254885Sdumbbell		if (r) {
2141254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
2142254885Sdumbbell			return r;
2143254885Sdumbbell		}
2144254885Sdumbbell		break;
2145254885Sdumbbell	}
2146254885Sdumbbell	case PACKET3_DRAW_INDEX_AUTO:
2147254885Sdumbbell		if (pkt->count != 1) {
2148254885Sdumbbell			DRM_ERROR("bad DRAW_INDEX_AUTO\n");
2149254885Sdumbbell			return -EINVAL;
2150254885Sdumbbell		}
2151254885Sdumbbell		r = evergreen_cs_track_check(p);
2152254885Sdumbbell		if (r) {
2153254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx);
2154254885Sdumbbell			return r;
2155254885Sdumbbell		}
2156254885Sdumbbell		break;
2157254885Sdumbbell	case PACKET3_DRAW_INDEX_MULTI_AUTO:
2158254885Sdumbbell		if (pkt->count != 2) {
2159254885Sdumbbell			DRM_ERROR("bad DRAW_INDEX_MULTI_AUTO\n");
2160254885Sdumbbell			return -EINVAL;
2161254885Sdumbbell		}
2162254885Sdumbbell		r = evergreen_cs_track_check(p);
2163254885Sdumbbell		if (r) {
2164254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx);
2165254885Sdumbbell			return r;
2166254885Sdumbbell		}
2167254885Sdumbbell		break;
2168254885Sdumbbell	case PACKET3_DRAW_INDEX_IMMD:
2169254885Sdumbbell		if (pkt->count < 2) {
2170254885Sdumbbell			DRM_ERROR("bad DRAW_INDEX_IMMD\n");
2171254885Sdumbbell			return -EINVAL;
2172254885Sdumbbell		}
2173254885Sdumbbell		r = evergreen_cs_track_check(p);
2174254885Sdumbbell		if (r) {
2175254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
2176254885Sdumbbell			return r;
2177254885Sdumbbell		}
2178254885Sdumbbell		break;
2179254885Sdumbbell	case PACKET3_DRAW_INDEX_OFFSET:
2180254885Sdumbbell		if (pkt->count != 2) {
2181254885Sdumbbell			DRM_ERROR("bad DRAW_INDEX_OFFSET\n");
2182254885Sdumbbell			return -EINVAL;
2183254885Sdumbbell		}
2184254885Sdumbbell		r = evergreen_cs_track_check(p);
2185254885Sdumbbell		if (r) {
2186254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
2187254885Sdumbbell			return r;
2188254885Sdumbbell		}
2189254885Sdumbbell		break;
2190254885Sdumbbell	case PACKET3_DRAW_INDEX_OFFSET_2:
2191254885Sdumbbell		if (pkt->count != 3) {
2192254885Sdumbbell			DRM_ERROR("bad DRAW_INDEX_OFFSET_2\n");
2193254885Sdumbbell			return -EINVAL;
2194254885Sdumbbell		}
2195254885Sdumbbell		r = evergreen_cs_track_check(p);
2196254885Sdumbbell		if (r) {
2197254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
2198254885Sdumbbell			return r;
2199254885Sdumbbell		}
2200254885Sdumbbell		break;
2201254885Sdumbbell	case PACKET3_DISPATCH_DIRECT:
2202254885Sdumbbell		if (pkt->count != 3) {
2203254885Sdumbbell			DRM_ERROR("bad DISPATCH_DIRECT\n");
2204254885Sdumbbell			return -EINVAL;
2205254885Sdumbbell		}
2206254885Sdumbbell		r = evergreen_cs_track_check(p);
2207254885Sdumbbell		if (r) {
2208254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx);
2209254885Sdumbbell			return r;
2210254885Sdumbbell		}
2211254885Sdumbbell		break;
2212254885Sdumbbell	case PACKET3_DISPATCH_INDIRECT:
2213254885Sdumbbell		if (pkt->count != 1) {
2214254885Sdumbbell			DRM_ERROR("bad DISPATCH_INDIRECT\n");
2215254885Sdumbbell			return -EINVAL;
2216254885Sdumbbell		}
2217254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
2218254885Sdumbbell		if (r) {
2219254885Sdumbbell			DRM_ERROR("bad DISPATCH_INDIRECT\n");
2220254885Sdumbbell			return -EINVAL;
2221254885Sdumbbell		}
2222254885Sdumbbell		ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
2223254885Sdumbbell		r = evergreen_cs_track_check(p);
2224254885Sdumbbell		if (r) {
2225254885Sdumbbell			dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
2226254885Sdumbbell			return r;
2227254885Sdumbbell		}
2228254885Sdumbbell		break;
2229254885Sdumbbell	case PACKET3_WAIT_REG_MEM:
2230254885Sdumbbell		if (pkt->count != 5) {
2231254885Sdumbbell			DRM_ERROR("bad WAIT_REG_MEM\n");
2232254885Sdumbbell			return -EINVAL;
2233254885Sdumbbell		}
2234254885Sdumbbell		/* bit 4 is reg (0) or mem (1) */
2235254885Sdumbbell		if (idx_value & 0x10) {
2236254885Sdumbbell			uint64_t offset;
2237254885Sdumbbell
2238254885Sdumbbell			r = evergreen_cs_packet_next_reloc(p, &reloc);
2239254885Sdumbbell			if (r) {
2240254885Sdumbbell				DRM_ERROR("bad WAIT_REG_MEM\n");
2241254885Sdumbbell				return -EINVAL;
2242254885Sdumbbell			}
2243254885Sdumbbell
2244254885Sdumbbell			offset = reloc->lobj.gpu_offset +
2245254885Sdumbbell			         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
2246254885Sdumbbell			         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
2247254885Sdumbbell
2248254885Sdumbbell			ib[idx+1] = (ib[idx+1] & 0x3) | (offset & 0xfffffffc);
2249254885Sdumbbell			ib[idx+2] = upper_32_bits(offset) & 0xff;
2250254885Sdumbbell		}
2251254885Sdumbbell		break;
2252254885Sdumbbell	case PACKET3_CP_DMA:
2253254885Sdumbbell	{
2254254885Sdumbbell		u32 command, size, info;
2255254885Sdumbbell		u64 offset, tmp;
2256254885Sdumbbell		if (pkt->count != 4) {
2257254885Sdumbbell			DRM_ERROR("bad CP DMA\n");
2258254885Sdumbbell			return -EINVAL;
2259254885Sdumbbell		}
2260254885Sdumbbell		command = radeon_get_ib_value(p, idx+4);
2261254885Sdumbbell		size = command & 0x1fffff;
2262254885Sdumbbell		info = radeon_get_ib_value(p, idx+1);
2263254885Sdumbbell		if ((((info & 0x60000000) >> 29) != 0) || /* src = GDS or DATA */
2264254885Sdumbbell		    (((info & 0x00300000) >> 20) != 0) || /* dst = GDS */
2265254885Sdumbbell		    ((((info & 0x00300000) >> 20) == 0) &&
2266254885Sdumbbell		     (command & PACKET3_CP_DMA_CMD_DAS)) || /* dst = register */
2267254885Sdumbbell		    ((((info & 0x60000000) >> 29) == 0) &&
2268254885Sdumbbell		     (command & PACKET3_CP_DMA_CMD_SAS))) { /* src = register */
2269254885Sdumbbell			/* non mem to mem copies requires dw aligned count */
2270254885Sdumbbell			if (size % 4) {
2271254885Sdumbbell				DRM_ERROR("CP DMA command requires dw count alignment\n");
2272254885Sdumbbell				return -EINVAL;
2273254885Sdumbbell			}
2274254885Sdumbbell		}
2275254885Sdumbbell		if (command & PACKET3_CP_DMA_CMD_SAS) {
2276254885Sdumbbell			/* src address space is register */
2277254885Sdumbbell			/* GDS is ok */
2278254885Sdumbbell			if (((info & 0x60000000) >> 29) != 1) {
2279254885Sdumbbell				DRM_ERROR("CP DMA SAS not supported\n");
2280254885Sdumbbell				return -EINVAL;
2281254885Sdumbbell			}
2282254885Sdumbbell		} else {
2283254885Sdumbbell			if (command & PACKET3_CP_DMA_CMD_SAIC) {
2284254885Sdumbbell				DRM_ERROR("CP DMA SAIC only supported for registers\n");
2285254885Sdumbbell				return -EINVAL;
2286254885Sdumbbell			}
2287254885Sdumbbell			/* src address space is memory */
2288254885Sdumbbell			if (((info & 0x60000000) >> 29) == 0) {
2289254885Sdumbbell				r = evergreen_cs_packet_next_reloc(p, &reloc);
2290254885Sdumbbell				if (r) {
2291254885Sdumbbell					DRM_ERROR("bad CP DMA SRC\n");
2292254885Sdumbbell					return -EINVAL;
2293254885Sdumbbell				}
2294254885Sdumbbell
2295254885Sdumbbell				tmp = radeon_get_ib_value(p, idx) +
2296254885Sdumbbell					((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
2297254885Sdumbbell
2298254885Sdumbbell				offset = reloc->lobj.gpu_offset + tmp;
2299254885Sdumbbell
2300254885Sdumbbell				if ((tmp + size) > radeon_bo_size(reloc->robj)) {
2301254885Sdumbbell					dev_warn(p->dev, "CP DMA src buffer too small (%ju %lu)\n",
2302254885Sdumbbell						 (uintmax_t)tmp + size, radeon_bo_size(reloc->robj));
2303254885Sdumbbell					return -EINVAL;
2304254885Sdumbbell				}
2305254885Sdumbbell
2306254885Sdumbbell				ib[idx] = offset;
2307254885Sdumbbell				ib[idx+1] = (ib[idx+1] & 0xffffff00) | (upper_32_bits(offset) & 0xff);
2308254885Sdumbbell			} else if (((info & 0x60000000) >> 29) != 2) {
2309254885Sdumbbell				DRM_ERROR("bad CP DMA SRC_SEL\n");
2310254885Sdumbbell				return -EINVAL;
2311254885Sdumbbell			}
2312254885Sdumbbell		}
2313254885Sdumbbell		if (command & PACKET3_CP_DMA_CMD_DAS) {
2314254885Sdumbbell			/* dst address space is register */
2315254885Sdumbbell			/* GDS is ok */
2316254885Sdumbbell			if (((info & 0x00300000) >> 20) != 1) {
2317254885Sdumbbell				DRM_ERROR("CP DMA DAS not supported\n");
2318254885Sdumbbell				return -EINVAL;
2319254885Sdumbbell			}
2320254885Sdumbbell		} else {
2321254885Sdumbbell			/* dst address space is memory */
2322254885Sdumbbell			if (command & PACKET3_CP_DMA_CMD_DAIC) {
2323254885Sdumbbell				DRM_ERROR("CP DMA DAIC only supported for registers\n");
2324254885Sdumbbell				return -EINVAL;
2325254885Sdumbbell			}
2326254885Sdumbbell			if (((info & 0x00300000) >> 20) == 0) {
2327254885Sdumbbell				r = evergreen_cs_packet_next_reloc(p, &reloc);
2328254885Sdumbbell				if (r) {
2329254885Sdumbbell					DRM_ERROR("bad CP DMA DST\n");
2330254885Sdumbbell					return -EINVAL;
2331254885Sdumbbell				}
2332254885Sdumbbell
2333254885Sdumbbell				tmp = radeon_get_ib_value(p, idx+2) +
2334254885Sdumbbell					((u64)(radeon_get_ib_value(p, idx+3) & 0xff) << 32);
2335254885Sdumbbell
2336254885Sdumbbell				offset = reloc->lobj.gpu_offset + tmp;
2337254885Sdumbbell
2338254885Sdumbbell				if ((tmp + size) > radeon_bo_size(reloc->robj)) {
2339254885Sdumbbell					dev_warn(p->dev, "CP DMA dst buffer too small (%ju %lu)\n",
2340254885Sdumbbell						 (uintmax_t)tmp + size, radeon_bo_size(reloc->robj));
2341254885Sdumbbell					return -EINVAL;
2342254885Sdumbbell				}
2343254885Sdumbbell
2344254885Sdumbbell				ib[idx+2] = offset;
2345254885Sdumbbell				ib[idx+3] = upper_32_bits(offset) & 0xff;
2346254885Sdumbbell			} else {
2347254885Sdumbbell				DRM_ERROR("bad CP DMA DST_SEL\n");
2348254885Sdumbbell				return -EINVAL;
2349254885Sdumbbell			}
2350254885Sdumbbell		}
2351254885Sdumbbell		break;
2352254885Sdumbbell	}
2353254885Sdumbbell	case PACKET3_SURFACE_SYNC:
2354254885Sdumbbell		if (pkt->count != 3) {
2355254885Sdumbbell			DRM_ERROR("bad SURFACE_SYNC\n");
2356254885Sdumbbell			return -EINVAL;
2357254885Sdumbbell		}
2358254885Sdumbbell		/* 0xffffffff/0x0 is flush all cache flag */
2359254885Sdumbbell		if (radeon_get_ib_value(p, idx + 1) != 0xffffffff ||
2360254885Sdumbbell		    radeon_get_ib_value(p, idx + 2) != 0) {
2361254885Sdumbbell			r = evergreen_cs_packet_next_reloc(p, &reloc);
2362254885Sdumbbell			if (r) {
2363254885Sdumbbell				DRM_ERROR("bad SURFACE_SYNC\n");
2364254885Sdumbbell				return -EINVAL;
2365254885Sdumbbell			}
2366254885Sdumbbell			ib[idx+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
2367254885Sdumbbell		}
2368254885Sdumbbell		break;
2369254885Sdumbbell	case PACKET3_EVENT_WRITE:
2370254885Sdumbbell		if (pkt->count != 2 && pkt->count != 0) {
2371254885Sdumbbell			DRM_ERROR("bad EVENT_WRITE\n");
2372254885Sdumbbell			return -EINVAL;
2373254885Sdumbbell		}
2374254885Sdumbbell		if (pkt->count) {
2375254885Sdumbbell			uint64_t offset;
2376254885Sdumbbell
2377254885Sdumbbell			r = evergreen_cs_packet_next_reloc(p, &reloc);
2378254885Sdumbbell			if (r) {
2379254885Sdumbbell				DRM_ERROR("bad EVENT_WRITE\n");
2380254885Sdumbbell				return -EINVAL;
2381254885Sdumbbell			}
2382254885Sdumbbell			offset = reloc->lobj.gpu_offset +
2383254885Sdumbbell			         (radeon_get_ib_value(p, idx+1) & 0xfffffff8) +
2384254885Sdumbbell			         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
2385254885Sdumbbell
2386254885Sdumbbell			ib[idx+1] = offset & 0xfffffff8;
2387254885Sdumbbell			ib[idx+2] = upper_32_bits(offset) & 0xff;
2388254885Sdumbbell		}
2389254885Sdumbbell		break;
2390254885Sdumbbell	case PACKET3_EVENT_WRITE_EOP:
2391254885Sdumbbell	{
2392254885Sdumbbell		uint64_t offset;
2393254885Sdumbbell
2394254885Sdumbbell		if (pkt->count != 4) {
2395254885Sdumbbell			DRM_ERROR("bad EVENT_WRITE_EOP\n");
2396254885Sdumbbell			return -EINVAL;
2397254885Sdumbbell		}
2398254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
2399254885Sdumbbell		if (r) {
2400254885Sdumbbell			DRM_ERROR("bad EVENT_WRITE_EOP\n");
2401254885Sdumbbell			return -EINVAL;
2402254885Sdumbbell		}
2403254885Sdumbbell
2404254885Sdumbbell		offset = reloc->lobj.gpu_offset +
2405254885Sdumbbell		         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
2406254885Sdumbbell		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
2407254885Sdumbbell
2408254885Sdumbbell		ib[idx+1] = offset & 0xfffffffc;
2409254885Sdumbbell		ib[idx+2] = (ib[idx+2] & 0xffffff00) | (upper_32_bits(offset) & 0xff);
2410254885Sdumbbell		break;
2411254885Sdumbbell	}
2412254885Sdumbbell	case PACKET3_EVENT_WRITE_EOS:
2413254885Sdumbbell	{
2414254885Sdumbbell		uint64_t offset;
2415254885Sdumbbell
2416254885Sdumbbell		if (pkt->count != 3) {
2417254885Sdumbbell			DRM_ERROR("bad EVENT_WRITE_EOS\n");
2418254885Sdumbbell			return -EINVAL;
2419254885Sdumbbell		}
2420254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
2421254885Sdumbbell		if (r) {
2422254885Sdumbbell			DRM_ERROR("bad EVENT_WRITE_EOS\n");
2423254885Sdumbbell			return -EINVAL;
2424254885Sdumbbell		}
2425254885Sdumbbell
2426254885Sdumbbell		offset = reloc->lobj.gpu_offset +
2427254885Sdumbbell		         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
2428254885Sdumbbell		         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
2429254885Sdumbbell
2430254885Sdumbbell		ib[idx+1] = offset & 0xfffffffc;
2431254885Sdumbbell		ib[idx+2] = (ib[idx+2] & 0xffffff00) | (upper_32_bits(offset) & 0xff);
2432254885Sdumbbell		break;
2433254885Sdumbbell	}
2434254885Sdumbbell	case PACKET3_SET_CONFIG_REG:
2435254885Sdumbbell		start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_START;
2436254885Sdumbbell		end_reg = 4 * pkt->count + start_reg - 4;
2437254885Sdumbbell		if ((start_reg < PACKET3_SET_CONFIG_REG_START) ||
2438254885Sdumbbell		    (start_reg >= PACKET3_SET_CONFIG_REG_END) ||
2439254885Sdumbbell		    (end_reg >= PACKET3_SET_CONFIG_REG_END)) {
2440254885Sdumbbell			DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n");
2441254885Sdumbbell			return -EINVAL;
2442254885Sdumbbell		}
2443254885Sdumbbell		for (i = 0; i < pkt->count; i++) {
2444254885Sdumbbell			reg = start_reg + (4 * i);
2445254885Sdumbbell			r = evergreen_cs_check_reg(p, reg, idx+1+i);
2446254885Sdumbbell			if (r)
2447254885Sdumbbell				return r;
2448254885Sdumbbell		}
2449254885Sdumbbell		break;
2450254885Sdumbbell	case PACKET3_SET_CONTEXT_REG:
2451254885Sdumbbell		start_reg = (idx_value << 2) + PACKET3_SET_CONTEXT_REG_START;
2452254885Sdumbbell		end_reg = 4 * pkt->count + start_reg - 4;
2453254885Sdumbbell		if ((start_reg < PACKET3_SET_CONTEXT_REG_START) ||
2454254885Sdumbbell		    (start_reg >= PACKET3_SET_CONTEXT_REG_END) ||
2455254885Sdumbbell		    (end_reg >= PACKET3_SET_CONTEXT_REG_END)) {
2456254885Sdumbbell			DRM_ERROR("bad PACKET3_SET_CONTEXT_REG\n");
2457254885Sdumbbell			return -EINVAL;
2458254885Sdumbbell		}
2459254885Sdumbbell		for (i = 0; i < pkt->count; i++) {
2460254885Sdumbbell			reg = start_reg + (4 * i);
2461254885Sdumbbell			r = evergreen_cs_check_reg(p, reg, idx+1+i);
2462254885Sdumbbell			if (r)
2463254885Sdumbbell				return r;
2464254885Sdumbbell		}
2465254885Sdumbbell		break;
2466254885Sdumbbell	case PACKET3_SET_RESOURCE:
2467254885Sdumbbell		if (pkt->count % 8) {
2468254885Sdumbbell			DRM_ERROR("bad SET_RESOURCE\n");
2469254885Sdumbbell			return -EINVAL;
2470254885Sdumbbell		}
2471254885Sdumbbell		start_reg = (idx_value << 2) + PACKET3_SET_RESOURCE_START;
2472254885Sdumbbell		end_reg = 4 * pkt->count + start_reg - 4;
2473254885Sdumbbell		if ((start_reg < PACKET3_SET_RESOURCE_START) ||
2474254885Sdumbbell		    (start_reg >= PACKET3_SET_RESOURCE_END) ||
2475254885Sdumbbell		    (end_reg >= PACKET3_SET_RESOURCE_END)) {
2476254885Sdumbbell			DRM_ERROR("bad SET_RESOURCE\n");
2477254885Sdumbbell			return -EINVAL;
2478254885Sdumbbell		}
2479254885Sdumbbell		for (i = 0; i < (pkt->count / 8); i++) {
2480254885Sdumbbell			struct radeon_bo *texture, *mipmap;
2481254885Sdumbbell			u32 toffset, moffset;
2482254885Sdumbbell			u32 size, offset, mip_address, tex_dim;
2483254885Sdumbbell
2484254885Sdumbbell			switch (G__SQ_CONSTANT_TYPE(radeon_get_ib_value(p, idx+1+(i*8)+7))) {
2485254885Sdumbbell			case SQ_TEX_VTX_VALID_TEXTURE:
2486254885Sdumbbell				/* tex base */
2487254885Sdumbbell				r = evergreen_cs_packet_next_reloc(p, &reloc);
2488254885Sdumbbell				if (r) {
2489254885Sdumbbell					DRM_ERROR("bad SET_RESOURCE (tex)\n");
2490254885Sdumbbell					return -EINVAL;
2491254885Sdumbbell				}
2492254885Sdumbbell				if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
2493254885Sdumbbell					ib[idx+1+(i*8)+1] |=
2494254885Sdumbbell						TEX_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
2495254885Sdumbbell					if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
2496254885Sdumbbell						unsigned bankw, bankh, mtaspect, tile_split;
2497254885Sdumbbell
2498254885Sdumbbell						evergreen_tiling_fields(reloc->lobj.tiling_flags,
2499254885Sdumbbell									&bankw, &bankh, &mtaspect,
2500254885Sdumbbell									&tile_split);
2501254885Sdumbbell						ib[idx+1+(i*8)+6] |= TEX_TILE_SPLIT(tile_split);
2502254885Sdumbbell						ib[idx+1+(i*8)+7] |=
2503254885Sdumbbell							TEX_BANK_WIDTH(bankw) |
2504254885Sdumbbell							TEX_BANK_HEIGHT(bankh) |
2505254885Sdumbbell							MACRO_TILE_ASPECT(mtaspect) |
2506254885Sdumbbell							TEX_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
2507254885Sdumbbell					}
2508254885Sdumbbell				}
2509254885Sdumbbell				texture = reloc->robj;
2510254885Sdumbbell				toffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
2511254885Sdumbbell
2512254885Sdumbbell				/* tex mip base */
2513254885Sdumbbell				tex_dim = ib[idx+1+(i*8)+0] & 0x7;
2514254885Sdumbbell				mip_address = ib[idx+1+(i*8)+3];
2515254885Sdumbbell
2516254885Sdumbbell				if ((tex_dim == SQ_TEX_DIM_2D_MSAA || tex_dim == SQ_TEX_DIM_2D_ARRAY_MSAA) &&
2517254885Sdumbbell				    !mip_address &&
2518254885Sdumbbell				    !evergreen_cs_packet_next_is_pkt3_nop(p)) {
2519254885Sdumbbell					/* MIP_ADDRESS should point to FMASK for an MSAA texture.
2520254885Sdumbbell					 * It should be 0 if FMASK is disabled. */
2521254885Sdumbbell					moffset = 0;
2522254885Sdumbbell					mipmap = NULL;
2523254885Sdumbbell				} else {
2524254885Sdumbbell					r = evergreen_cs_packet_next_reloc(p, &reloc);
2525254885Sdumbbell					if (r) {
2526254885Sdumbbell						DRM_ERROR("bad SET_RESOURCE (tex)\n");
2527254885Sdumbbell						return -EINVAL;
2528254885Sdumbbell					}
2529254885Sdumbbell					moffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
2530254885Sdumbbell					mipmap = reloc->robj;
2531254885Sdumbbell				}
2532254885Sdumbbell
2533254885Sdumbbell				r = evergreen_cs_track_validate_texture(p, texture, mipmap, idx+1+(i*8));
2534254885Sdumbbell				if (r)
2535254885Sdumbbell					return r;
2536254885Sdumbbell				ib[idx+1+(i*8)+2] += toffset;
2537254885Sdumbbell				ib[idx+1+(i*8)+3] += moffset;
2538254885Sdumbbell				break;
2539254885Sdumbbell			case SQ_TEX_VTX_VALID_BUFFER:
2540254885Sdumbbell			{
2541254885Sdumbbell				uint64_t offset64;
2542254885Sdumbbell				/* vtx base */
2543254885Sdumbbell				r = evergreen_cs_packet_next_reloc(p, &reloc);
2544254885Sdumbbell				if (r) {
2545254885Sdumbbell					DRM_ERROR("bad SET_RESOURCE (vtx)\n");
2546254885Sdumbbell					return -EINVAL;
2547254885Sdumbbell				}
2548254885Sdumbbell				offset = radeon_get_ib_value(p, idx+1+(i*8)+0);
2549254885Sdumbbell				size = radeon_get_ib_value(p, idx+1+(i*8)+1);
2550254885Sdumbbell				if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) {
2551254885Sdumbbell					/* force size to size of the buffer */
2552254885Sdumbbell					dev_warn(p->dev, "vbo resource seems too big for the bo\n");
2553254885Sdumbbell					ib[idx+1+(i*8)+1] = radeon_bo_size(reloc->robj) - offset;
2554254885Sdumbbell				}
2555254885Sdumbbell
2556254885Sdumbbell				offset64 = reloc->lobj.gpu_offset + offset;
2557254885Sdumbbell				ib[idx+1+(i*8)+0] = offset64;
2558254885Sdumbbell				ib[idx+1+(i*8)+2] = (ib[idx+1+(i*8)+2] & 0xffffff00) |
2559254885Sdumbbell						    (upper_32_bits(offset64) & 0xff);
2560254885Sdumbbell				break;
2561254885Sdumbbell			}
2562254885Sdumbbell			case SQ_TEX_VTX_INVALID_TEXTURE:
2563254885Sdumbbell			case SQ_TEX_VTX_INVALID_BUFFER:
2564254885Sdumbbell			default:
2565254885Sdumbbell				DRM_ERROR("bad SET_RESOURCE\n");
2566254885Sdumbbell				return -EINVAL;
2567254885Sdumbbell			}
2568254885Sdumbbell		}
2569254885Sdumbbell		break;
2570254885Sdumbbell	case PACKET3_SET_ALU_CONST:
2571254885Sdumbbell		/* XXX fix me ALU const buffers only */
2572254885Sdumbbell		break;
2573254885Sdumbbell	case PACKET3_SET_BOOL_CONST:
2574254885Sdumbbell		start_reg = (idx_value << 2) + PACKET3_SET_BOOL_CONST_START;
2575254885Sdumbbell		end_reg = 4 * pkt->count + start_reg - 4;
2576254885Sdumbbell		if ((start_reg < PACKET3_SET_BOOL_CONST_START) ||
2577254885Sdumbbell		    (start_reg >= PACKET3_SET_BOOL_CONST_END) ||
2578254885Sdumbbell		    (end_reg >= PACKET3_SET_BOOL_CONST_END)) {
2579254885Sdumbbell			DRM_ERROR("bad SET_BOOL_CONST\n");
2580254885Sdumbbell			return -EINVAL;
2581254885Sdumbbell		}
2582254885Sdumbbell		break;
2583254885Sdumbbell	case PACKET3_SET_LOOP_CONST:
2584254885Sdumbbell		start_reg = (idx_value << 2) + PACKET3_SET_LOOP_CONST_START;
2585254885Sdumbbell		end_reg = 4 * pkt->count + start_reg - 4;
2586254885Sdumbbell		if ((start_reg < PACKET3_SET_LOOP_CONST_START) ||
2587254885Sdumbbell		    (start_reg >= PACKET3_SET_LOOP_CONST_END) ||
2588254885Sdumbbell		    (end_reg >= PACKET3_SET_LOOP_CONST_END)) {
2589254885Sdumbbell			DRM_ERROR("bad SET_LOOP_CONST\n");
2590254885Sdumbbell			return -EINVAL;
2591254885Sdumbbell		}
2592254885Sdumbbell		break;
2593254885Sdumbbell	case PACKET3_SET_CTL_CONST:
2594254885Sdumbbell		start_reg = (idx_value << 2) + PACKET3_SET_CTL_CONST_START;
2595254885Sdumbbell		end_reg = 4 * pkt->count + start_reg - 4;
2596254885Sdumbbell		if ((start_reg < PACKET3_SET_CTL_CONST_START) ||
2597254885Sdumbbell		    (start_reg >= PACKET3_SET_CTL_CONST_END) ||
2598254885Sdumbbell		    (end_reg >= PACKET3_SET_CTL_CONST_END)) {
2599254885Sdumbbell			DRM_ERROR("bad SET_CTL_CONST\n");
2600254885Sdumbbell			return -EINVAL;
2601254885Sdumbbell		}
2602254885Sdumbbell		break;
2603254885Sdumbbell	case PACKET3_SET_SAMPLER:
2604254885Sdumbbell		if (pkt->count % 3) {
2605254885Sdumbbell			DRM_ERROR("bad SET_SAMPLER\n");
2606254885Sdumbbell			return -EINVAL;
2607254885Sdumbbell		}
2608254885Sdumbbell		start_reg = (idx_value << 2) + PACKET3_SET_SAMPLER_START;
2609254885Sdumbbell		end_reg = 4 * pkt->count + start_reg - 4;
2610254885Sdumbbell		if ((start_reg < PACKET3_SET_SAMPLER_START) ||
2611254885Sdumbbell		    (start_reg >= PACKET3_SET_SAMPLER_END) ||
2612254885Sdumbbell		    (end_reg >= PACKET3_SET_SAMPLER_END)) {
2613254885Sdumbbell			DRM_ERROR("bad SET_SAMPLER\n");
2614254885Sdumbbell			return -EINVAL;
2615254885Sdumbbell		}
2616254885Sdumbbell		break;
2617254885Sdumbbell	case PACKET3_STRMOUT_BUFFER_UPDATE:
2618254885Sdumbbell		if (pkt->count != 4) {
2619254885Sdumbbell			DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (invalid count)\n");
2620254885Sdumbbell			return -EINVAL;
2621254885Sdumbbell		}
2622254885Sdumbbell		/* Updating memory at DST_ADDRESS. */
2623254885Sdumbbell		if (idx_value & 0x1) {
2624254885Sdumbbell			u64 offset;
2625254885Sdumbbell			r = evergreen_cs_packet_next_reloc(p, &reloc);
2626254885Sdumbbell			if (r) {
2627254885Sdumbbell				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing dst reloc)\n");
2628254885Sdumbbell				return -EINVAL;
2629254885Sdumbbell			}
2630254885Sdumbbell			offset = radeon_get_ib_value(p, idx+1);
2631254885Sdumbbell			offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
2632254885Sdumbbell			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
2633254885Sdumbbell				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE dst bo too small: 0x%jx, 0x%lx\n",
2634254885Sdumbbell					  (uintmax_t)offset + 4, radeon_bo_size(reloc->robj));
2635254885Sdumbbell				return -EINVAL;
2636254885Sdumbbell			}
2637254885Sdumbbell			offset += reloc->lobj.gpu_offset;
2638254885Sdumbbell			ib[idx+1] = offset;
2639254885Sdumbbell			ib[idx+2] = upper_32_bits(offset) & 0xff;
2640254885Sdumbbell		}
2641254885Sdumbbell		/* Reading data from SRC_ADDRESS. */
2642254885Sdumbbell		if (((idx_value >> 1) & 0x3) == 2) {
2643254885Sdumbbell			u64 offset;
2644254885Sdumbbell			r = evergreen_cs_packet_next_reloc(p, &reloc);
2645254885Sdumbbell			if (r) {
2646254885Sdumbbell				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE (missing src reloc)\n");
2647254885Sdumbbell				return -EINVAL;
2648254885Sdumbbell			}
2649254885Sdumbbell			offset = radeon_get_ib_value(p, idx+3);
2650254885Sdumbbell			offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
2651254885Sdumbbell			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
2652254885Sdumbbell				DRM_ERROR("bad STRMOUT_BUFFER_UPDATE src bo too small: 0x%jx, 0x%lx\n",
2653254885Sdumbbell					  (uintmax_t)offset + 4, radeon_bo_size(reloc->robj));
2654254885Sdumbbell				return -EINVAL;
2655254885Sdumbbell			}
2656254885Sdumbbell			offset += reloc->lobj.gpu_offset;
2657254885Sdumbbell			ib[idx+3] = offset;
2658254885Sdumbbell			ib[idx+4] = upper_32_bits(offset) & 0xff;
2659254885Sdumbbell		}
2660254885Sdumbbell		break;
2661254885Sdumbbell	case PACKET3_MEM_WRITE:
2662254885Sdumbbell	{
2663254885Sdumbbell		u64 offset;
2664254885Sdumbbell
2665254885Sdumbbell		if (pkt->count != 3) {
2666254885Sdumbbell			DRM_ERROR("bad MEM_WRITE (invalid count)\n");
2667254885Sdumbbell			return -EINVAL;
2668254885Sdumbbell		}
2669254885Sdumbbell		r = evergreen_cs_packet_next_reloc(p, &reloc);
2670254885Sdumbbell		if (r) {
2671254885Sdumbbell			DRM_ERROR("bad MEM_WRITE (missing reloc)\n");
2672254885Sdumbbell			return -EINVAL;
2673254885Sdumbbell		}
2674254885Sdumbbell		offset = radeon_get_ib_value(p, idx+0);
2675254885Sdumbbell		offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL;
2676254885Sdumbbell		if (offset & 0x7) {
2677254885Sdumbbell			DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n");
2678254885Sdumbbell			return -EINVAL;
2679254885Sdumbbell		}
2680254885Sdumbbell		if ((offset + 8) > radeon_bo_size(reloc->robj)) {
2681254885Sdumbbell			DRM_ERROR("bad MEM_WRITE bo too small: 0x%jx, 0x%lx\n",
2682254885Sdumbbell				  (uintmax_t)offset + 8, radeon_bo_size(reloc->robj));
2683254885Sdumbbell			return -EINVAL;
2684254885Sdumbbell		}
2685254885Sdumbbell		offset += reloc->lobj.gpu_offset;
2686254885Sdumbbell		ib[idx+0] = offset;
2687254885Sdumbbell		ib[idx+1] = upper_32_bits(offset) & 0xff;
2688254885Sdumbbell		break;
2689254885Sdumbbell	}
2690254885Sdumbbell	case PACKET3_COPY_DW:
2691254885Sdumbbell		if (pkt->count != 4) {
2692254885Sdumbbell			DRM_ERROR("bad COPY_DW (invalid count)\n");
2693254885Sdumbbell			return -EINVAL;
2694254885Sdumbbell		}
2695254885Sdumbbell		if (idx_value & 0x1) {
2696254885Sdumbbell			u64 offset;
2697254885Sdumbbell			/* SRC is memory. */
2698254885Sdumbbell			r = evergreen_cs_packet_next_reloc(p, &reloc);
2699254885Sdumbbell			if (r) {
2700254885Sdumbbell				DRM_ERROR("bad COPY_DW (missing src reloc)\n");
2701254885Sdumbbell				return -EINVAL;
2702254885Sdumbbell			}
2703254885Sdumbbell			offset = radeon_get_ib_value(p, idx+1);
2704254885Sdumbbell			offset += ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
2705254885Sdumbbell			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
2706254885Sdumbbell				DRM_ERROR("bad COPY_DW src bo too small: 0x%jx, 0x%lx\n",
2707254885Sdumbbell					  (uintmax_t)offset + 4, radeon_bo_size(reloc->robj));
2708254885Sdumbbell				return -EINVAL;
2709254885Sdumbbell			}
2710254885Sdumbbell			offset += reloc->lobj.gpu_offset;
2711254885Sdumbbell			ib[idx+1] = offset;
2712254885Sdumbbell			ib[idx+2] = upper_32_bits(offset) & 0xff;
2713254885Sdumbbell		} else {
2714254885Sdumbbell			/* SRC is a reg. */
2715254885Sdumbbell			reg = radeon_get_ib_value(p, idx+1) << 2;
2716254885Sdumbbell			if (!evergreen_is_safe_reg(p, reg, idx+1))
2717254885Sdumbbell				return -EINVAL;
2718254885Sdumbbell		}
2719254885Sdumbbell		if (idx_value & 0x2) {
2720254885Sdumbbell			u64 offset;
2721254885Sdumbbell			/* DST is memory. */
2722254885Sdumbbell			r = evergreen_cs_packet_next_reloc(p, &reloc);
2723254885Sdumbbell			if (r) {
2724254885Sdumbbell				DRM_ERROR("bad COPY_DW (missing dst reloc)\n");
2725254885Sdumbbell				return -EINVAL;
2726254885Sdumbbell			}
2727254885Sdumbbell			offset = radeon_get_ib_value(p, idx+3);
2728254885Sdumbbell			offset += ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
2729254885Sdumbbell			if ((offset + 4) > radeon_bo_size(reloc->robj)) {
2730254885Sdumbbell				DRM_ERROR("bad COPY_DW dst bo too small: 0x%jx, 0x%lx\n",
2731254885Sdumbbell					  (uintmax_t)offset + 4, radeon_bo_size(reloc->robj));
2732254885Sdumbbell				return -EINVAL;
2733254885Sdumbbell			}
2734254885Sdumbbell			offset += reloc->lobj.gpu_offset;
2735254885Sdumbbell			ib[idx+3] = offset;
2736254885Sdumbbell			ib[idx+4] = upper_32_bits(offset) & 0xff;
2737254885Sdumbbell		} else {
2738254885Sdumbbell			/* DST is a reg. */
2739254885Sdumbbell			reg = radeon_get_ib_value(p, idx+3) << 2;
2740254885Sdumbbell			if (!evergreen_is_safe_reg(p, reg, idx+3))
2741254885Sdumbbell				return -EINVAL;
2742254885Sdumbbell		}
2743254885Sdumbbell		break;
2744254885Sdumbbell	case PACKET3_NOP:
2745254885Sdumbbell		break;
2746254885Sdumbbell	default:
2747254885Sdumbbell		DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode);
2748254885Sdumbbell		return -EINVAL;
2749254885Sdumbbell	}
2750254885Sdumbbell	return 0;
2751254885Sdumbbell}
2752254885Sdumbbell
2753254885Sdumbbellint evergreen_cs_parse(struct radeon_cs_parser *p)
2754254885Sdumbbell{
2755254885Sdumbbell	struct radeon_cs_packet pkt;
2756254885Sdumbbell	struct evergreen_cs_track *track;
2757254885Sdumbbell	u32 tmp;
2758254885Sdumbbell	int r;
2759254885Sdumbbell
2760254885Sdumbbell	if (p->track == NULL) {
2761254885Sdumbbell		/* initialize tracker, we are in kms */
2762254885Sdumbbell		track = malloc(sizeof(*track), DRM_MEM_DRIVER, M_ZERO | M_WAITOK);
2763254885Sdumbbell		if (track == NULL)
2764254885Sdumbbell			return -ENOMEM;
2765254885Sdumbbell		evergreen_cs_track_init(track);
2766254885Sdumbbell		if (p->rdev->family >= CHIP_CAYMAN)
2767254885Sdumbbell			tmp = p->rdev->config.cayman.tile_config;
2768254885Sdumbbell		else
2769254885Sdumbbell			tmp = p->rdev->config.evergreen.tile_config;
2770254885Sdumbbell
2771254885Sdumbbell		switch (tmp & 0xf) {
2772254885Sdumbbell		case 0:
2773254885Sdumbbell			track->npipes = 1;
2774254885Sdumbbell			break;
2775254885Sdumbbell		case 1:
2776254885Sdumbbell		default:
2777254885Sdumbbell			track->npipes = 2;
2778254885Sdumbbell			break;
2779254885Sdumbbell		case 2:
2780254885Sdumbbell			track->npipes = 4;
2781254885Sdumbbell			break;
2782254885Sdumbbell		case 3:
2783254885Sdumbbell			track->npipes = 8;
2784254885Sdumbbell			break;
2785254885Sdumbbell		}
2786254885Sdumbbell
2787254885Sdumbbell		switch ((tmp & 0xf0) >> 4) {
2788254885Sdumbbell		case 0:
2789254885Sdumbbell			track->nbanks = 4;
2790254885Sdumbbell			break;
2791254885Sdumbbell		case 1:
2792254885Sdumbbell		default:
2793254885Sdumbbell			track->nbanks = 8;
2794254885Sdumbbell			break;
2795254885Sdumbbell		case 2:
2796254885Sdumbbell			track->nbanks = 16;
2797254885Sdumbbell			break;
2798254885Sdumbbell		}
2799254885Sdumbbell
2800254885Sdumbbell		switch ((tmp & 0xf00) >> 8) {
2801254885Sdumbbell		case 0:
2802254885Sdumbbell			track->group_size = 256;
2803254885Sdumbbell			break;
2804254885Sdumbbell		case 1:
2805254885Sdumbbell		default:
2806254885Sdumbbell			track->group_size = 512;
2807254885Sdumbbell			break;
2808254885Sdumbbell		}
2809254885Sdumbbell
2810254885Sdumbbell		switch ((tmp & 0xf000) >> 12) {
2811254885Sdumbbell		case 0:
2812254885Sdumbbell			track->row_size = 1;
2813254885Sdumbbell			break;
2814254885Sdumbbell		case 1:
2815254885Sdumbbell		default:
2816254885Sdumbbell			track->row_size = 2;
2817254885Sdumbbell			break;
2818254885Sdumbbell		case 2:
2819254885Sdumbbell			track->row_size = 4;
2820254885Sdumbbell			break;
2821254885Sdumbbell		}
2822254885Sdumbbell
2823254885Sdumbbell		p->track = track;
2824254885Sdumbbell	}
2825254885Sdumbbell	do {
2826254885Sdumbbell		r = evergreen_cs_packet_parse(p, &pkt, p->idx);
2827254885Sdumbbell		if (r) {
2828254885Sdumbbell			free(p->track, DRM_MEM_DRIVER);
2829254885Sdumbbell			p->track = NULL;
2830254885Sdumbbell			return r;
2831254885Sdumbbell		}
2832254885Sdumbbell		p->idx += pkt.count + 2;
2833254885Sdumbbell		switch (pkt.type) {
2834254885Sdumbbell		case PACKET_TYPE0:
2835254885Sdumbbell			r = evergreen_cs_parse_packet0(p, &pkt);
2836254885Sdumbbell			break;
2837254885Sdumbbell		case PACKET_TYPE2:
2838254885Sdumbbell			break;
2839254885Sdumbbell		case PACKET_TYPE3:
2840254885Sdumbbell			r = evergreen_packet3_check(p, &pkt);
2841254885Sdumbbell			break;
2842254885Sdumbbell		default:
2843254885Sdumbbell			DRM_ERROR("Unknown packet type %d !\n", pkt.type);
2844254885Sdumbbell			free(p->track, DRM_MEM_DRIVER);
2845254885Sdumbbell			p->track = NULL;
2846254885Sdumbbell			return -EINVAL;
2847254885Sdumbbell		}
2848254885Sdumbbell		if (r) {
2849254885Sdumbbell			free(p->track, DRM_MEM_DRIVER);
2850254885Sdumbbell			p->track = NULL;
2851254885Sdumbbell			return r;
2852254885Sdumbbell		}
2853254885Sdumbbell	} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
2854254885Sdumbbell#if 0
2855254885Sdumbbell	for (r = 0; r < p->ib.length_dw; r++) {
2856254885Sdumbbell		DRM_INFO("%05d  0x%08X\n", r, p->ib.ptr[r]);
2857254885Sdumbbell		mdelay(1);
2858254885Sdumbbell	}
2859254885Sdumbbell#endif
2860254885Sdumbbell	free(p->track, DRM_MEM_DRIVER);
2861254885Sdumbbell	p->track = NULL;
2862254885Sdumbbell	return 0;
2863254885Sdumbbell}
2864254885Sdumbbell
2865254885Sdumbbell/*
2866254885Sdumbbell *  DMA
2867254885Sdumbbell */
2868254885Sdumbbell
2869254885Sdumbbell#define GET_DMA_CMD(h) (((h) & 0xf0000000) >> 28)
2870254885Sdumbbell#define GET_DMA_COUNT(h) ((h) & 0x000fffff)
2871254885Sdumbbell#define GET_DMA_T(h) (((h) & 0x00800000) >> 23)
2872254885Sdumbbell#define GET_DMA_NEW(h) (((h) & 0x04000000) >> 26)
2873254885Sdumbbell#define GET_DMA_MISC(h) (((h) & 0x0700000) >> 20)
2874254885Sdumbbell
2875254885Sdumbbell/**
2876254885Sdumbbell * evergreen_dma_cs_parse() - parse the DMA IB
2877254885Sdumbbell * @p:		parser structure holding parsing context.
2878254885Sdumbbell *
2879254885Sdumbbell * Parses the DMA IB from the CS ioctl and updates
2880254885Sdumbbell * the GPU addresses based on the reloc information and
2881254885Sdumbbell * checks for errors. (Evergreen-Cayman)
2882254885Sdumbbell * Returns 0 for success and an error on failure.
2883254885Sdumbbell **/
2884254885Sdumbbellint evergreen_dma_cs_parse(struct radeon_cs_parser *p)
2885254885Sdumbbell{
2886254885Sdumbbell	struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx];
2887254885Sdumbbell	struct radeon_cs_reloc *src_reloc, *dst_reloc, *dst2_reloc;
2888254885Sdumbbell	u32 header, cmd, count, tiled, new_cmd, misc;
2889254885Sdumbbell	volatile u32 *ib = p->ib.ptr;
2890254885Sdumbbell	u32 idx, idx_value;
2891254885Sdumbbell	u64 src_offset, dst_offset, dst2_offset;
2892254885Sdumbbell	int r;
2893254885Sdumbbell
2894254885Sdumbbell	do {
2895254885Sdumbbell		if (p->idx >= ib_chunk->length_dw) {
2896254885Sdumbbell			DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
2897254885Sdumbbell				  p->idx, ib_chunk->length_dw);
2898254885Sdumbbell			return -EINVAL;
2899254885Sdumbbell		}
2900254885Sdumbbell		idx = p->idx;
2901254885Sdumbbell		header = radeon_get_ib_value(p, idx);
2902254885Sdumbbell		cmd = GET_DMA_CMD(header);
2903254885Sdumbbell		count = GET_DMA_COUNT(header);
2904254885Sdumbbell		tiled = GET_DMA_T(header);
2905254885Sdumbbell		new_cmd = GET_DMA_NEW(header);
2906254885Sdumbbell		misc = GET_DMA_MISC(header);
2907254885Sdumbbell
2908254885Sdumbbell		switch (cmd) {
2909254885Sdumbbell		case DMA_PACKET_WRITE:
2910254885Sdumbbell			r = r600_dma_cs_next_reloc(p, &dst_reloc);
2911254885Sdumbbell			if (r) {
2912254885Sdumbbell				DRM_ERROR("bad DMA_PACKET_WRITE\n");
2913254885Sdumbbell				return -EINVAL;
2914254885Sdumbbell			}
2915254885Sdumbbell			if (tiled) {
2916254885Sdumbbell				dst_offset = radeon_get_ib_value(p, idx+1);
2917254885Sdumbbell				dst_offset <<= 8;
2918254885Sdumbbell
2919254885Sdumbbell				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
2920254885Sdumbbell				p->idx += count + 7;
2921254885Sdumbbell			} else {
2922254885Sdumbbell				dst_offset = radeon_get_ib_value(p, idx+1);
2923254885Sdumbbell				dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
2924254885Sdumbbell
2925254885Sdumbbell				ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
2926254885Sdumbbell				ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
2927254885Sdumbbell				p->idx += count + 3;
2928254885Sdumbbell			}
2929254885Sdumbbell			if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
2930254885Sdumbbell				dev_warn(p->dev, "DMA write buffer too small (%ju %lu)\n",
2931254885Sdumbbell					 (uintmax_t)dst_offset, radeon_bo_size(dst_reloc->robj));
2932254885Sdumbbell				return -EINVAL;
2933254885Sdumbbell			}
2934254885Sdumbbell			break;
2935254885Sdumbbell		case DMA_PACKET_COPY:
2936254885Sdumbbell			r = r600_dma_cs_next_reloc(p, &src_reloc);
2937254885Sdumbbell			if (r) {
2938254885Sdumbbell				DRM_ERROR("bad DMA_PACKET_COPY\n");
2939254885Sdumbbell				return -EINVAL;
2940254885Sdumbbell			}
2941254885Sdumbbell			r = r600_dma_cs_next_reloc(p, &dst_reloc);
2942254885Sdumbbell			if (r) {
2943254885Sdumbbell				DRM_ERROR("bad DMA_PACKET_COPY\n");
2944254885Sdumbbell				return -EINVAL;
2945254885Sdumbbell			}
2946254885Sdumbbell			if (tiled) {
2947254885Sdumbbell				idx_value = radeon_get_ib_value(p, idx + 2);
2948254885Sdumbbell				if (new_cmd) {
2949254885Sdumbbell					switch (misc) {
2950254885Sdumbbell					case 0:
2951254885Sdumbbell						/* L2T, frame to fields */
2952261455Seadler						if (idx_value & (1U << 31)) {
2953254885Sdumbbell							DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n");
2954254885Sdumbbell							return -EINVAL;
2955254885Sdumbbell						}
2956254885Sdumbbell						r = r600_dma_cs_next_reloc(p, &dst2_reloc);
2957254885Sdumbbell						if (r) {
2958254885Sdumbbell							DRM_ERROR("bad L2T, frame to fields DMA_PACKET_COPY\n");
2959254885Sdumbbell							return -EINVAL;
2960254885Sdumbbell						}
2961254885Sdumbbell						dst_offset = radeon_get_ib_value(p, idx+1);
2962254885Sdumbbell						dst_offset <<= 8;
2963254885Sdumbbell						dst2_offset = radeon_get_ib_value(p, idx+2);
2964254885Sdumbbell						dst2_offset <<= 8;
2965254885Sdumbbell						src_offset = radeon_get_ib_value(p, idx+8);
2966254885Sdumbbell						src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
2967254885Sdumbbell						if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
2968254885Sdumbbell							dev_warn(p->dev, "DMA L2T, frame to fields src buffer too small (%ju %lu)\n",
2969254885Sdumbbell								 (uintmax_t)src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
2970254885Sdumbbell							return -EINVAL;
2971254885Sdumbbell						}
2972254885Sdumbbell						if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
2973254885Sdumbbell							dev_warn(p->dev, "DMA L2T, frame to fields buffer too small (%ju %lu)\n",
2974254885Sdumbbell								 (uintmax_t)dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
2975254885Sdumbbell							return -EINVAL;
2976254885Sdumbbell						}
2977254885Sdumbbell						if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) {
2978254885Sdumbbell							dev_warn(p->dev, "DMA L2T, frame to fields buffer too small (%ju %lu)\n",
2979254885Sdumbbell								 (uintmax_t)dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));
2980254885Sdumbbell							return -EINVAL;
2981254885Sdumbbell						}
2982254885Sdumbbell						ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
2983254885Sdumbbell						ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8);
2984254885Sdumbbell						ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
2985254885Sdumbbell						ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
2986254885Sdumbbell						p->idx += 10;
2987254885Sdumbbell						break;
2988254885Sdumbbell					case 1:
2989254885Sdumbbell						/* L2T, T2L partial */
2990254885Sdumbbell						if (p->family < CHIP_CAYMAN) {
2991254885Sdumbbell							DRM_ERROR("L2T, T2L Partial is cayman only !\n");
2992254885Sdumbbell							return -EINVAL;
2993254885Sdumbbell						}
2994254885Sdumbbell						/* detile bit */
2995261455Seadler						if (idx_value & (1U << 31)) {
2996254885Sdumbbell							/* tiled src, linear dst */
2997254885Sdumbbell							ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
2998254885Sdumbbell
2999254885Sdumbbell							ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
3000254885Sdumbbell							ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
3001254885Sdumbbell						} else {
3002254885Sdumbbell							/* linear src, tiled dst */
3003254885Sdumbbell							ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
3004254885Sdumbbell							ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
3005254885Sdumbbell
3006254885Sdumbbell							ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
3007254885Sdumbbell						}
3008254885Sdumbbell						p->idx += 12;
3009254885Sdumbbell						break;
3010254885Sdumbbell					case 3:
3011254885Sdumbbell						/* L2T, broadcast */
3012261455Seadler						if (idx_value & (1U << 31)) {
3013254885Sdumbbell							DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
3014254885Sdumbbell							return -EINVAL;
3015254885Sdumbbell						}
3016254885Sdumbbell						r = r600_dma_cs_next_reloc(p, &dst2_reloc);
3017254885Sdumbbell						if (r) {
3018254885Sdumbbell							DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
3019254885Sdumbbell							return -EINVAL;
3020254885Sdumbbell						}
3021254885Sdumbbell						dst_offset = radeon_get_ib_value(p, idx+1);
3022254885Sdumbbell						dst_offset <<= 8;
3023254885Sdumbbell						dst2_offset = radeon_get_ib_value(p, idx+2);
3024254885Sdumbbell						dst2_offset <<= 8;
3025254885Sdumbbell						src_offset = radeon_get_ib_value(p, idx+8);
3026254885Sdumbbell						src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
3027254885Sdumbbell						if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
3028254885Sdumbbell							dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%ju %lu)\n",
3029254885Sdumbbell								 (uintmax_t)src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
3030254885Sdumbbell							return -EINVAL;
3031254885Sdumbbell						}
3032254885Sdumbbell						if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
3033254885Sdumbbell							dev_warn(p->dev, "DMA L2T, broadcast dst buffer too small (%ju %lu)\n",
3034254885Sdumbbell								 (uintmax_t)dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
3035254885Sdumbbell							return -EINVAL;
3036254885Sdumbbell						}
3037254885Sdumbbell						if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) {
3038254885Sdumbbell							dev_warn(p->dev, "DMA L2T, broadcast dst2 buffer too small (%ju %lu)\n",
3039254885Sdumbbell								 (uintmax_t)dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));
3040254885Sdumbbell							return -EINVAL;
3041254885Sdumbbell						}
3042254885Sdumbbell						ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
3043254885Sdumbbell						ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8);
3044254885Sdumbbell						ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
3045254885Sdumbbell						ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
3046254885Sdumbbell						p->idx += 10;
3047254885Sdumbbell						break;
3048254885Sdumbbell					case 4:
3049254885Sdumbbell						/* L2T, T2L */
3050254885Sdumbbell						/* detile bit */
3051261455Seadler						if (idx_value & (1U << 31)) {
3052254885Sdumbbell							/* tiled src, linear dst */
3053254885Sdumbbell							src_offset = radeon_get_ib_value(p, idx+1);
3054254885Sdumbbell							src_offset <<= 8;
3055254885Sdumbbell							ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
3056254885Sdumbbell
3057254885Sdumbbell							dst_offset = radeon_get_ib_value(p, idx+7);
3058254885Sdumbbell							dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
3059254885Sdumbbell							ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
3060254885Sdumbbell							ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
3061254885Sdumbbell						} else {
3062254885Sdumbbell							/* linear src, tiled dst */
3063254885Sdumbbell							src_offset = radeon_get_ib_value(p, idx+7);
3064254885Sdumbbell							src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
3065254885Sdumbbell							ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
3066254885Sdumbbell							ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
3067254885Sdumbbell
3068254885Sdumbbell							dst_offset = radeon_get_ib_value(p, idx+1);
3069254885Sdumbbell							dst_offset <<= 8;
3070254885Sdumbbell							ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
3071254885Sdumbbell						}
3072254885Sdumbbell						if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
3073254885Sdumbbell							dev_warn(p->dev, "DMA L2T, T2L src buffer too small (%ju %lu)\n",
3074254885Sdumbbell								 (uintmax_t)src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
3075254885Sdumbbell							return -EINVAL;
3076254885Sdumbbell						}
3077254885Sdumbbell						if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
3078254885Sdumbbell							dev_warn(p->dev, "DMA L2T, T2L dst buffer too small (%ju %lu)\n",
3079254885Sdumbbell								 (uintmax_t)dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
3080254885Sdumbbell							return -EINVAL;
3081254885Sdumbbell						}
3082254885Sdumbbell						p->idx += 9;
3083254885Sdumbbell						break;
3084254885Sdumbbell					case 5:
3085254885Sdumbbell						/* T2T partial */
3086254885Sdumbbell						if (p->family < CHIP_CAYMAN) {
3087254885Sdumbbell							DRM_ERROR("L2T, T2L Partial is cayman only !\n");
3088254885Sdumbbell							return -EINVAL;
3089254885Sdumbbell						}
3090254885Sdumbbell						ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
3091254885Sdumbbell						ib[idx+4] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
3092254885Sdumbbell						p->idx += 13;
3093254885Sdumbbell						break;
3094254885Sdumbbell					case 7:
3095254885Sdumbbell						/* L2T, broadcast */
3096261455Seadler						if (idx_value & (1U << 31)) {
3097254885Sdumbbell							DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
3098254885Sdumbbell							return -EINVAL;
3099254885Sdumbbell						}
3100254885Sdumbbell						r = r600_dma_cs_next_reloc(p, &dst2_reloc);
3101254885Sdumbbell						if (r) {
3102254885Sdumbbell							DRM_ERROR("bad L2T, broadcast DMA_PACKET_COPY\n");
3103254885Sdumbbell							return -EINVAL;
3104254885Sdumbbell						}
3105254885Sdumbbell						dst_offset = radeon_get_ib_value(p, idx+1);
3106254885Sdumbbell						dst_offset <<= 8;
3107254885Sdumbbell						dst2_offset = radeon_get_ib_value(p, idx+2);
3108254885Sdumbbell						dst2_offset <<= 8;
3109254885Sdumbbell						src_offset = radeon_get_ib_value(p, idx+8);
3110254885Sdumbbell						src_offset |= ((u64)(radeon_get_ib_value(p, idx+9) & 0xff)) << 32;
3111254885Sdumbbell						if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
3112254885Sdumbbell							dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%ju %lu)\n",
3113254885Sdumbbell								 (uintmax_t)src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
3114254885Sdumbbell							return -EINVAL;
3115254885Sdumbbell						}
3116254885Sdumbbell						if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
3117254885Sdumbbell							dev_warn(p->dev, "DMA L2T, broadcast dst buffer too small (%ju %lu)\n",
3118254885Sdumbbell								 (uintmax_t)dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
3119254885Sdumbbell							return -EINVAL;
3120254885Sdumbbell						}
3121254885Sdumbbell						if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) {
3122254885Sdumbbell							dev_warn(p->dev, "DMA L2T, broadcast dst2 buffer too small (%ju %lu)\n",
3123254885Sdumbbell								 (uintmax_t)dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));
3124254885Sdumbbell							return -EINVAL;
3125254885Sdumbbell						}
3126254885Sdumbbell						ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
3127254885Sdumbbell						ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8);
3128254885Sdumbbell						ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
3129254885Sdumbbell						ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
3130254885Sdumbbell						p->idx += 10;
3131254885Sdumbbell						break;
3132254885Sdumbbell					default:
3133254885Sdumbbell						DRM_ERROR("bad DMA_PACKET_COPY misc %u\n", misc);
3134254885Sdumbbell						return -EINVAL;
3135254885Sdumbbell					}
3136254885Sdumbbell				} else {
3137254885Sdumbbell					switch (misc) {
3138254885Sdumbbell					case 0:
3139254885Sdumbbell						/* detile bit */
3140261455Seadler						if (idx_value & (1U << 31)) {
3141254885Sdumbbell							/* tiled src, linear dst */
3142254885Sdumbbell							src_offset = radeon_get_ib_value(p, idx+1);
3143254885Sdumbbell							src_offset <<= 8;
3144254885Sdumbbell							ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
3145254885Sdumbbell
3146254885Sdumbbell							dst_offset = radeon_get_ib_value(p, idx+7);
3147254885Sdumbbell							dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
3148254885Sdumbbell							ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
3149254885Sdumbbell							ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
3150254885Sdumbbell						} else {
3151254885Sdumbbell							/* linear src, tiled dst */
3152254885Sdumbbell							src_offset = radeon_get_ib_value(p, idx+7);
3153254885Sdumbbell							src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
3154254885Sdumbbell							ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
3155254885Sdumbbell							ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
3156254885Sdumbbell
3157254885Sdumbbell							dst_offset = radeon_get_ib_value(p, idx+1);
3158254885Sdumbbell							dst_offset <<= 8;
3159254885Sdumbbell							ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
3160254885Sdumbbell						}
3161254885Sdumbbell						if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
3162254885Sdumbbell							dev_warn(p->dev, "DMA L2T, broadcast src buffer too small (%ju %lu)\n",
3163254885Sdumbbell								 (uintmax_t)src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
3164254885Sdumbbell							return -EINVAL;
3165254885Sdumbbell						}
3166254885Sdumbbell						if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
3167254885Sdumbbell							dev_warn(p->dev, "DMA L2T, broadcast dst buffer too small (%ju %lu)\n",
3168254885Sdumbbell								 (uintmax_t)dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
3169254885Sdumbbell							return -EINVAL;
3170254885Sdumbbell						}
3171254885Sdumbbell						p->idx += 9;
3172254885Sdumbbell						break;
3173254885Sdumbbell					default:
3174254885Sdumbbell						DRM_ERROR("bad DMA_PACKET_COPY misc %u\n", misc);
3175254885Sdumbbell						return -EINVAL;
3176254885Sdumbbell					}
3177254885Sdumbbell				}
3178254885Sdumbbell			} else {
3179254885Sdumbbell				if (new_cmd) {
3180254885Sdumbbell					switch (misc) {
3181254885Sdumbbell					case 0:
3182254885Sdumbbell						/* L2L, byte */
3183254885Sdumbbell						src_offset = radeon_get_ib_value(p, idx+2);
3184254885Sdumbbell						src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
3185254885Sdumbbell						dst_offset = radeon_get_ib_value(p, idx+1);
3186254885Sdumbbell						dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
3187254885Sdumbbell						if ((src_offset + count) > radeon_bo_size(src_reloc->robj)) {
3188254885Sdumbbell							dev_warn(p->dev, "DMA L2L, byte src buffer too small (%ju %lu)\n",
3189254885Sdumbbell								 (uintmax_t)src_offset + count, radeon_bo_size(src_reloc->robj));
3190254885Sdumbbell							return -EINVAL;
3191254885Sdumbbell						}
3192254885Sdumbbell						if ((dst_offset + count) > radeon_bo_size(dst_reloc->robj)) {
3193254885Sdumbbell							dev_warn(p->dev, "DMA L2L, byte dst buffer too small (%ju %lu)\n",
3194254885Sdumbbell								 (uintmax_t)dst_offset + count, radeon_bo_size(dst_reloc->robj));
3195254885Sdumbbell							return -EINVAL;
3196254885Sdumbbell						}
3197254885Sdumbbell						ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xffffffff);
3198254885Sdumbbell						ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xffffffff);
3199254885Sdumbbell						ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
3200254885Sdumbbell						ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
3201254885Sdumbbell						p->idx += 5;
3202254885Sdumbbell						break;
3203254885Sdumbbell					case 1:
3204254885Sdumbbell						/* L2L, partial */
3205254885Sdumbbell						if (p->family < CHIP_CAYMAN) {
3206254885Sdumbbell							DRM_ERROR("L2L Partial is cayman only !\n");
3207254885Sdumbbell							return -EINVAL;
3208254885Sdumbbell						}
3209254885Sdumbbell						ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset & 0xffffffff);
3210254885Sdumbbell						ib[idx+2] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
3211254885Sdumbbell						ib[idx+4] += (u32)(dst_reloc->lobj.gpu_offset & 0xffffffff);
3212254885Sdumbbell						ib[idx+5] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
3213254885Sdumbbell
3214254885Sdumbbell						p->idx += 9;
3215254885Sdumbbell						break;
3216254885Sdumbbell					case 4:
3217254885Sdumbbell						/* L2L, dw, broadcast */
3218254885Sdumbbell						r = r600_dma_cs_next_reloc(p, &dst2_reloc);
3219254885Sdumbbell						if (r) {
3220254885Sdumbbell							DRM_ERROR("bad L2L, dw, broadcast DMA_PACKET_COPY\n");
3221254885Sdumbbell							return -EINVAL;
3222254885Sdumbbell						}
3223254885Sdumbbell						dst_offset = radeon_get_ib_value(p, idx+1);
3224254885Sdumbbell						dst_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
3225254885Sdumbbell						dst2_offset = radeon_get_ib_value(p, idx+2);
3226254885Sdumbbell						dst2_offset |= ((u64)(radeon_get_ib_value(p, idx+5) & 0xff)) << 32;
3227254885Sdumbbell						src_offset = radeon_get_ib_value(p, idx+3);
3228254885Sdumbbell						src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
3229254885Sdumbbell						if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
3230254885Sdumbbell							dev_warn(p->dev, "DMA L2L, dw, broadcast src buffer too small (%ju %lu)\n",
3231254885Sdumbbell								 (uintmax_t)src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
3232254885Sdumbbell							return -EINVAL;
3233254885Sdumbbell						}
3234254885Sdumbbell						if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
3235254885Sdumbbell							dev_warn(p->dev, "DMA L2L, dw, broadcast dst buffer too small (%ju %lu)\n",
3236254885Sdumbbell								 (uintmax_t)dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
3237254885Sdumbbell							return -EINVAL;
3238254885Sdumbbell						}
3239254885Sdumbbell						if ((dst2_offset + (count * 4)) > radeon_bo_size(dst2_reloc->robj)) {
3240254885Sdumbbell							dev_warn(p->dev, "DMA L2L, dw, broadcast dst2 buffer too small (%ju %lu)\n",
3241254885Sdumbbell								 (uintmax_t)dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));
3242254885Sdumbbell							return -EINVAL;
3243254885Sdumbbell						}
3244254885Sdumbbell						ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
3245254885Sdumbbell						ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset & 0xfffffffc);
3246254885Sdumbbell						ib[idx+3] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
3247254885Sdumbbell						ib[idx+4] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
3248254885Sdumbbell						ib[idx+5] += upper_32_bits(dst2_reloc->lobj.gpu_offset) & 0xff;
3249254885Sdumbbell						ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
3250254885Sdumbbell						p->idx += 7;
3251254885Sdumbbell						break;
3252254885Sdumbbell					default:
3253254885Sdumbbell						DRM_ERROR("bad DMA_PACKET_COPY misc %u\n", misc);
3254254885Sdumbbell						return -EINVAL;
3255254885Sdumbbell					}
3256254885Sdumbbell				} else {
3257254885Sdumbbell					/* L2L, dw */
3258254885Sdumbbell					src_offset = radeon_get_ib_value(p, idx+2);
3259254885Sdumbbell					src_offset |= ((u64)(radeon_get_ib_value(p, idx+4) & 0xff)) << 32;
3260254885Sdumbbell					dst_offset = radeon_get_ib_value(p, idx+1);
3261254885Sdumbbell					dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
3262254885Sdumbbell					if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
3263254885Sdumbbell						dev_warn(p->dev, "DMA L2L, dw src buffer too small (%ju %lu)\n",
3264254885Sdumbbell							 (uintmax_t)src_offset + (count * 4), radeon_bo_size(src_reloc->robj));
3265254885Sdumbbell						return -EINVAL;
3266254885Sdumbbell					}
3267254885Sdumbbell					if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
3268254885Sdumbbell						dev_warn(p->dev, "DMA L2L, dw dst buffer too small (%ju %lu)\n",
3269254885Sdumbbell							 (uintmax_t)dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
3270254885Sdumbbell						return -EINVAL;
3271254885Sdumbbell					}
3272254885Sdumbbell					ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
3273254885Sdumbbell					ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
3274254885Sdumbbell					ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
3275254885Sdumbbell					ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
3276254885Sdumbbell					p->idx += 5;
3277254885Sdumbbell				}
3278254885Sdumbbell			}
3279254885Sdumbbell			break;
3280254885Sdumbbell		case DMA_PACKET_CONSTANT_FILL:
3281254885Sdumbbell			r = r600_dma_cs_next_reloc(p, &dst_reloc);
3282254885Sdumbbell			if (r) {
3283254885Sdumbbell				DRM_ERROR("bad DMA_PACKET_CONSTANT_FILL\n");
3284254885Sdumbbell				return -EINVAL;
3285254885Sdumbbell			}
3286254885Sdumbbell			dst_offset = radeon_get_ib_value(p, idx+1);
3287254885Sdumbbell			dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0x00ff0000)) << 16;
3288254885Sdumbbell			if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
3289254885Sdumbbell				dev_warn(p->dev, "DMA constant fill buffer too small (%ju %lu)\n",
3290254885Sdumbbell					 (uintmax_t)dst_offset, radeon_bo_size(dst_reloc->robj));
3291254885Sdumbbell				return -EINVAL;
3292254885Sdumbbell			}
3293254885Sdumbbell			ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
3294254885Sdumbbell			ib[idx+3] += (upper_32_bits(dst_reloc->lobj.gpu_offset) << 16) & 0x00ff0000;
3295254885Sdumbbell			p->idx += 4;
3296254885Sdumbbell			break;
3297254885Sdumbbell		case DMA_PACKET_NOP:
3298254885Sdumbbell			p->idx += 1;
3299254885Sdumbbell			break;
3300254885Sdumbbell		default:
3301254885Sdumbbell			DRM_ERROR("Unknown packet type %d at %d !\n", cmd, idx);
3302254885Sdumbbell			return -EINVAL;
3303254885Sdumbbell		}
3304254885Sdumbbell	} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
3305254885Sdumbbell#if 0
3306254885Sdumbbell	for (r = 0; r < p->ib->length_dw; r++) {
3307254885Sdumbbell		DRM_INFO("%05d  0x%08X\n", r, p->ib.ptr[r]);
3308254885Sdumbbell		mdelay(1);
3309254885Sdumbbell	}
3310254885Sdumbbell#endif
3311254885Sdumbbell	return 0;
3312254885Sdumbbell}
3313254885Sdumbbell
3314254885Sdumbbell/* vm parser */
3315254885Sdumbbellstatic bool evergreen_vm_reg_valid(u32 reg)
3316254885Sdumbbell{
3317254885Sdumbbell	/* context regs are fine */
3318254885Sdumbbell	if (reg >= 0x28000)
3319254885Sdumbbell		return true;
3320254885Sdumbbell
3321254885Sdumbbell	/* check config regs */
3322254885Sdumbbell	switch (reg) {
3323254885Sdumbbell	case WAIT_UNTIL:
3324254885Sdumbbell	case GRBM_GFX_INDEX:
3325254885Sdumbbell	case CP_STRMOUT_CNTL:
3326254885Sdumbbell	case CP_COHER_CNTL:
3327254885Sdumbbell	case CP_COHER_SIZE:
3328254885Sdumbbell	case VGT_VTX_VECT_EJECT_REG:
3329254885Sdumbbell	case VGT_CACHE_INVALIDATION:
3330254885Sdumbbell	case VGT_GS_VERTEX_REUSE:
3331254885Sdumbbell	case VGT_PRIMITIVE_TYPE:
3332254885Sdumbbell	case VGT_INDEX_TYPE:
3333254885Sdumbbell	case VGT_NUM_INDICES:
3334254885Sdumbbell	case VGT_NUM_INSTANCES:
3335254885Sdumbbell	case VGT_COMPUTE_DIM_X:
3336254885Sdumbbell	case VGT_COMPUTE_DIM_Y:
3337254885Sdumbbell	case VGT_COMPUTE_DIM_Z:
3338254885Sdumbbell	case VGT_COMPUTE_START_X:
3339254885Sdumbbell	case VGT_COMPUTE_START_Y:
3340254885Sdumbbell	case VGT_COMPUTE_START_Z:
3341254885Sdumbbell	case VGT_COMPUTE_INDEX:
3342254885Sdumbbell	case VGT_COMPUTE_THREAD_GROUP_SIZE:
3343254885Sdumbbell	case VGT_HS_OFFCHIP_PARAM:
3344254885Sdumbbell	case PA_CL_ENHANCE:
3345254885Sdumbbell	case PA_SU_LINE_STIPPLE_VALUE:
3346254885Sdumbbell	case PA_SC_LINE_STIPPLE_STATE:
3347254885Sdumbbell	case PA_SC_ENHANCE:
3348254885Sdumbbell	case SQ_DYN_GPR_CNTL_PS_FLUSH_REQ:
3349254885Sdumbbell	case SQ_DYN_GPR_SIMD_LOCK_EN:
3350254885Sdumbbell	case SQ_CONFIG:
3351254885Sdumbbell	case SQ_GPR_RESOURCE_MGMT_1:
3352254885Sdumbbell	case SQ_GLOBAL_GPR_RESOURCE_MGMT_1:
3353254885Sdumbbell	case SQ_GLOBAL_GPR_RESOURCE_MGMT_2:
3354254885Sdumbbell	case SQ_CONST_MEM_BASE:
3355254885Sdumbbell	case SQ_STATIC_THREAD_MGMT_1:
3356254885Sdumbbell	case SQ_STATIC_THREAD_MGMT_2:
3357254885Sdumbbell	case SQ_STATIC_THREAD_MGMT_3:
3358254885Sdumbbell	case SPI_CONFIG_CNTL:
3359254885Sdumbbell	case SPI_CONFIG_CNTL_1:
3360254885Sdumbbell	case TA_CNTL_AUX:
3361254885Sdumbbell	case DB_DEBUG:
3362254885Sdumbbell	case DB_DEBUG2:
3363254885Sdumbbell	case DB_DEBUG3:
3364254885Sdumbbell	case DB_DEBUG4:
3365254885Sdumbbell	case DB_WATERMARKS:
3366254885Sdumbbell	case TD_PS_BORDER_COLOR_INDEX:
3367254885Sdumbbell	case TD_PS_BORDER_COLOR_RED:
3368254885Sdumbbell	case TD_PS_BORDER_COLOR_GREEN:
3369254885Sdumbbell	case TD_PS_BORDER_COLOR_BLUE:
3370254885Sdumbbell	case TD_PS_BORDER_COLOR_ALPHA:
3371254885Sdumbbell	case TD_VS_BORDER_COLOR_INDEX:
3372254885Sdumbbell	case TD_VS_BORDER_COLOR_RED:
3373254885Sdumbbell	case TD_VS_BORDER_COLOR_GREEN:
3374254885Sdumbbell	case TD_VS_BORDER_COLOR_BLUE:
3375254885Sdumbbell	case TD_VS_BORDER_COLOR_ALPHA:
3376254885Sdumbbell	case TD_GS_BORDER_COLOR_INDEX:
3377254885Sdumbbell	case TD_GS_BORDER_COLOR_RED:
3378254885Sdumbbell	case TD_GS_BORDER_COLOR_GREEN:
3379254885Sdumbbell	case TD_GS_BORDER_COLOR_BLUE:
3380254885Sdumbbell	case TD_GS_BORDER_COLOR_ALPHA:
3381254885Sdumbbell	case TD_HS_BORDER_COLOR_INDEX:
3382254885Sdumbbell	case TD_HS_BORDER_COLOR_RED:
3383254885Sdumbbell	case TD_HS_BORDER_COLOR_GREEN:
3384254885Sdumbbell	case TD_HS_BORDER_COLOR_BLUE:
3385254885Sdumbbell	case TD_HS_BORDER_COLOR_ALPHA:
3386254885Sdumbbell	case TD_LS_BORDER_COLOR_INDEX:
3387254885Sdumbbell	case TD_LS_BORDER_COLOR_RED:
3388254885Sdumbbell	case TD_LS_BORDER_COLOR_GREEN:
3389254885Sdumbbell	case TD_LS_BORDER_COLOR_BLUE:
3390254885Sdumbbell	case TD_LS_BORDER_COLOR_ALPHA:
3391254885Sdumbbell	case TD_CS_BORDER_COLOR_INDEX:
3392254885Sdumbbell	case TD_CS_BORDER_COLOR_RED:
3393254885Sdumbbell	case TD_CS_BORDER_COLOR_GREEN:
3394254885Sdumbbell	case TD_CS_BORDER_COLOR_BLUE:
3395254885Sdumbbell	case TD_CS_BORDER_COLOR_ALPHA:
3396254885Sdumbbell	case SQ_ESGS_RING_SIZE:
3397254885Sdumbbell	case SQ_GSVS_RING_SIZE:
3398254885Sdumbbell	case SQ_ESTMP_RING_SIZE:
3399254885Sdumbbell	case SQ_GSTMP_RING_SIZE:
3400254885Sdumbbell	case SQ_HSTMP_RING_SIZE:
3401254885Sdumbbell	case SQ_LSTMP_RING_SIZE:
3402254885Sdumbbell	case SQ_PSTMP_RING_SIZE:
3403254885Sdumbbell	case SQ_VSTMP_RING_SIZE:
3404254885Sdumbbell	case SQ_ESGS_RING_ITEMSIZE:
3405254885Sdumbbell	case SQ_ESTMP_RING_ITEMSIZE:
3406254885Sdumbbell	case SQ_GSTMP_RING_ITEMSIZE:
3407254885Sdumbbell	case SQ_GSVS_RING_ITEMSIZE:
3408254885Sdumbbell	case SQ_GS_VERT_ITEMSIZE:
3409254885Sdumbbell	case SQ_GS_VERT_ITEMSIZE_1:
3410254885Sdumbbell	case SQ_GS_VERT_ITEMSIZE_2:
3411254885Sdumbbell	case SQ_GS_VERT_ITEMSIZE_3:
3412254885Sdumbbell	case SQ_GSVS_RING_OFFSET_1:
3413254885Sdumbbell	case SQ_GSVS_RING_OFFSET_2:
3414254885Sdumbbell	case SQ_GSVS_RING_OFFSET_3:
3415254885Sdumbbell	case SQ_HSTMP_RING_ITEMSIZE:
3416254885Sdumbbell	case SQ_LSTMP_RING_ITEMSIZE:
3417254885Sdumbbell	case SQ_PSTMP_RING_ITEMSIZE:
3418254885Sdumbbell	case SQ_VSTMP_RING_ITEMSIZE:
3419254885Sdumbbell	case VGT_TF_RING_SIZE:
3420254885Sdumbbell	case SQ_ESGS_RING_BASE:
3421254885Sdumbbell	case SQ_GSVS_RING_BASE:
3422254885Sdumbbell	case SQ_ESTMP_RING_BASE:
3423254885Sdumbbell	case SQ_GSTMP_RING_BASE:
3424254885Sdumbbell	case SQ_HSTMP_RING_BASE:
3425254885Sdumbbell	case SQ_LSTMP_RING_BASE:
3426254885Sdumbbell	case SQ_PSTMP_RING_BASE:
3427254885Sdumbbell	case SQ_VSTMP_RING_BASE:
3428254885Sdumbbell	case CAYMAN_VGT_OFFCHIP_LDS_BASE:
3429254885Sdumbbell	case CAYMAN_SQ_EX_ALLOC_TABLE_SLOTS:
3430254885Sdumbbell		return true;
3431254885Sdumbbell	default:
3432254885Sdumbbell		DRM_ERROR("Invalid register 0x%x in CS\n", reg);
3433254885Sdumbbell		return false;
3434254885Sdumbbell	}
3435254885Sdumbbell}
3436254885Sdumbbell
3437254885Sdumbbellstatic int evergreen_vm_packet3_check(struct radeon_device *rdev,
3438254885Sdumbbell				      u32 *ib, struct radeon_cs_packet *pkt)
3439254885Sdumbbell{
3440254885Sdumbbell	u32 idx = pkt->idx + 1;
3441254885Sdumbbell	u32 idx_value = ib[idx];
3442254885Sdumbbell	u32 start_reg, end_reg, reg, i;
3443254885Sdumbbell	u32 command, info;
3444254885Sdumbbell
3445254885Sdumbbell	switch (pkt->opcode) {
3446254885Sdumbbell	case PACKET3_NOP:
3447254885Sdumbbell	case PACKET3_SET_BASE:
3448254885Sdumbbell	case PACKET3_CLEAR_STATE:
3449254885Sdumbbell	case PACKET3_INDEX_BUFFER_SIZE:
3450254885Sdumbbell	case PACKET3_DISPATCH_DIRECT:
3451254885Sdumbbell	case PACKET3_DISPATCH_INDIRECT:
3452254885Sdumbbell	case PACKET3_MODE_CONTROL:
3453254885Sdumbbell	case PACKET3_SET_PREDICATION:
3454254885Sdumbbell	case PACKET3_COND_EXEC:
3455254885Sdumbbell	case PACKET3_PRED_EXEC:
3456254885Sdumbbell	case PACKET3_DRAW_INDIRECT:
3457254885Sdumbbell	case PACKET3_DRAW_INDEX_INDIRECT:
3458254885Sdumbbell	case PACKET3_INDEX_BASE:
3459254885Sdumbbell	case PACKET3_DRAW_INDEX_2:
3460254885Sdumbbell	case PACKET3_CONTEXT_CONTROL:
3461254885Sdumbbell	case PACKET3_DRAW_INDEX_OFFSET:
3462254885Sdumbbell	case PACKET3_INDEX_TYPE:
3463254885Sdumbbell	case PACKET3_DRAW_INDEX:
3464254885Sdumbbell	case PACKET3_DRAW_INDEX_AUTO:
3465254885Sdumbbell	case PACKET3_DRAW_INDEX_IMMD:
3466254885Sdumbbell	case PACKET3_NUM_INSTANCES:
3467254885Sdumbbell	case PACKET3_DRAW_INDEX_MULTI_AUTO:
3468254885Sdumbbell	case PACKET3_STRMOUT_BUFFER_UPDATE:
3469254885Sdumbbell	case PACKET3_DRAW_INDEX_OFFSET_2:
3470254885Sdumbbell	case PACKET3_DRAW_INDEX_MULTI_ELEMENT:
3471254885Sdumbbell	case PACKET3_MPEG_INDEX:
3472254885Sdumbbell	case PACKET3_WAIT_REG_MEM:
3473254885Sdumbbell	case PACKET3_MEM_WRITE:
3474254885Sdumbbell	case PACKET3_SURFACE_SYNC:
3475254885Sdumbbell	case PACKET3_EVENT_WRITE:
3476254885Sdumbbell	case PACKET3_EVENT_WRITE_EOP:
3477254885Sdumbbell	case PACKET3_EVENT_WRITE_EOS:
3478254885Sdumbbell	case PACKET3_SET_CONTEXT_REG:
3479254885Sdumbbell	case PACKET3_SET_BOOL_CONST:
3480254885Sdumbbell	case PACKET3_SET_LOOP_CONST:
3481254885Sdumbbell	case PACKET3_SET_RESOURCE:
3482254885Sdumbbell	case PACKET3_SET_SAMPLER:
3483254885Sdumbbell	case PACKET3_SET_CTL_CONST:
3484254885Sdumbbell	case PACKET3_SET_RESOURCE_OFFSET:
3485254885Sdumbbell	case PACKET3_SET_CONTEXT_REG_INDIRECT:
3486254885Sdumbbell	case PACKET3_SET_RESOURCE_INDIRECT:
3487254885Sdumbbell	case CAYMAN_PACKET3_DEALLOC_STATE:
3488254885Sdumbbell		break;
3489254885Sdumbbell	case PACKET3_COND_WRITE:
3490254885Sdumbbell		if (idx_value & 0x100) {
3491254885Sdumbbell			reg = ib[idx + 5] * 4;
3492254885Sdumbbell			if (!evergreen_vm_reg_valid(reg))
3493254885Sdumbbell				return -EINVAL;
3494254885Sdumbbell		}
3495254885Sdumbbell		break;
3496254885Sdumbbell	case PACKET3_COPY_DW:
3497254885Sdumbbell		if (idx_value & 0x2) {
3498254885Sdumbbell			reg = ib[idx + 3] * 4;
3499254885Sdumbbell			if (!evergreen_vm_reg_valid(reg))
3500254885Sdumbbell				return -EINVAL;
3501254885Sdumbbell		}
3502254885Sdumbbell		break;
3503254885Sdumbbell	case PACKET3_SET_CONFIG_REG:
3504254885Sdumbbell		start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_START;
3505254885Sdumbbell		end_reg = 4 * pkt->count + start_reg - 4;
3506254885Sdumbbell		if ((start_reg < PACKET3_SET_CONFIG_REG_START) ||
3507254885Sdumbbell		    (start_reg >= PACKET3_SET_CONFIG_REG_END) ||
3508254885Sdumbbell		    (end_reg >= PACKET3_SET_CONFIG_REG_END)) {
3509254885Sdumbbell			DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n");
3510254885Sdumbbell			return -EINVAL;
3511254885Sdumbbell		}
3512254885Sdumbbell		for (i = 0; i < pkt->count; i++) {
3513254885Sdumbbell			reg = start_reg + (4 * i);
3514254885Sdumbbell			if (!evergreen_vm_reg_valid(reg))
3515254885Sdumbbell				return -EINVAL;
3516254885Sdumbbell		}
3517254885Sdumbbell		break;
3518254885Sdumbbell	case PACKET3_CP_DMA:
3519254885Sdumbbell		command = ib[idx + 4];
3520254885Sdumbbell		info = ib[idx + 1];
3521254885Sdumbbell		if ((((info & 0x60000000) >> 29) != 0) || /* src = GDS or DATA */
3522254885Sdumbbell		    (((info & 0x00300000) >> 20) != 0) || /* dst = GDS */
3523254885Sdumbbell		    ((((info & 0x00300000) >> 20) == 0) &&
3524254885Sdumbbell		     (command & PACKET3_CP_DMA_CMD_DAS)) || /* dst = register */
3525254885Sdumbbell		    ((((info & 0x60000000) >> 29) == 0) &&
3526254885Sdumbbell		     (command & PACKET3_CP_DMA_CMD_SAS))) { /* src = register */
3527254885Sdumbbell			/* non mem to mem copies requires dw aligned count */
3528254885Sdumbbell			if ((command & 0x1fffff) % 4) {
3529254885Sdumbbell				DRM_ERROR("CP DMA command requires dw count alignment\n");
3530254885Sdumbbell				return -EINVAL;
3531254885Sdumbbell			}
3532254885Sdumbbell		}
3533254885Sdumbbell		if (command & PACKET3_CP_DMA_CMD_SAS) {
3534254885Sdumbbell			/* src address space is register */
3535254885Sdumbbell			if (((info & 0x60000000) >> 29) == 0) {
3536254885Sdumbbell				start_reg = idx_value << 2;
3537254885Sdumbbell				if (command & PACKET3_CP_DMA_CMD_SAIC) {
3538254885Sdumbbell					reg = start_reg;
3539254885Sdumbbell					if (!evergreen_vm_reg_valid(reg)) {
3540254885Sdumbbell						DRM_ERROR("CP DMA Bad SRC register\n");
3541254885Sdumbbell						return -EINVAL;
3542254885Sdumbbell					}
3543254885Sdumbbell				} else {
3544254885Sdumbbell					for (i = 0; i < (command & 0x1fffff); i++) {
3545254885Sdumbbell						reg = start_reg + (4 * i);
3546254885Sdumbbell						if (!evergreen_vm_reg_valid(reg)) {
3547254885Sdumbbell							DRM_ERROR("CP DMA Bad SRC register\n");
3548254885Sdumbbell							return -EINVAL;
3549254885Sdumbbell						}
3550254885Sdumbbell					}
3551254885Sdumbbell				}
3552254885Sdumbbell			}
3553254885Sdumbbell		}
3554254885Sdumbbell		if (command & PACKET3_CP_DMA_CMD_DAS) {
3555254885Sdumbbell			/* dst address space is register */
3556254885Sdumbbell			if (((info & 0x00300000) >> 20) == 0) {
3557254885Sdumbbell				start_reg = ib[idx + 2];
3558254885Sdumbbell				if (command & PACKET3_CP_DMA_CMD_DAIC) {
3559254885Sdumbbell					reg = start_reg;
3560254885Sdumbbell					if (!evergreen_vm_reg_valid(reg)) {
3561254885Sdumbbell						DRM_ERROR("CP DMA Bad DST register\n");
3562254885Sdumbbell						return -EINVAL;
3563254885Sdumbbell					}
3564254885Sdumbbell				} else {
3565254885Sdumbbell					for (i = 0; i < (command & 0x1fffff); i++) {
3566254885Sdumbbell						reg = start_reg + (4 * i);
3567254885Sdumbbell						if (!evergreen_vm_reg_valid(reg)) {
3568254885Sdumbbell							DRM_ERROR("CP DMA Bad DST register\n");
3569254885Sdumbbell							return -EINVAL;
3570254885Sdumbbell						}
3571254885Sdumbbell					}
3572254885Sdumbbell				}
3573254885Sdumbbell			}
3574254885Sdumbbell		}
3575254885Sdumbbell		break;
3576254885Sdumbbell	default:
3577254885Sdumbbell		return -EINVAL;
3578254885Sdumbbell	}
3579254885Sdumbbell	return 0;
3580254885Sdumbbell}
3581254885Sdumbbell
3582254885Sdumbbellint evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
3583254885Sdumbbell{
3584254885Sdumbbell	int ret = 0;
3585254885Sdumbbell	u32 idx = 0;
3586254885Sdumbbell	struct radeon_cs_packet pkt;
3587254885Sdumbbell
3588254885Sdumbbell	do {
3589254885Sdumbbell		pkt.idx = idx;
3590254885Sdumbbell		pkt.type = CP_PACKET_GET_TYPE(ib->ptr[idx]);
3591254885Sdumbbell		pkt.count = CP_PACKET_GET_COUNT(ib->ptr[idx]);
3592254885Sdumbbell		pkt.one_reg_wr = 0;
3593254885Sdumbbell		switch (pkt.type) {
3594254885Sdumbbell		case PACKET_TYPE0:
3595254885Sdumbbell			dev_err(rdev->dev, "Packet0 not allowed!\n");
3596254885Sdumbbell			ret = -EINVAL;
3597254885Sdumbbell			break;
3598254885Sdumbbell		case PACKET_TYPE2:
3599254885Sdumbbell			idx += 1;
3600254885Sdumbbell			break;
3601254885Sdumbbell		case PACKET_TYPE3:
3602254885Sdumbbell			pkt.opcode = CP_PACKET3_GET_OPCODE(ib->ptr[idx]);
3603254885Sdumbbell			ret = evergreen_vm_packet3_check(rdev, ib->ptr, &pkt);
3604254885Sdumbbell			idx += pkt.count + 2;
3605254885Sdumbbell			break;
3606254885Sdumbbell		default:
3607254885Sdumbbell			dev_err(rdev->dev, "Unknown packet type %d !\n", pkt.type);
3608254885Sdumbbell			ret = -EINVAL;
3609254885Sdumbbell			break;
3610254885Sdumbbell		}
3611254885Sdumbbell		if (ret)
3612254885Sdumbbell			break;
3613254885Sdumbbell	} while (idx < ib->length_dw);
3614254885Sdumbbell
3615254885Sdumbbell	return ret;
3616254885Sdumbbell}
3617254885Sdumbbell
3618254885Sdumbbell/**
3619254885Sdumbbell * evergreen_dma_ib_parse() - parse the DMA IB for VM
3620254885Sdumbbell * @rdev: radeon_device pointer
3621254885Sdumbbell * @ib:	radeon_ib pointer
3622254885Sdumbbell *
3623254885Sdumbbell * Parses the DMA IB from the VM CS ioctl
3624254885Sdumbbell * checks for errors. (Cayman-SI)
3625254885Sdumbbell * Returns 0 for success and an error on failure.
3626254885Sdumbbell **/
3627254885Sdumbbellint evergreen_dma_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
3628254885Sdumbbell{
3629254885Sdumbbell	u32 idx = 0;
3630254885Sdumbbell	u32 header, cmd, count, tiled, new_cmd, misc;
3631254885Sdumbbell
3632254885Sdumbbell	do {
3633254885Sdumbbell		header = ib->ptr[idx];
3634254885Sdumbbell		cmd = GET_DMA_CMD(header);
3635254885Sdumbbell		count = GET_DMA_COUNT(header);
3636254885Sdumbbell		tiled = GET_DMA_T(header);
3637254885Sdumbbell		new_cmd = GET_DMA_NEW(header);
3638254885Sdumbbell		misc = GET_DMA_MISC(header);
3639254885Sdumbbell
3640254885Sdumbbell		switch (cmd) {
3641254885Sdumbbell		case DMA_PACKET_WRITE:
3642254885Sdumbbell			if (tiled)
3643254885Sdumbbell				idx += count + 7;
3644254885Sdumbbell			else
3645254885Sdumbbell				idx += count + 3;
3646254885Sdumbbell			break;
3647254885Sdumbbell		case DMA_PACKET_COPY:
3648254885Sdumbbell			if (tiled) {
3649254885Sdumbbell				if (new_cmd) {
3650254885Sdumbbell					switch (misc) {
3651254885Sdumbbell					case 0:
3652254885Sdumbbell						/* L2T, frame to fields */
3653254885Sdumbbell						idx += 10;
3654254885Sdumbbell						break;
3655254885Sdumbbell					case 1:
3656254885Sdumbbell						/* L2T, T2L partial */
3657254885Sdumbbell						idx += 12;
3658254885Sdumbbell						break;
3659254885Sdumbbell					case 3:
3660254885Sdumbbell						/* L2T, broadcast */
3661254885Sdumbbell						idx += 10;
3662254885Sdumbbell						break;
3663254885Sdumbbell					case 4:
3664254885Sdumbbell						/* L2T, T2L */
3665254885Sdumbbell						idx += 9;
3666254885Sdumbbell						break;
3667254885Sdumbbell					case 5:
3668254885Sdumbbell						/* T2T partial */
3669254885Sdumbbell						idx += 13;
3670254885Sdumbbell						break;
3671254885Sdumbbell					case 7:
3672254885Sdumbbell						/* L2T, broadcast */
3673254885Sdumbbell						idx += 10;
3674254885Sdumbbell						break;
3675254885Sdumbbell					default:
3676254885Sdumbbell						DRM_ERROR("bad DMA_PACKET_COPY misc %u\n", misc);
3677254885Sdumbbell						return -EINVAL;
3678254885Sdumbbell					}
3679254885Sdumbbell				} else {
3680254885Sdumbbell					switch (misc) {
3681254885Sdumbbell					case 0:
3682254885Sdumbbell						idx += 9;
3683254885Sdumbbell						break;
3684254885Sdumbbell					default:
3685254885Sdumbbell						DRM_ERROR("bad DMA_PACKET_COPY misc %u\n", misc);
3686254885Sdumbbell						return -EINVAL;
3687254885Sdumbbell					}
3688254885Sdumbbell				}
3689254885Sdumbbell			} else {
3690254885Sdumbbell				if (new_cmd) {
3691254885Sdumbbell					switch (misc) {
3692254885Sdumbbell					case 0:
3693254885Sdumbbell						/* L2L, byte */
3694254885Sdumbbell						idx += 5;
3695254885Sdumbbell						break;
3696254885Sdumbbell					case 1:
3697254885Sdumbbell						/* L2L, partial */
3698254885Sdumbbell						idx += 9;
3699254885Sdumbbell						break;
3700254885Sdumbbell					case 4:
3701254885Sdumbbell						/* L2L, dw, broadcast */
3702254885Sdumbbell						idx += 7;
3703254885Sdumbbell						break;
3704254885Sdumbbell					default:
3705254885Sdumbbell						DRM_ERROR("bad DMA_PACKET_COPY misc %u\n", misc);
3706254885Sdumbbell						return -EINVAL;
3707254885Sdumbbell					}
3708254885Sdumbbell				} else {
3709254885Sdumbbell					/* L2L, dw */
3710254885Sdumbbell					idx += 5;
3711254885Sdumbbell				}
3712254885Sdumbbell			}
3713254885Sdumbbell			break;
3714254885Sdumbbell		case DMA_PACKET_CONSTANT_FILL:
3715254885Sdumbbell			idx += 4;
3716254885Sdumbbell			break;
3717254885Sdumbbell		case DMA_PACKET_NOP:
3718254885Sdumbbell			idx += 1;
3719254885Sdumbbell			break;
3720254885Sdumbbell		default:
3721254885Sdumbbell			DRM_ERROR("Unknown packet type %d at %d !\n", cmd, idx);
3722254885Sdumbbell			return -EINVAL;
3723254885Sdumbbell		}
3724254885Sdumbbell	} while (idx < ib->length_dw);
3725254885Sdumbbell
3726254885Sdumbbell	return 0;
3727254885Sdumbbell}
3728