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