radeon_cs.c revision 207066
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: head/sys/dev/drm/radeon_cs.c 207066 2010-04-22 18:21:25Z rnoland $"); 30#include "dev/drm/drmP.h" 31#include "dev/drm/radeon_drm.h" 32#include "dev/drm/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 134int 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 mtx_lock(&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 (dev_priv == NULL) { 152 DRM_ERROR("called with no initialization\n"); 153 mtx_unlock(&dev_priv->cs.cs_mutex); 154 return -EINVAL; 155 } 156 if (!cs->num_chunks) { 157 mtx_unlock(&dev_priv->cs.cs_mutex); 158 return 0; 159 } 160 161 162 chunk_array = drm_calloc(cs->num_chunks, sizeof(uint64_t), DRM_MEM_DRIVER); 163 if (!chunk_array) { 164 mtx_unlock(&dev_priv->cs.cs_mutex); 165 return -ENOMEM; 166 } 167 168 chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks); 169 170 if (DRM_COPY_FROM_USER(chunk_array, chunk_array_ptr, sizeof(uint64_t)*cs->num_chunks)) { 171 r = -EFAULT; 172 goto out; 173 } 174 175 parser.dev = dev; 176 parser.file_priv = fpriv; 177 parser.reloc_index = -1; 178 parser.ib_index = -1; 179 parser.num_chunks = cs->num_chunks; 180 /* copy out the chunk headers */ 181 parser.chunks = drm_calloc(parser.num_chunks, sizeof(struct drm_radeon_kernel_chunk), DRM_MEM_DRIVER); 182 if (!parser.chunks) { 183 r = -ENOMEM; 184 goto out; 185 } 186 187 for (i = 0; i < parser.num_chunks; i++) { 188 struct drm_radeon_cs_chunk user_chunk; 189 190 chunk_ptr = (void __user *)(unsigned long)chunk_array[i]; 191 192 if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr, sizeof(struct drm_radeon_cs_chunk))){ 193 r = -EFAULT; 194 goto out; 195 } 196 parser.chunks[i].chunk_id = user_chunk.chunk_id; 197 198 if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) 199 parser.reloc_index = i; 200 201 if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_IB) 202 parser.ib_index = i; 203 204 if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_OLD) { 205 parser.ib_index = i; 206 parser.reloc_index = -1; 207 } 208 209 parser.chunks[i].length_dw = user_chunk.length_dw; 210 parser.chunks[i].chunk_data = (uint32_t *)(unsigned long)user_chunk.chunk_data; 211 212 parser.chunks[i].kdata = NULL; 213 size = parser.chunks[i].length_dw * sizeof(uint32_t); 214 215 switch(parser.chunks[i].chunk_id) { 216 case RADEON_CHUNK_ID_IB: 217 case RADEON_CHUNK_ID_OLD: 218 if (size == 0) { 219 r = -EINVAL; 220 goto out; 221 } 222 case RADEON_CHUNK_ID_RELOCS: 223 if (size) { 224 parser.chunks[i].kdata = drm_alloc(size, DRM_MEM_DRIVER); 225 if (!parser.chunks[i].kdata) { 226 r = -ENOMEM; 227 goto out; 228 } 229 230 if (DRM_COPY_FROM_USER(parser.chunks[i].kdata, parser.chunks[i].chunk_data, size)) { 231 r = -EFAULT; 232 goto out; 233 } 234 } else 235 parser.chunks[i].kdata = NULL; 236 break; 237 default: 238 break; 239 } 240 DRM_DEBUG("chunk %d %d %d %p\n", i, parser.chunks[i].chunk_id, parser.chunks[i].length_dw, 241 parser.chunks[i].chunk_data); 242 } 243 244 if (parser.chunks[parser.ib_index].length_dw > (16 * 1024)) { 245 DRM_ERROR("cs->dwords too big: %d\n", parser.chunks[parser.ib_index].length_dw); 246 r = -EINVAL; 247 goto out; 248 } 249 250 /* get ib */ 251 r = dev_priv->cs.ib_get(&parser); 252 if (r) { 253 DRM_ERROR("ib_get failed\n"); 254 goto out; 255 } 256 257 /* now parse command stream */ 258 r = dev_priv->cs.parse(&parser); 259 if (r) { 260 goto out; 261 } 262 263out: 264 dev_priv->cs.ib_free(&parser, r); 265 266 /* emit cs id sequence */ 267 dev_priv->cs.id_emit(&parser, &cs_id); 268 269 cs->cs_id = cs_id; 270 271 mtx_unlock(&dev_priv->cs.cs_mutex); 272 273 for (i = 0; i < parser.num_chunks; i++) { 274 if (parser.chunks[i].kdata) 275 drm_free(parser.chunks[i].kdata, parser.chunks[i].length_dw * sizeof(uint32_t), DRM_MEM_DRIVER); 276 } 277 278 drm_free(parser.chunks, sizeof(struct drm_radeon_kernel_chunk)*parser.num_chunks, DRM_MEM_DRIVER); 279 drm_free(chunk_array, sizeof(uint64_t)*parser.num_chunks, DRM_MEM_DRIVER); 280 281 return r; 282} 283 284/* for non-mm */ 285static int r600_nomm_relocate(struct drm_radeon_cs_parser *parser, uint32_t *reloc, uint64_t *offset) 286{ 287 struct drm_device *dev = parser->dev; 288 drm_radeon_private_t *dev_priv = dev->dev_private; 289 struct drm_radeon_kernel_chunk *reloc_chunk = &parser->chunks[parser->reloc_index]; 290 uint32_t offset_dw = reloc[1]; 291 292 //DRM_INFO("reloc: 0x%08x 0x%08x\n", reloc[0], reloc[1]); 293 //DRM_INFO("length: %d\n", reloc_chunk->length_dw); 294 295 if (!reloc_chunk->kdata) 296 return -EINVAL; 297 298 if (offset_dw > reloc_chunk->length_dw) { 299 DRM_ERROR("Offset larger than chunk 0x%x %d\n", offset_dw, reloc_chunk->length_dw); 300 return -EINVAL; 301 } 302 303 /* 40 bit addr */ 304 *offset = reloc_chunk->kdata[offset_dw + 3]; 305 *offset <<= 32; 306 *offset |= reloc_chunk->kdata[offset_dw + 0]; 307 308 //DRM_INFO("offset 0x%lx\n", *offset); 309 310 if (!radeon_check_offset(dev_priv, *offset)) { 311 DRM_ERROR("bad offset! 0x%lx\n", (unsigned long)*offset); 312 return -EINVAL; 313 } 314 315 return 0; 316} 317 318static inline int r600_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t *offset_dw_p) 319{ 320 uint32_t hdr, num_dw, reg; 321 int count_dw = 1; 322 int ret = 0; 323 uint32_t offset_dw = *offset_dw_p; 324 int incr = 2; 325 326 hdr = parser->chunks[parser->ib_index].kdata[offset_dw]; 327 num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2; 328 reg = (hdr & 0xffff) << 2; 329 330 while (count_dw < num_dw) { 331 switch (reg) { 332 case AVIVO_D1MODE_VLINE_START_END: 333 case AVIVO_D2MODE_VLINE_START_END: 334 break; 335 default: 336 ret = -EINVAL; 337 DRM_ERROR("bad packet 0 reg: 0x%08x\n", reg); 338 break; 339 } 340 if (ret) 341 break; 342 count_dw++; 343 reg += 4; 344 } 345 *offset_dw_p += incr; 346 return ret; 347} 348 349static inline int r600_cs_packet3(struct drm_radeon_cs_parser *parser, uint32_t *offset_dw_p) 350{ 351 struct drm_device *dev = parser->dev; 352 drm_radeon_private_t *dev_priv = dev->dev_private; 353 uint32_t hdr, num_dw, start_reg, end_reg, reg; 354 uint32_t *reloc; 355 uint64_t offset; 356 int ret = 0; 357 uint32_t offset_dw = *offset_dw_p; 358 int incr = 2; 359 int i; 360 struct drm_radeon_kernel_chunk *ib_chunk; 361 362 ib_chunk = &parser->chunks[parser->ib_index]; 363 364 hdr = ib_chunk->kdata[offset_dw]; 365 num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2; 366 367 /* just the ones we use for now, add more later */ 368 switch (hdr & 0xff00) { 369 case R600_IT_START_3D_CMDBUF: 370 //DRM_INFO("R600_IT_START_3D_CMDBUF\n"); 371 if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) 372 ret = -EINVAL; 373 if (num_dw != 2) 374 ret = -EINVAL; 375 if (ret) 376 DRM_ERROR("bad START_3D\n"); 377 break; 378 case R600_IT_CONTEXT_CONTROL: 379 //DRM_INFO("R600_IT_CONTEXT_CONTROL\n"); 380 if (num_dw != 3) 381 ret = -EINVAL; 382 if (ret) 383 DRM_ERROR("bad CONTEXT_CONTROL\n"); 384 break; 385 case R600_IT_INDEX_TYPE: 386 case R600_IT_NUM_INSTANCES: 387 //DRM_INFO("R600_IT_INDEX_TYPE/R600_IT_NUM_INSTANCES\n"); 388 if (num_dw != 2) 389 ret = -EINVAL; 390 if (ret) 391 DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES\n"); 392 break; 393 case R600_IT_DRAW_INDEX: 394 //DRM_INFO("R600_IT_DRAW_INDEX\n"); 395 if (num_dw != 5) { 396 ret = -EINVAL; 397 DRM_ERROR("bad DRAW_INDEX\n"); 398 break; 399 } 400 reloc = ib_chunk->kdata + offset_dw + num_dw; 401 ret = dev_priv->cs.relocate(parser, reloc, &offset); 402 if (ret) { 403 DRM_ERROR("bad DRAW_INDEX\n"); 404 break; 405 } 406 ib_chunk->kdata[offset_dw + 1] += (offset & 0xffffffff); 407 ib_chunk->kdata[offset_dw + 2] += (upper_32_bits(offset) & 0xff); 408 break; 409 case R600_IT_DRAW_INDEX_AUTO: 410 //DRM_INFO("R600_IT_DRAW_INDEX_AUTO\n"); 411 if (num_dw != 3) 412 ret = -EINVAL; 413 if (ret) 414 DRM_ERROR("bad DRAW_INDEX_AUTO\n"); 415 break; 416 case R600_IT_DRAW_INDEX_IMMD_BE: 417 case R600_IT_DRAW_INDEX_IMMD: 418 //DRM_INFO("R600_IT_DRAW_INDEX_IMMD\n"); 419 if (num_dw < 4) 420 ret = -EINVAL; 421 if (ret) 422 DRM_ERROR("bad DRAW_INDEX_IMMD\n"); 423 break; 424 case R600_IT_WAIT_REG_MEM: 425 //DRM_INFO("R600_IT_WAIT_REG_MEM\n"); 426 if (num_dw != 7) 427 ret = -EINVAL; 428 /* bit 4 is reg (0) or mem (1) */ 429 if (ib_chunk->kdata[offset_dw + 1] & 0x10) { 430 reloc = ib_chunk->kdata + offset_dw + num_dw; 431 ret = dev_priv->cs.relocate(parser, reloc, &offset); 432 if (ret) { 433 DRM_ERROR("bad WAIT_REG_MEM\n"); 434 break; 435 } 436 ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff); 437 ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff); 438 } 439 if (ret) 440 DRM_ERROR("bad WAIT_REG_MEM\n"); 441 break; 442 case R600_IT_SURFACE_SYNC: 443 //DRM_INFO("R600_IT_SURFACE_SYNC\n"); 444 if (num_dw != 5) 445 ret = -EINVAL; 446 /* 0xffffffff/0x0 is flush all cache flag */ 447 else if ((ib_chunk->kdata[offset_dw + 2] == 0xffffffff) && 448 (ib_chunk->kdata[offset_dw + 3] == 0)) 449 ret = 0; 450 else { 451 reloc = ib_chunk->kdata + offset_dw + num_dw; 452 ret = dev_priv->cs.relocate(parser, reloc, &offset); 453 if (ret) { 454 DRM_ERROR("bad SURFACE_SYNC\n"); 455 break; 456 } 457 ib_chunk->kdata[offset_dw + 3] += ((offset >> 8) & 0xffffffff); 458 } 459 break; 460 case R600_IT_EVENT_WRITE: 461 //DRM_INFO("R600_IT_EVENT_WRITE\n"); 462 if ((num_dw != 4) && (num_dw != 2)) 463 ret = -EINVAL; 464 if (num_dw > 2) { 465 reloc = ib_chunk->kdata + offset_dw + num_dw; 466 ret = dev_priv->cs.relocate(parser, reloc, &offset); 467 if (ret) { 468 DRM_ERROR("bad EVENT_WRITE\n"); 469 break; 470 } 471 ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff); 472 ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff); 473 } 474 if (ret) 475 DRM_ERROR("bad EVENT_WRITE\n"); 476 break; 477 case R600_IT_EVENT_WRITE_EOP: 478 //DRM_INFO("R600_IT_EVENT_WRITE_EOP\n"); 479 if (num_dw != 6) { 480 ret = -EINVAL; 481 DRM_ERROR("bad EVENT_WRITE_EOP\n"); 482 break; 483 } 484 reloc = ib_chunk->kdata + offset_dw + num_dw; 485 ret = dev_priv->cs.relocate(parser, reloc, &offset); 486 if (ret) { 487 DRM_ERROR("bad EVENT_WRITE_EOP\n"); 488 break; 489 } 490 ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff); 491 ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff); 492 break; 493 case R600_IT_SET_CONFIG_REG: 494 //DRM_INFO("R600_IT_SET_CONFIG_REG\n"); 495 start_reg = (ib_chunk->kdata[offset_dw + 1] << 2) + R600_SET_CONFIG_REG_OFFSET; 496 end_reg = 4 * (num_dw - 2) + start_reg - 4; 497 if ((start_reg < R600_SET_CONFIG_REG_OFFSET) || 498 (start_reg >= R600_SET_CONFIG_REG_END) || 499 (end_reg >= R600_SET_CONFIG_REG_END)) 500 ret = -EINVAL; 501 else { 502 for (i = 0; i < (num_dw - 2); i++) { 503 reg = start_reg + (4 * i); 504 switch (reg) { 505 case R600_CP_COHER_BASE: 506 /* use R600_IT_SURFACE_SYNC */ 507 ret = -EINVAL; 508 break; 509 default: 510 break; 511 } 512 if (ret) 513 break; 514 } 515 } 516 if (ret) 517 DRM_ERROR("bad SET_CONFIG_REG\n"); 518 break; 519 case R600_IT_SET_CONTEXT_REG: 520 //DRM_INFO("R600_IT_SET_CONTEXT_REG\n"); 521 start_reg = ib_chunk->kdata[offset_dw + 1] << 2; 522 start_reg += R600_SET_CONTEXT_REG_OFFSET; 523 end_reg = 4 * (num_dw - 2) + start_reg - 4; 524 if ((start_reg < R600_SET_CONTEXT_REG_OFFSET) || 525 (start_reg >= R600_SET_CONTEXT_REG_END) || 526 (end_reg >= R600_SET_CONTEXT_REG_END)) 527 ret = -EINVAL; 528 else { 529 for (i = 0; i < (num_dw - 2); i++) { 530 reg = start_reg + (4 * i); 531 switch (reg) { 532 case R600_DB_DEPTH_BASE: 533 case R600_CB_COLOR0_BASE: 534 case R600_CB_COLOR1_BASE: 535 case R600_CB_COLOR2_BASE: 536 case R600_CB_COLOR3_BASE: 537 case R600_CB_COLOR4_BASE: 538 case R600_CB_COLOR5_BASE: 539 case R600_CB_COLOR6_BASE: 540 case R600_CB_COLOR7_BASE: 541 case R600_SQ_PGM_START_FS: 542 case R600_SQ_PGM_START_ES: 543 case R600_SQ_PGM_START_VS: 544 case R600_SQ_PGM_START_GS: 545 case R600_SQ_PGM_START_PS: 546 //DRM_INFO("reg: 0x%08x\n", reg); 547 reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 2); 548 ret = dev_priv->cs.relocate(parser, reloc, &offset); 549 if (ret) { 550 DRM_ERROR("bad SET_CONTEXT_REG\n"); 551 break; 552 } 553 ib_chunk->kdata[offset_dw + 2 + i] += 554 ((offset >> 8) & 0xffffffff); 555 break; 556 case R600_VGT_DMA_BASE: 557 case R600_VGT_DMA_BASE_HI: 558 /* These should be handled by DRAW_INDEX packet 3 */ 559 case R600_VGT_STRMOUT_BASE_OFFSET_0: 560 case R600_VGT_STRMOUT_BASE_OFFSET_1: 561 case R600_VGT_STRMOUT_BASE_OFFSET_2: 562 case R600_VGT_STRMOUT_BASE_OFFSET_3: 563 case R600_VGT_STRMOUT_BASE_OFFSET_HI_0: 564 case R600_VGT_STRMOUT_BASE_OFFSET_HI_1: 565 case R600_VGT_STRMOUT_BASE_OFFSET_HI_2: 566 case R600_VGT_STRMOUT_BASE_OFFSET_HI_3: 567 case R600_VGT_STRMOUT_BUFFER_BASE_0: 568 case R600_VGT_STRMOUT_BUFFER_BASE_1: 569 case R600_VGT_STRMOUT_BUFFER_BASE_2: 570 case R600_VGT_STRMOUT_BUFFER_BASE_3: 571 case R600_VGT_STRMOUT_BUFFER_OFFSET_0: 572 case R600_VGT_STRMOUT_BUFFER_OFFSET_1: 573 case R600_VGT_STRMOUT_BUFFER_OFFSET_2: 574 case R600_VGT_STRMOUT_BUFFER_OFFSET_3: 575 /* These should be handled by STRMOUT_BUFFER packet 3 */ 576 DRM_ERROR("bad context reg: 0x%08x\n", reg); 577 ret = -EINVAL; 578 break; 579 default: 580 break; 581 } 582 if (ret) 583 break; 584 } 585 } 586 if (ret) 587 DRM_ERROR("bad SET_CONTEXT_REG\n"); 588 break; 589 case R600_IT_SET_RESOURCE: 590 //DRM_INFO("R600_IT_SET_RESOURCE\n"); 591 if ((num_dw - 2) % 7) 592 ret = -EINVAL; 593 start_reg = ib_chunk->kdata[offset_dw + 1] << 2; 594 start_reg += R600_SET_RESOURCE_OFFSET; 595 end_reg = 4 * (num_dw - 2) + start_reg - 4; 596 if ((start_reg < R600_SET_RESOURCE_OFFSET) || 597 (start_reg >= R600_SET_RESOURCE_END) || 598 (end_reg >= R600_SET_RESOURCE_END)) 599 ret = -EINVAL; 600 else { 601 for (i = 0; i < ((num_dw - 2) / 7); i++) { 602 switch ((ib_chunk->kdata[offset_dw + (i * 7) + 6 + 2] & 0xc0000000) >> 30) { 603 case R600_SQ_TEX_VTX_INVALID_TEXTURE: 604 case R600_SQ_TEX_VTX_INVALID_BUFFER: 605 default: 606 ret = -EINVAL; 607 break; 608 case R600_SQ_TEX_VTX_VALID_TEXTURE: 609 /* tex base */ 610 reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 4); 611 ret = dev_priv->cs.relocate(parser, reloc, &offset); 612 if (ret) 613 break; 614 ib_chunk->kdata[offset_dw + (i * 7) + 2 + 2] += 615 ((offset >> 8) & 0xffffffff); 616 /* tex mip base */ 617 reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 4) + 2; 618 ret = dev_priv->cs.relocate(parser, reloc, &offset); 619 if (ret) 620 break; 621 ib_chunk->kdata[offset_dw + (i * 7) + 3 + 2] += 622 ((offset >> 8) & 0xffffffff); 623 break; 624 case R600_SQ_TEX_VTX_VALID_BUFFER: 625 /* vtx base */ 626 reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 2); 627 ret = dev_priv->cs.relocate(parser, reloc, &offset); 628 if (ret) 629 break; 630 ib_chunk->kdata[offset_dw + (i * 7) + 0 + 2] += (offset & 0xffffffff); 631 ib_chunk->kdata[offset_dw + (i * 7) + 2 + 2] += (upper_32_bits(offset) & 0xff); 632 break; 633 } 634 if (ret) 635 break; 636 } 637 } 638 if (ret) 639 DRM_ERROR("bad SET_RESOURCE\n"); 640 break; 641 case R600_IT_SET_ALU_CONST: 642 //DRM_INFO("R600_IT_SET_ALU_CONST\n"); 643 start_reg = ib_chunk->kdata[offset_dw + 1] << 2; 644 start_reg += R600_SET_ALU_CONST_OFFSET; 645 end_reg = 4 * (num_dw - 2) + start_reg - 4; 646 if ((start_reg < R600_SET_ALU_CONST_OFFSET) || 647 (start_reg >= R600_SET_ALU_CONST_END) || 648 (end_reg >= R600_SET_ALU_CONST_END)) 649 ret = -EINVAL; 650 if (ret) 651 DRM_ERROR("bad SET_ALU_CONST\n"); 652 break; 653 case R600_IT_SET_BOOL_CONST: 654 //DRM_INFO("R600_IT_SET_BOOL_CONST\n"); 655 start_reg = ib_chunk->kdata[offset_dw + 1] << 2; 656 start_reg += R600_SET_BOOL_CONST_OFFSET; 657 end_reg = 4 * (num_dw - 2) + start_reg - 4; 658 if ((start_reg < R600_SET_BOOL_CONST_OFFSET) || 659 (start_reg >= R600_SET_BOOL_CONST_END) || 660 (end_reg >= R600_SET_BOOL_CONST_END)) 661 ret = -EINVAL; 662 if (ret) 663 DRM_ERROR("bad SET_BOOL_CONST\n"); 664 break; 665 case R600_IT_SET_LOOP_CONST: 666 //DRM_INFO("R600_IT_SET_LOOP_CONST\n"); 667 start_reg = ib_chunk->kdata[offset_dw + 1] << 2; 668 start_reg += R600_SET_LOOP_CONST_OFFSET; 669 end_reg = 4 * (num_dw - 2) + start_reg - 4; 670 if ((start_reg < R600_SET_LOOP_CONST_OFFSET) || 671 (start_reg >= R600_SET_LOOP_CONST_END) || 672 (end_reg >= R600_SET_LOOP_CONST_END)) 673 ret = -EINVAL; 674 if (ret) 675 DRM_ERROR("bad SET_LOOP_CONST\n"); 676 break; 677 case R600_IT_SET_CTL_CONST: 678 //DRM_INFO("R600_IT_SET_CTL_CONST\n"); 679 start_reg = ib_chunk->kdata[offset_dw + 1] << 2; 680 start_reg += R600_SET_CTL_CONST_OFFSET; 681 end_reg = 4 * (num_dw - 2) + start_reg - 4; 682 if ((start_reg < R600_SET_CTL_CONST_OFFSET) || 683 (start_reg >= R600_SET_CTL_CONST_END) || 684 (end_reg >= R600_SET_CTL_CONST_END)) 685 ret = -EINVAL; 686 if (ret) 687 DRM_ERROR("bad SET_CTL_CONST\n"); 688 break; 689 case R600_IT_SET_SAMPLER: 690 //DRM_INFO("R600_IT_SET_SAMPLER\n"); 691 if ((num_dw - 2) % 3) 692 ret = -EINVAL; 693 start_reg = ib_chunk->kdata[offset_dw + 1] << 2; 694 start_reg += R600_SET_SAMPLER_OFFSET; 695 end_reg = 4 * (num_dw - 2) + start_reg - 4; 696 if ((start_reg < R600_SET_SAMPLER_OFFSET) || 697 (start_reg >= R600_SET_SAMPLER_END) || 698 (end_reg >= R600_SET_SAMPLER_END)) 699 ret = -EINVAL; 700 if (ret) 701 DRM_ERROR("bad SET_SAMPLER\n"); 702 break; 703 case R600_IT_SURFACE_BASE_UPDATE: 704 //DRM_INFO("R600_IT_SURFACE_BASE_UPDATE\n"); 705 if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) || 706 ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600)) 707 ret = -EINVAL; 708 if (num_dw != 2) 709 ret = -EINVAL; 710 if (ret) 711 DRM_ERROR("bad SURFACE_BASE_UPDATE\n"); 712 break; 713 case RADEON_CP_NOP: 714 //DRM_INFO("NOP: %d\n", ib_chunk->kdata[offset_dw + 1]); 715 break; 716 default: 717 DRM_ERROR("invalid packet 3 0x%08x\n", 0xff00); 718 ret = -EINVAL; 719 break; 720 } 721 722 *offset_dw_p += incr; 723 return ret; 724} 725 726static int r600_cs_parse(struct drm_radeon_cs_parser *parser) 727{ 728 volatile int rb; 729 struct drm_radeon_kernel_chunk *ib_chunk; 730 /* scan the packet for various things */ 731 int count_dw = 0, size_dw; 732 int ret = 0; 733 734 ib_chunk = &parser->chunks[parser->ib_index]; 735 size_dw = ib_chunk->length_dw; 736 737 while (count_dw < size_dw && ret == 0) { 738 int hdr = ib_chunk->kdata[count_dw]; 739 int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16; 740 741 switch (hdr & RADEON_CP_PACKET_MASK) { 742 case RADEON_CP_PACKET0: 743 ret = r600_cs_packet0(parser, &count_dw); 744 break; 745 case RADEON_CP_PACKET1: 746 ret = -EINVAL; 747 break; 748 case RADEON_CP_PACKET2: 749 DRM_DEBUG("Packet 2\n"); 750 num_dw += 1; 751 break; 752 case RADEON_CP_PACKET3: 753 ret = r600_cs_packet3(parser, &count_dw); 754 break; 755 } 756 757 count_dw += num_dw; 758 } 759 760 if (ret) 761 return ret; 762 763 764 /* copy the packet into the IB */ 765 memcpy(parser->ib, ib_chunk->kdata, ib_chunk->length_dw * sizeof(uint32_t)); 766 767 /* read back last byte to flush WC buffers */ 768 rb = readl(((vm_offset_t)parser->ib + (ib_chunk->length_dw-1) * sizeof(uint32_t))); 769 770 return 0; 771} 772 773static uint32_t radeon_cs_id_get(struct drm_radeon_private *radeon) 774{ 775 /* FIXME: protect with a spinlock */ 776 /* FIXME: check if wrap affect last reported wrap & sequence */ 777 radeon->cs.id_scnt = (radeon->cs.id_scnt + 1) & 0x00FFFFFF; 778 if (!radeon->cs.id_scnt) { 779 /* increment wrap counter */ 780 radeon->cs.id_wcnt += 0x01000000; 781 /* valid sequence counter start at 1 */ 782 radeon->cs.id_scnt = 1; 783 } 784 return (radeon->cs.id_scnt | radeon->cs.id_wcnt); 785} 786 787static void r600_cs_id_emit(struct drm_radeon_cs_parser *parser, uint32_t *id) 788{ 789 drm_radeon_private_t *dev_priv = parser->dev->dev_private; 790 RING_LOCALS; 791 792 //dev_priv->irq_emitted = radeon_update_breadcrumb(parser->dev); 793 794 *id = radeon_cs_id_get(dev_priv); 795 796 /* SCRATCH 2 */ 797 BEGIN_RING(3); 798 R600_CLEAR_AGE(*id); 799 ADVANCE_RING(); 800 COMMIT_RING(); 801} 802 803static uint32_t r600_cs_id_last_get(struct drm_device *dev) 804{ 805 //drm_radeon_private_t *dev_priv = dev->dev_private; 806 807 //return GET_R600_SCRATCH(dev_priv, 2); 808 return 0; 809} 810 811static int r600_ib_get(struct drm_radeon_cs_parser *parser) 812{ 813 struct drm_device *dev = parser->dev; 814 drm_radeon_private_t *dev_priv = dev->dev_private; 815 struct drm_buf *buf; 816 817 buf = radeon_freelist_get(dev); 818 if (!buf) { 819 dev_priv->cs_buf = NULL; 820 return -EBUSY; 821 } 822 buf->file_priv = parser->file_priv; 823 dev_priv->cs_buf = buf; 824 parser->ib = (void *)((vm_offset_t)dev->agp_buffer_map->virtual + 825 buf->offset); 826 827 return 0; 828} 829 830static void r600_ib_free(struct drm_radeon_cs_parser *parser, int error) 831{ 832 struct drm_device *dev = parser->dev; 833 drm_radeon_private_t *dev_priv = dev->dev_private; 834 struct drm_buf *buf = dev_priv->cs_buf; 835 836 if (buf) { 837 if (!error) 838 r600_cp_dispatch_indirect(dev, buf, 0, 839 parser->chunks[parser->ib_index].length_dw * sizeof(uint32_t)); 840 radeon_cp_discard_buffer(dev, buf); 841 COMMIT_RING(); 842 } 843} 844 845int r600_cs_init(struct drm_device *dev) 846{ 847 drm_radeon_private_t *dev_priv = dev->dev_private; 848 849 dev_priv->cs.ib_get = r600_ib_get; 850 dev_priv->cs.ib_free = r600_ib_free; 851 dev_priv->cs.id_emit = r600_cs_id_emit; 852 dev_priv->cs.id_last_get = r600_cs_id_last_get; 853 dev_priv->cs.parse = r600_cs_parse; 854 dev_priv->cs.relocate = r600_nomm_relocate; 855 return 0; 856} 857