Home | History | Annotate | Line # | Download | only in shared-core
      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 (at) 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 
    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 */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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