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