xref: /netbsd-src/sys/external/bsd/drm/dist/shared-core/radeon_cs.c (revision 12c8119aab232b3d9fdd820962c691cca4149acd)
1 /*-
2  * Copyright 2008 Jerome Glisse.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Jerome Glisse <glisse@freedesktop.org>
26  */
27 
28 #include <sys/cdefs.h>
29 /*__FBSDID("$FreeBSD: src/sys/dev/drm/radeon_cs.c,v 1.2 2009/09/28 22:41:28 rnoland Exp $");*/
30 #include "drmP.h"
31 #include "radeon_drm.h"
32 #include "radeon_drv.h"
33 
34 /* regs */
35 #define AVIVO_D1MODE_VLINE_START_END                           0x6538
36 #define AVIVO_D2MODE_VLINE_START_END                           0x6d38
37 #define R600_CP_COHER_BASE                                     0x85f8
38 #define R600_DB_DEPTH_BASE                                     0x2800c
39 #define R600_CB_COLOR0_BASE                                    0x28040
40 #define R600_CB_COLOR1_BASE                                    0x28044
41 #define R600_CB_COLOR2_BASE                                    0x28048
42 #define R600_CB_COLOR3_BASE                                    0x2804c
43 #define R600_CB_COLOR4_BASE                                    0x28050
44 #define R600_CB_COLOR5_BASE                                    0x28054
45 #define R600_CB_COLOR6_BASE                                    0x28058
46 #define R600_CB_COLOR7_BASE                                    0x2805c
47 #define R600_SQ_PGM_START_FS                                   0x28894
48 #define R600_SQ_PGM_START_ES                                   0x28880
49 #define R600_SQ_PGM_START_VS                                   0x28858
50 #define R600_SQ_PGM_START_GS                                   0x2886c
51 #define R600_SQ_PGM_START_PS                                   0x28840
52 #define R600_VGT_DMA_BASE                                      0x287e8
53 #define R600_VGT_DMA_BASE_HI                                   0x287e4
54 #define R600_VGT_STRMOUT_BASE_OFFSET_0                         0x28b10
55 #define R600_VGT_STRMOUT_BASE_OFFSET_1                         0x28b14
56 #define R600_VGT_STRMOUT_BASE_OFFSET_2                         0x28b18
57 #define R600_VGT_STRMOUT_BASE_OFFSET_3                         0x28b1c
58 #define R600_VGT_STRMOUT_BASE_OFFSET_HI_0                      0x28b44
59 #define R600_VGT_STRMOUT_BASE_OFFSET_HI_1                      0x28b48
60 #define R600_VGT_STRMOUT_BASE_OFFSET_HI_2                      0x28b4c
61 #define R600_VGT_STRMOUT_BASE_OFFSET_HI_3                      0x28b50
62 #define R600_VGT_STRMOUT_BUFFER_BASE_0                         0x28ad8
63 #define R600_VGT_STRMOUT_BUFFER_BASE_1                         0x28ae8
64 #define R600_VGT_STRMOUT_BUFFER_BASE_2                         0x28af8
65 #define R600_VGT_STRMOUT_BUFFER_BASE_3                         0x28b08
66 #define R600_VGT_STRMOUT_BUFFER_OFFSET_0                       0x28adc
67 #define R600_VGT_STRMOUT_BUFFER_OFFSET_1                       0x28aec
68 #define R600_VGT_STRMOUT_BUFFER_OFFSET_2                       0x28afc
69 #define R600_VGT_STRMOUT_BUFFER_OFFSET_3                       0x28b0c
70 
71 /* resource type */
72 #define R600_SQ_TEX_VTX_INVALID_TEXTURE                        0x0
73 #define R600_SQ_TEX_VTX_INVALID_BUFFER                         0x1
74 #define R600_SQ_TEX_VTX_VALID_TEXTURE                          0x2
75 #define R600_SQ_TEX_VTX_VALID_BUFFER                           0x3
76 
77 /* packet 3 type offsets */
78 #define R600_SET_CONFIG_REG_OFFSET                             0x00008000
79 #define R600_SET_CONFIG_REG_END                                0x0000ac00
80 #define R600_SET_CONTEXT_REG_OFFSET                            0x00028000
81 #define R600_SET_CONTEXT_REG_END                               0x00029000
82 #define R600_SET_ALU_CONST_OFFSET                              0x00030000
83 #define R600_SET_ALU_CONST_END                                 0x00032000
84 #define R600_SET_RESOURCE_OFFSET                               0x00038000
85 #define R600_SET_RESOURCE_END                                  0x0003c000
86 #define R600_SET_SAMPLER_OFFSET                                0x0003c000
87 #define R600_SET_SAMPLER_END                                   0x0003cff0
88 #define R600_SET_CTL_CONST_OFFSET                              0x0003cff0
89 #define R600_SET_CTL_CONST_END                                 0x0003e200
90 #define R600_SET_LOOP_CONST_OFFSET                             0x0003e200
91 #define R600_SET_LOOP_CONST_END                                0x0003e380
92 #define R600_SET_BOOL_CONST_OFFSET                             0x0003e380
93 #define R600_SET_BOOL_CONST_END                                0x00040000
94 
95 /* Packet 3 types */
96 #define R600_IT_INDIRECT_BUFFER_END               0x00001700
97 #define R600_IT_SET_PREDICATION                   0x00002000
98 #define R600_IT_REG_RMW                           0x00002100
99 #define R600_IT_COND_EXEC                         0x00002200
100 #define R600_IT_PRED_EXEC                         0x00002300
101 #define R600_IT_START_3D_CMDBUF                   0x00002400
102 #define R600_IT_DRAW_INDEX_2                      0x00002700
103 #define R600_IT_CONTEXT_CONTROL                   0x00002800
104 #define R600_IT_DRAW_INDEX_IMMD_BE                0x00002900
105 #define R600_IT_INDEX_TYPE                        0x00002A00
106 #define R600_IT_DRAW_INDEX                        0x00002B00
107 #define R600_IT_DRAW_INDEX_AUTO                   0x00002D00
108 #define R600_IT_DRAW_INDEX_IMMD                   0x00002E00
109 #define R600_IT_NUM_INSTANCES                     0x00002F00
110 #define R600_IT_STRMOUT_BUFFER_UPDATE             0x00003400
111 #define R600_IT_INDIRECT_BUFFER_MP                0x00003800
112 #define R600_IT_MEM_SEMAPHORE                     0x00003900
113 #define R600_IT_MPEG_INDEX                        0x00003A00
114 #define R600_IT_WAIT_REG_MEM                      0x00003C00
115 #define R600_IT_MEM_WRITE                         0x00003D00
116 #define R600_IT_INDIRECT_BUFFER                   0x00003200
117 #define R600_IT_CP_INTERRUPT                      0x00004000
118 #define R600_IT_SURFACE_SYNC                      0x00004300
119 #define R600_IT_ME_INITIALIZE                     0x00004400
120 #define R600_IT_COND_WRITE                        0x00004500
121 #define R600_IT_EVENT_WRITE                       0x00004600
122 #define R600_IT_EVENT_WRITE_EOP                   0x00004700
123 #define R600_IT_ONE_REG_WRITE                     0x00005700
124 #define R600_IT_SET_CONFIG_REG                    0x00006800
125 #define R600_IT_SET_CONTEXT_REG                   0x00006900
126 #define R600_IT_SET_ALU_CONST                     0x00006A00
127 #define R600_IT_SET_BOOL_CONST                    0x00006B00
128 #define R600_IT_SET_LOOP_CONST                    0x00006C00
129 #define R600_IT_SET_RESOURCE                      0x00006D00
130 #define R600_IT_SET_SAMPLER                       0x00006E00
131 #define R600_IT_SET_CTL_CONST                     0x00006F00
132 #define R600_IT_SURFACE_BASE_UPDATE               0x00007300
133 
radeon_cs_ioctl(struct drm_device * dev,void * data,struct drm_file * fpriv)134 int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv)
135 {
136 	struct drm_radeon_cs_parser parser;
137 	struct drm_radeon_private *dev_priv = dev->dev_private;
138 	struct drm_radeon_cs *cs = data;
139 	uint32_t cs_id;
140 	struct drm_radeon_cs_chunk __user **chunk_ptr = NULL;
141 	uint64_t *chunk_array;
142 	uint64_t *chunk_array_ptr;
143 	long size;
144 	int r, i;
145 
146 	DRM_SPINLOCK(&dev_priv->cs.cs_mutex);
147 	/* set command stream id to 0 which is fake id */
148 	cs_id = 0;
149 	cs->cs_id = cs_id;
150 
151 	if (!cs->num_chunks) {
152 		DRM_SPINUNLOCK(&dev_priv->cs.cs_mutex);
153 		return 0;
154 	}
155 
156 
157 	chunk_array = drm_calloc(cs->num_chunks, sizeof(uint64_t), DRM_MEM_DRIVER);
158 	if (!chunk_array) {
159 		DRM_SPINUNLOCK(&dev_priv->cs.cs_mutex);
160 		return -ENOMEM;
161 	}
162 
163 	chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks);
164 
165 	if (DRM_COPY_FROM_USER(chunk_array, chunk_array_ptr, sizeof(uint64_t)*cs->num_chunks)) {
166 		r = -EFAULT;
167 		goto out;
168 	}
169 
170 	parser.dev = dev;
171 	parser.file_priv = fpriv;
172 	parser.reloc_index = -1;
173 	parser.ib_index = -1;
174 	parser.num_chunks = cs->num_chunks;
175 	/* copy out the chunk headers */
176 	parser.chunks = drm_calloc(parser.num_chunks, sizeof(struct drm_radeon_kernel_chunk), DRM_MEM_DRIVER);
177 	if (!parser.chunks) {
178 		r = -ENOMEM;
179 		goto out;
180 	}
181 
182 	for (i = 0; i < parser.num_chunks; i++) {
183 		struct drm_radeon_cs_chunk user_chunk;
184 
185 		chunk_ptr = (void __user *)(unsigned long)chunk_array[i];
186 
187 		if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr, sizeof(struct drm_radeon_cs_chunk))){
188 			r = -EFAULT;
189 			goto out;
190 		}
191 		parser.chunks[i].chunk_id = user_chunk.chunk_id;
192 
193 		if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS)
194 			parser.reloc_index = i;
195 
196 		if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_IB)
197 			parser.ib_index = i;
198 
199 		if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_OLD) {
200 			parser.ib_index = i;
201 			parser.reloc_index = -1;
202 		}
203 
204 		parser.chunks[i].length_dw = user_chunk.length_dw;
205 		parser.chunks[i].chunk_data = (uint32_t *)(unsigned long)user_chunk.chunk_data;
206 
207 		parser.chunks[i].kdata = NULL;
208 		size = parser.chunks[i].length_dw * sizeof(uint32_t);
209 
210 		switch(parser.chunks[i].chunk_id) {
211 		case RADEON_CHUNK_ID_IB:
212 		case RADEON_CHUNK_ID_OLD:
213 			if (size == 0) {
214 				r = -EINVAL;
215 				goto out;
216 			}
217 		case RADEON_CHUNK_ID_RELOCS:
218 			if (size) {
219 				parser.chunks[i].kdata = drm_alloc(size, DRM_MEM_DRIVER);
220 				if (!parser.chunks[i].kdata) {
221 					r = -ENOMEM;
222 					goto out;
223 				}
224 
225 				if (DRM_COPY_FROM_USER(parser.chunks[i].kdata, parser.chunks[i].chunk_data, size)) {
226 					r = -EFAULT;
227 					goto out;
228 				}
229 			} else
230 				parser.chunks[i].kdata = NULL;
231 			break;
232 		default:
233 			break;
234 		}
235 		DRM_DEBUG("chunk %d %d %d %p\n", i, parser.chunks[i].chunk_id, parser.chunks[i].length_dw,
236 			  parser.chunks[i].chunk_data);
237 	}
238 
239 	if (parser.chunks[parser.ib_index].length_dw > (16 * 1024)) {
240 		DRM_ERROR("cs->dwords too big: %d\n", parser.chunks[parser.ib_index].length_dw);
241 		r = -EINVAL;
242 		goto out;
243 	}
244 
245 	/* get ib */
246 	r = dev_priv->cs.ib_get(&parser);
247 	if (r) {
248 		DRM_ERROR("ib_get failed\n");
249 		goto out;
250 	}
251 
252 	/* now parse command stream */
253 	r = dev_priv->cs.parse(&parser);
254 	if (r) {
255 		goto out;
256 	}
257 
258 out:
259 	dev_priv->cs.ib_free(&parser, r);
260 
261 	/* emit cs id sequence */
262 	dev_priv->cs.id_emit(&parser, &cs_id);
263 
264 	cs->cs_id = cs_id;
265 
266 	DRM_SPINUNLOCK(&dev_priv->cs.cs_mutex);
267 
268 	for (i = 0; i < parser.num_chunks; i++) {
269 		if (parser.chunks[i].kdata)
270 			drm_free(parser.chunks[i].kdata, parser.chunks[i].length_dw * sizeof(uint32_t), DRM_MEM_DRIVER);
271 	}
272 
273 	drm_free(parser.chunks, sizeof(struct drm_radeon_kernel_chunk)*parser.num_chunks, DRM_MEM_DRIVER);
274 	drm_free(chunk_array, sizeof(uint64_t)*parser.num_chunks, DRM_MEM_DRIVER);
275 
276 	return r;
277 }
278 
279 /* for non-mm */
r600_nomm_relocate(struct drm_radeon_cs_parser * parser,uint32_t * reloc,uint64_t * offset)280 static int r600_nomm_relocate(struct drm_radeon_cs_parser *parser, uint32_t *reloc, uint64_t *offset)
281 {
282 	struct drm_device *dev = parser->dev;
283 	drm_radeon_private_t *dev_priv = dev->dev_private;
284 	struct drm_radeon_kernel_chunk *reloc_chunk = &parser->chunks[parser->reloc_index];
285 	uint32_t offset_dw = reloc[1];
286 
287 	//DRM_INFO("reloc: 0x%08x 0x%08x\n", reloc[0], reloc[1]);
288 	//DRM_INFO("length: %d\n", reloc_chunk->length_dw);
289 
290 	if (!reloc_chunk->kdata)
291 		return -EINVAL;
292 
293 	if (offset_dw > reloc_chunk->length_dw) {
294 		DRM_ERROR("Offset larger than chunk 0x%x %d\n", offset_dw, reloc_chunk->length_dw);
295 		return -EINVAL;
296 	}
297 
298 	/* 40 bit addr */
299 	*offset = reloc_chunk->kdata[offset_dw + 3];
300 	*offset <<= 32;
301 	*offset |= reloc_chunk->kdata[offset_dw + 0];
302 
303 	//DRM_INFO("offset 0x%lx\n", *offset);
304 
305 	if (!radeon_check_offset(dev_priv, *offset)) {
306 		DRM_ERROR("bad offset! 0x%lx\n", (unsigned long)*offset);
307 		return -EINVAL;
308 	}
309 
310 	return 0;
311 }
312 
r600_cs_packet0(struct drm_radeon_cs_parser * parser,uint32_t * offset_dw_p)313 static inline int r600_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t *offset_dw_p)
314 {
315 	uint32_t hdr, num_dw, reg;
316 	int count_dw = 1;
317 	int ret = 0;
318 	uint32_t offset_dw = *offset_dw_p;
319 	int incr = 2;
320 
321 	hdr = parser->chunks[parser->ib_index].kdata[offset_dw];
322 	num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2;
323 	reg = (hdr & 0xffff) << 2;
324 
325 	while (count_dw < num_dw) {
326 		switch (reg) {
327 		case AVIVO_D1MODE_VLINE_START_END:
328 		case AVIVO_D2MODE_VLINE_START_END:
329 			break;
330 		default:
331 			ret = -EINVAL;
332 			DRM_ERROR("bad packet 0 reg: 0x%08x\n", reg);
333 			break;
334 		}
335 		if (ret)
336 			break;
337 		count_dw++;
338 		reg += 4;
339 	}
340 	*offset_dw_p += incr;
341 	return ret;
342 }
343 
r600_cs_packet3(struct drm_radeon_cs_parser * parser,uint32_t * offset_dw_p)344 static inline int r600_cs_packet3(struct drm_radeon_cs_parser *parser, uint32_t *offset_dw_p)
345 {
346 	struct drm_device *dev = parser->dev;
347 	drm_radeon_private_t *dev_priv = dev->dev_private;
348 	uint32_t hdr, num_dw, start_reg, end_reg, reg;
349 	uint32_t *reloc;
350 	uint64_t offset;
351 	int ret = 0;
352 	uint32_t offset_dw = *offset_dw_p;
353 	int incr = 2;
354 	int i;
355 	struct drm_radeon_kernel_chunk *ib_chunk;
356 
357 	ib_chunk = &parser->chunks[parser->ib_index];
358 
359 	hdr = ib_chunk->kdata[offset_dw];
360 	num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2;
361 
362 	/* just the ones we use for now, add more later */
363 	switch (hdr & 0xff00) {
364 	case R600_IT_START_3D_CMDBUF:
365 		//DRM_INFO("R600_IT_START_3D_CMDBUF\n");
366 		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
367 			ret = -EINVAL;
368 		if (num_dw != 2)
369 			ret = -EINVAL;
370 		if (ret)
371 			DRM_ERROR("bad START_3D\n");
372 		break;
373 	case R600_IT_CONTEXT_CONTROL:
374 		//DRM_INFO("R600_IT_CONTEXT_CONTROL\n");
375 		if (num_dw != 3)
376 			ret = -EINVAL;
377 		if (ret)
378 			DRM_ERROR("bad CONTEXT_CONTROL\n");
379 		break;
380 	case R600_IT_INDEX_TYPE:
381 	case R600_IT_NUM_INSTANCES:
382 		//DRM_INFO("R600_IT_INDEX_TYPE/R600_IT_NUM_INSTANCES\n");
383 		if (num_dw != 2)
384 			ret = -EINVAL;
385 		if (ret)
386 			DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES\n");
387 		break;
388 	case R600_IT_DRAW_INDEX:
389 		//DRM_INFO("R600_IT_DRAW_INDEX\n");
390 		if (num_dw != 5) {
391 			ret = -EINVAL;
392 			DRM_ERROR("bad DRAW_INDEX\n");
393 			break;
394 		}
395 		reloc = ib_chunk->kdata + offset_dw + num_dw;
396 		ret = dev_priv->cs.relocate(parser, reloc, &offset);
397 		if (ret) {
398 			DRM_ERROR("bad DRAW_INDEX\n");
399 			break;
400 		}
401 		ib_chunk->kdata[offset_dw + 1] += (offset & 0xffffffff);
402 		ib_chunk->kdata[offset_dw + 2] += (upper_32_bits(offset) & 0xff);
403 		break;
404 	case R600_IT_DRAW_INDEX_AUTO:
405 		//DRM_INFO("R600_IT_DRAW_INDEX_AUTO\n");
406 		if (num_dw != 3)
407 			ret = -EINVAL;
408 		if (ret)
409 			DRM_ERROR("bad DRAW_INDEX_AUTO\n");
410 		break;
411 	case R600_IT_DRAW_INDEX_IMMD_BE:
412 	case R600_IT_DRAW_INDEX_IMMD:
413 		//DRM_INFO("R600_IT_DRAW_INDEX_IMMD\n");
414 		if (num_dw < 4)
415 			ret = -EINVAL;
416 		if (ret)
417 			DRM_ERROR("bad DRAW_INDEX_IMMD\n");
418 		break;
419 	case R600_IT_WAIT_REG_MEM:
420 		//DRM_INFO("R600_IT_WAIT_REG_MEM\n");
421 		if (num_dw != 7)
422 			ret = -EINVAL;
423 		/* bit 4 is reg (0) or mem (1) */
424 		if (ib_chunk->kdata[offset_dw + 1] & 0x10) {
425 			reloc = ib_chunk->kdata + offset_dw + num_dw;
426 			ret = dev_priv->cs.relocate(parser, reloc, &offset);
427 			if (ret) {
428 				DRM_ERROR("bad WAIT_REG_MEM\n");
429 				break;
430 			}
431 			ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff);
432 			ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff);
433 		}
434 		if (ret)
435 			DRM_ERROR("bad WAIT_REG_MEM\n");
436 		break;
437 	case R600_IT_SURFACE_SYNC:
438 		//DRM_INFO("R600_IT_SURFACE_SYNC\n");
439 		if (num_dw != 5)
440 			ret = -EINVAL;
441 		/* 0xffffffff/0x0 is flush all cache flag */
442 		else if ((ib_chunk->kdata[offset_dw + 2] == 0xffffffff) &&
443 			 (ib_chunk->kdata[offset_dw + 3] == 0))
444 			ret = 0;
445 		else {
446 			reloc = ib_chunk->kdata + offset_dw + num_dw;
447 			ret = dev_priv->cs.relocate(parser, reloc, &offset);
448 			if (ret) {
449 				DRM_ERROR("bad SURFACE_SYNC\n");
450 				break;
451 			}
452 			ib_chunk->kdata[offset_dw + 3] += ((offset >> 8) & 0xffffffff);
453 		}
454 		break;
455 	case R600_IT_EVENT_WRITE:
456 		//DRM_INFO("R600_IT_EVENT_WRITE\n");
457 		if ((num_dw != 4) && (num_dw != 2))
458 			ret = -EINVAL;
459 		if (num_dw > 2) {
460 			reloc = ib_chunk->kdata + offset_dw + num_dw;
461 			ret = dev_priv->cs.relocate(parser, reloc, &offset);
462 			if (ret) {
463 				DRM_ERROR("bad EVENT_WRITE\n");
464 				break;
465 			}
466 			ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff);
467 			ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff);
468 		}
469 		if (ret)
470 			DRM_ERROR("bad EVENT_WRITE\n");
471 		break;
472 	case R600_IT_EVENT_WRITE_EOP:
473 		//DRM_INFO("R600_IT_EVENT_WRITE_EOP\n");
474 		if (num_dw != 6) {
475 			ret = -EINVAL;
476 			DRM_ERROR("bad EVENT_WRITE_EOP\n");
477 			break;
478 		}
479 		reloc = ib_chunk->kdata + offset_dw + num_dw;
480 		ret = dev_priv->cs.relocate(parser, reloc, &offset);
481 		if (ret) {
482 			DRM_ERROR("bad EVENT_WRITE_EOP\n");
483 			break;
484 		}
485 		ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff);
486 		ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff);
487 		break;
488 	case R600_IT_SET_CONFIG_REG:
489 		//DRM_INFO("R600_IT_SET_CONFIG_REG\n");
490 		start_reg = (ib_chunk->kdata[offset_dw + 1] << 2) + R600_SET_CONFIG_REG_OFFSET;
491 		end_reg = 4 * (num_dw - 2) + start_reg - 4;
492 		if ((start_reg < R600_SET_CONFIG_REG_OFFSET) ||
493 		    (start_reg >= R600_SET_CONFIG_REG_END) ||
494 		    (end_reg >= R600_SET_CONFIG_REG_END))
495 			ret = -EINVAL;
496 		else {
497 			for (i = 0; i < (num_dw - 2); i++) {
498 				reg = start_reg + (4 * i);
499 				switch (reg) {
500 				case R600_CP_COHER_BASE:
501 					/* use R600_IT_SURFACE_SYNC */
502 					ret = -EINVAL;
503 					break;
504 				default:
505 					break;
506 				}
507 				if (ret)
508 					break;
509 			}
510 		}
511 		if (ret)
512 			DRM_ERROR("bad SET_CONFIG_REG\n");
513 		break;
514 	case R600_IT_SET_CONTEXT_REG:
515 		//DRM_INFO("R600_IT_SET_CONTEXT_REG\n");
516 		start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
517 		start_reg += R600_SET_CONTEXT_REG_OFFSET;
518 		end_reg = 4 * (num_dw - 2) + start_reg - 4;
519 		if ((start_reg < R600_SET_CONTEXT_REG_OFFSET) ||
520 		    (start_reg >= R600_SET_CONTEXT_REG_END) ||
521 		    (end_reg >= R600_SET_CONTEXT_REG_END))
522 			ret = -EINVAL;
523 		else {
524 			for (i = 0; i < (num_dw - 2); i++) {
525 				reg = start_reg + (4 * i);
526 				switch (reg) {
527 				case R600_DB_DEPTH_BASE:
528 				case R600_CB_COLOR0_BASE:
529 				case R600_CB_COLOR1_BASE:
530 				case R600_CB_COLOR2_BASE:
531 				case R600_CB_COLOR3_BASE:
532 				case R600_CB_COLOR4_BASE:
533 				case R600_CB_COLOR5_BASE:
534 				case R600_CB_COLOR6_BASE:
535 				case R600_CB_COLOR7_BASE:
536 				case R600_SQ_PGM_START_FS:
537 				case R600_SQ_PGM_START_ES:
538 				case R600_SQ_PGM_START_VS:
539 				case R600_SQ_PGM_START_GS:
540 				case R600_SQ_PGM_START_PS:
541 					//DRM_INFO("reg: 0x%08x\n", reg);
542 					reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 2);
543 					ret = dev_priv->cs.relocate(parser, reloc, &offset);
544 					if (ret) {
545 						DRM_ERROR("bad SET_CONTEXT_REG\n");
546 						break;
547 					}
548 					ib_chunk->kdata[offset_dw + 2 + i] +=
549 						((offset >> 8) & 0xffffffff);
550 					break;
551 				case R600_VGT_DMA_BASE:
552 				case R600_VGT_DMA_BASE_HI:
553 					/* These should be handled by DRAW_INDEX packet 3 */
554 				case R600_VGT_STRMOUT_BASE_OFFSET_0:
555 				case R600_VGT_STRMOUT_BASE_OFFSET_1:
556 				case R600_VGT_STRMOUT_BASE_OFFSET_2:
557 				case R600_VGT_STRMOUT_BASE_OFFSET_3:
558 				case R600_VGT_STRMOUT_BASE_OFFSET_HI_0:
559 				case R600_VGT_STRMOUT_BASE_OFFSET_HI_1:
560 				case R600_VGT_STRMOUT_BASE_OFFSET_HI_2:
561 				case R600_VGT_STRMOUT_BASE_OFFSET_HI_3:
562 				case R600_VGT_STRMOUT_BUFFER_BASE_0:
563 				case R600_VGT_STRMOUT_BUFFER_BASE_1:
564 				case R600_VGT_STRMOUT_BUFFER_BASE_2:
565 				case R600_VGT_STRMOUT_BUFFER_BASE_3:
566 				case R600_VGT_STRMOUT_BUFFER_OFFSET_0:
567 				case R600_VGT_STRMOUT_BUFFER_OFFSET_1:
568 				case R600_VGT_STRMOUT_BUFFER_OFFSET_2:
569 				case R600_VGT_STRMOUT_BUFFER_OFFSET_3:
570 					/* These should be handled by STRMOUT_BUFFER packet 3 */
571 					DRM_ERROR("bad context reg: 0x%08x\n", reg);
572 					ret = -EINVAL;
573 					break;
574 				default:
575 					break;
576 				}
577 				if (ret)
578 					break;
579 			}
580 		}
581 		if (ret)
582 			DRM_ERROR("bad SET_CONTEXT_REG\n");
583 		break;
584 	case R600_IT_SET_RESOURCE:
585 		//DRM_INFO("R600_IT_SET_RESOURCE\n");
586 		if ((num_dw - 2) % 7)
587 			ret = -EINVAL;
588 		start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
589 		start_reg += R600_SET_RESOURCE_OFFSET;
590 		end_reg = 4 * (num_dw - 2) + start_reg - 4;
591 		if ((start_reg < R600_SET_RESOURCE_OFFSET) ||
592 		    (start_reg >= R600_SET_RESOURCE_END) ||
593 		    (end_reg >= R600_SET_RESOURCE_END))
594 			ret = -EINVAL;
595 		else {
596 			for (i = 0; i < ((num_dw - 2) / 7); i++) {
597 				switch ((ib_chunk->kdata[offset_dw + (i * 7) + 6 + 2] & 0xc0000000) >> 30) {
598 				case R600_SQ_TEX_VTX_INVALID_TEXTURE:
599 				case R600_SQ_TEX_VTX_INVALID_BUFFER:
600 				default:
601 					ret = -EINVAL;
602 					break;
603 				case R600_SQ_TEX_VTX_VALID_TEXTURE:
604 					/* tex base */
605 					reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 4);
606 					ret = dev_priv->cs.relocate(parser, reloc, &offset);
607 					if (ret)
608 						break;
609 					ib_chunk->kdata[offset_dw + (i * 7) + 2 + 2] +=
610 						((offset >> 8) & 0xffffffff);
611 					/* tex mip base */
612 					reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 4) + 2;
613 					ret = dev_priv->cs.relocate(parser, reloc, &offset);
614 					if (ret)
615 						break;
616 					ib_chunk->kdata[offset_dw + (i * 7) + 3 + 2] +=
617 						((offset >> 8) & 0xffffffff);
618 					break;
619 				case R600_SQ_TEX_VTX_VALID_BUFFER:
620 					/* vtx base */
621 					reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 2);
622 					ret = dev_priv->cs.relocate(parser, reloc, &offset);
623 					if (ret)
624 						break;
625 					ib_chunk->kdata[offset_dw + (i * 7) + 0 + 2] += (offset & 0xffffffff);
626 					ib_chunk->kdata[offset_dw + (i * 7) + 2 + 2] += (upper_32_bits(offset) & 0xff);
627 					break;
628 				}
629 				if (ret)
630 					break;
631 			}
632 		}
633 		if (ret)
634 			DRM_ERROR("bad SET_RESOURCE\n");
635 		break;
636 	case R600_IT_SET_ALU_CONST:
637 		//DRM_INFO("R600_IT_SET_ALU_CONST\n");
638 		start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
639 		start_reg += R600_SET_ALU_CONST_OFFSET;
640 		end_reg = 4 * (num_dw - 2) + start_reg - 4;
641 		if ((start_reg < R600_SET_ALU_CONST_OFFSET) ||
642 		    (start_reg >= R600_SET_ALU_CONST_END) ||
643 		    (end_reg >= R600_SET_ALU_CONST_END))
644 			ret = -EINVAL;
645 		if (ret)
646 			DRM_ERROR("bad SET_ALU_CONST\n");
647 		break;
648 	case R600_IT_SET_BOOL_CONST:
649 		//DRM_INFO("R600_IT_SET_BOOL_CONST\n");
650 		start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
651 		start_reg += R600_SET_BOOL_CONST_OFFSET;
652 		end_reg = 4 * (num_dw - 2) + start_reg - 4;
653 		if ((start_reg < R600_SET_BOOL_CONST_OFFSET) ||
654 		    (start_reg >= R600_SET_BOOL_CONST_END) ||
655 		    (end_reg >= R600_SET_BOOL_CONST_END))
656 			ret = -EINVAL;
657 		if (ret)
658 			DRM_ERROR("bad SET_BOOL_CONST\n");
659 		break;
660 	case R600_IT_SET_LOOP_CONST:
661 		//DRM_INFO("R600_IT_SET_LOOP_CONST\n");
662 		start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
663 		start_reg += R600_SET_LOOP_CONST_OFFSET;
664 		end_reg = 4 * (num_dw - 2) + start_reg - 4;
665 		if ((start_reg < R600_SET_LOOP_CONST_OFFSET) ||
666 		    (start_reg >= R600_SET_LOOP_CONST_END) ||
667 		    (end_reg >= R600_SET_LOOP_CONST_END))
668 			ret = -EINVAL;
669 		if (ret)
670 			DRM_ERROR("bad SET_LOOP_CONST\n");
671 		break;
672 	case R600_IT_SET_CTL_CONST:
673 		//DRM_INFO("R600_IT_SET_CTL_CONST\n");
674 		start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
675 		start_reg += R600_SET_CTL_CONST_OFFSET;
676 		end_reg = 4 * (num_dw - 2) + start_reg - 4;
677 		if ((start_reg < R600_SET_CTL_CONST_OFFSET) ||
678 		    (start_reg >= R600_SET_CTL_CONST_END) ||
679 		    (end_reg >= R600_SET_CTL_CONST_END))
680 			ret = -EINVAL;
681 		if (ret)
682 			DRM_ERROR("bad SET_CTL_CONST\n");
683 		break;
684 	case R600_IT_SET_SAMPLER:
685 		//DRM_INFO("R600_IT_SET_SAMPLER\n");
686 		if ((num_dw - 2) % 3)
687 			ret = -EINVAL;
688 		start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
689 		start_reg += R600_SET_SAMPLER_OFFSET;
690 		end_reg = 4 * (num_dw - 2) + start_reg - 4;
691 		if ((start_reg < R600_SET_SAMPLER_OFFSET) ||
692 		    (start_reg >= R600_SET_SAMPLER_END) ||
693 		    (end_reg >= R600_SET_SAMPLER_END))
694 			ret = -EINVAL;
695 		if (ret)
696 			DRM_ERROR("bad SET_SAMPLER\n");
697 		break;
698 	case R600_IT_SURFACE_BASE_UPDATE:
699 		//DRM_INFO("R600_IT_SURFACE_BASE_UPDATE\n");
700 		if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) ||
701 		    ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600))
702 			ret = -EINVAL;
703 		if (num_dw != 2)
704 			ret = -EINVAL;
705 		if (ret)
706 			DRM_ERROR("bad SURFACE_BASE_UPDATE\n");
707 		break;
708 	case RADEON_CP_NOP:
709 		//DRM_INFO("NOP: %d\n", ib_chunk->kdata[offset_dw + 1]);
710 		break;
711 	default:
712 		DRM_ERROR("invalid packet 3 0x%08x\n", 0xff00);
713 		ret = -EINVAL;
714 		break;
715 	}
716 
717 	*offset_dw_p += incr;
718 	return ret;
719 }
720 
r600_cs_parse(struct drm_radeon_cs_parser * parser)721 static int r600_cs_parse(struct drm_radeon_cs_parser *parser)
722 {
723 	struct drm_radeon_kernel_chunk *ib_chunk;
724 	/* scan the packet for various things */
725 	int count_dw = 0, size_dw;
726 	int ret = 0;
727 
728 	ib_chunk = &parser->chunks[parser->ib_index];
729 	size_dw = ib_chunk->length_dw;
730 
731 	while (count_dw < size_dw && ret == 0) {
732 		int hdr = ib_chunk->kdata[count_dw];
733 		int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16;
734 
735 		switch (hdr & RADEON_CP_PACKET_MASK) {
736 		case RADEON_CP_PACKET0:
737 			ret = r600_cs_packet0(parser, &count_dw);
738 			break;
739 		case RADEON_CP_PACKET1:
740 			ret = -EINVAL;
741 			break;
742 		case RADEON_CP_PACKET2:
743 			DRM_DEBUG("Packet 2\n");
744 			num_dw += 1;
745 			break;
746 		case RADEON_CP_PACKET3:
747 			ret = r600_cs_packet3(parser, &count_dw);
748 			break;
749 		}
750 
751 		count_dw += num_dw;
752 	}
753 
754 	if (ret)
755 		return ret;
756 
757 
758 	/* copy the packet into the IB */
759 	memcpy(parser->ib, ib_chunk->kdata, ib_chunk->length_dw * sizeof(uint32_t));
760 
761 	/* read back last byte to flush WC buffers */
762 	readl(((vm_offset_t)parser->ib + (ib_chunk->length_dw-1) * sizeof(uint32_t)));
763 
764 	return 0;
765 }
766 
radeon_cs_id_get(struct drm_radeon_private * radeon)767 static uint32_t radeon_cs_id_get(struct drm_radeon_private *radeon)
768 {
769 	/* FIXME: protect with a spinlock */
770 	/* FIXME: check if wrap affect last reported wrap & sequence */
771 	radeon->cs.id_scnt = (radeon->cs.id_scnt + 1) & 0x00FFFFFF;
772 	if (!radeon->cs.id_scnt) {
773 		/* increment wrap counter */
774 		radeon->cs.id_wcnt += 0x01000000;
775 		/* valid sequence counter start at 1 */
776 		radeon->cs.id_scnt = 1;
777 	}
778 	return (radeon->cs.id_scnt | radeon->cs.id_wcnt);
779 }
780 
r600_cs_id_emit(struct drm_radeon_cs_parser * parser,uint32_t * id)781 static void r600_cs_id_emit(struct drm_radeon_cs_parser *parser, uint32_t *id)
782 {
783 	drm_radeon_private_t *dev_priv = parser->dev->dev_private;
784 	RING_LOCALS;
785 
786 	//dev_priv->irq_emitted = radeon_update_breadcrumb(parser->dev);
787 
788 	*id = radeon_cs_id_get(dev_priv);
789 
790 	/* SCRATCH 2 */
791 	BEGIN_RING(3);
792 	R600_CLEAR_AGE(*id);
793 	ADVANCE_RING();
794 	COMMIT_RING();
795 }
796 
r600_cs_id_last_get(struct drm_device * dev)797 static uint32_t r600_cs_id_last_get(struct drm_device *dev)
798 {
799 	//drm_radeon_private_t *dev_priv = dev->dev_private;
800 
801 	//return GET_R600_SCRATCH(dev_priv, 2);
802 	return 0;
803 }
804 
r600_ib_get(struct drm_radeon_cs_parser * parser)805 static int r600_ib_get(struct drm_radeon_cs_parser *parser)
806 {
807 	struct drm_device *dev = parser->dev;
808 	drm_radeon_private_t *dev_priv = dev->dev_private;
809 	struct drm_buf *buf;
810 
811 	buf = radeon_freelist_get(dev);
812 	if (!buf) {
813 		dev_priv->cs_buf = NULL;
814 		return -EBUSY;
815 	}
816 	buf->file_priv = parser->file_priv;
817 	dev_priv->cs_buf = buf;
818 	parser->ib = (void *)((vm_offset_t)dev->agp_buffer_map->handle +
819 	    buf->offset);
820 
821 	return 0;
822 }
823 
r600_ib_free(struct drm_radeon_cs_parser * parser,int error)824 static void r600_ib_free(struct drm_radeon_cs_parser *parser, int error)
825 {
826 	struct drm_device *dev = parser->dev;
827 	drm_radeon_private_t *dev_priv = dev->dev_private;
828 	struct drm_buf *buf = dev_priv->cs_buf;
829 
830 	if (buf) {
831 		if (!error)
832 			r600_cp_dispatch_indirect(dev, buf, 0,
833 						  parser->chunks[parser->ib_index].length_dw * sizeof(uint32_t));
834 		radeon_cp_discard_buffer(dev, buf);
835 		COMMIT_RING();
836 	}
837 }
838 
r600_cs_init(struct drm_device * dev)839 int r600_cs_init(struct drm_device *dev)
840 {
841 	drm_radeon_private_t *dev_priv = dev->dev_private;
842 
843 	dev_priv->cs.ib_get = r600_ib_get;
844 	dev_priv->cs.ib_free = r600_ib_free;
845 	dev_priv->cs.id_emit = r600_cs_id_emit;
846 	dev_priv->cs.id_last_get = r600_cs_id_last_get;
847 	dev_priv->cs.parse = r600_cs_parse;
848 	dev_priv->cs.relocate = r600_nomm_relocate;
849 	return 0;
850 }
851