1 /* 2 * Copyright 2008 Advanced Micro Devices, Inc. 3 * Copyright 2008 Red Hat Inc. 4 * Copyright 2009 Jerome Glisse. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the 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 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: Dave Airlie 25 * Alex Deucher 26 * Jerome Glisse 27 */ 28 #include "drmP.h" 29 #include "radeon.h" 30 #include "r600d.h" 31 32 static int r600_cs_packet_next_reloc_mm(struct radeon_cs_parser *p, 33 struct radeon_cs_reloc **cs_reloc); 34 static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p, 35 struct radeon_cs_reloc **cs_reloc); 36 typedef int (*next_reloc_t)(struct radeon_cs_parser*, struct radeon_cs_reloc**); 37 static next_reloc_t r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_mm; 38 39 struct r600_cs_track { 40 u32 cb_color0_base_last; 41 }; 42 43 /** 44 * r600_cs_packet_parse() - parse cp packet and point ib index to next packet 45 * @parser: parser structure holding parsing context. 46 * @pkt: where to store packet informations 47 * 48 * Assume that chunk_ib_index is properly set. Will return -EINVAL 49 * if packet is bigger than remaining ib size. or if packets is unknown. 50 **/ 51 int r600_cs_packet_parse(struct radeon_cs_parser *p, 52 struct radeon_cs_packet *pkt, 53 unsigned idx) 54 { 55 struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx]; 56 uint32_t header; 57 58 if (idx >= ib_chunk->length_dw) { 59 DRM_ERROR("Can not parse packet at %d after CS end %d !\n", 60 idx, ib_chunk->length_dw); 61 return -EINVAL; 62 } 63 header = radeon_get_ib_value(p, idx); 64 pkt->idx = idx; 65 pkt->type = CP_PACKET_GET_TYPE(header); 66 pkt->count = CP_PACKET_GET_COUNT(header); 67 pkt->one_reg_wr = 0; 68 switch (pkt->type) { 69 case PACKET_TYPE0: 70 pkt->reg = CP_PACKET0_GET_REG(header); 71 break; 72 case PACKET_TYPE3: 73 pkt->opcode = CP_PACKET3_GET_OPCODE(header); 74 break; 75 case PACKET_TYPE2: 76 pkt->count = -1; 77 break; 78 default: 79 DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx); 80 return -EINVAL; 81 } 82 if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) { 83 DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n", 84 pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw); 85 return -EINVAL; 86 } 87 return 0; 88 } 89 90 /** 91 * r600_cs_packet_next_reloc_mm() - parse next packet which should be reloc packet3 92 * @parser: parser structure holding parsing context. 93 * @data: pointer to relocation data 94 * @offset_start: starting offset 95 * @offset_mask: offset mask (to align start offset on) 96 * @reloc: reloc informations 97 * 98 * Check next packet is relocation packet3, do bo validation and compute 99 * GPU offset using the provided start. 100 **/ 101 static int r600_cs_packet_next_reloc_mm(struct radeon_cs_parser *p, 102 struct radeon_cs_reloc **cs_reloc) 103 { 104 struct radeon_cs_chunk *relocs_chunk; 105 struct radeon_cs_packet p3reloc; 106 unsigned idx; 107 int r; 108 109 if (p->chunk_relocs_idx == -1) { 110 DRM_ERROR("No relocation chunk !\n"); 111 return -EINVAL; 112 } 113 *cs_reloc = NULL; 114 relocs_chunk = &p->chunks[p->chunk_relocs_idx]; 115 r = r600_cs_packet_parse(p, &p3reloc, p->idx); 116 if (r) { 117 return r; 118 } 119 p->idx += p3reloc.count + 2; 120 if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { 121 DRM_ERROR("No packet3 for relocation for packet at %d.\n", 122 p3reloc.idx); 123 return -EINVAL; 124 } 125 idx = radeon_get_ib_value(p, p3reloc.idx + 1); 126 if (idx >= relocs_chunk->length_dw) { 127 DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", 128 idx, relocs_chunk->length_dw); 129 return -EINVAL; 130 } 131 /* FIXME: we assume reloc size is 4 dwords */ 132 *cs_reloc = p->relocs_ptr[(idx / 4)]; 133 return 0; 134 } 135 136 /** 137 * r600_cs_packet_next_reloc_nomm() - parse next packet which should be reloc packet3 138 * @parser: parser structure holding parsing context. 139 * @data: pointer to relocation data 140 * @offset_start: starting offset 141 * @offset_mask: offset mask (to align start offset on) 142 * @reloc: reloc informations 143 * 144 * Check next packet is relocation packet3, do bo validation and compute 145 * GPU offset using the provided start. 146 **/ 147 static int r600_cs_packet_next_reloc_nomm(struct radeon_cs_parser *p, 148 struct radeon_cs_reloc **cs_reloc) 149 { 150 struct radeon_cs_chunk *relocs_chunk; 151 struct radeon_cs_packet p3reloc; 152 unsigned idx; 153 int r; 154 155 if (p->chunk_relocs_idx == -1) { 156 DRM_ERROR("No relocation chunk !\n"); 157 return -EINVAL; 158 } 159 *cs_reloc = NULL; 160 relocs_chunk = &p->chunks[p->chunk_relocs_idx]; 161 r = r600_cs_packet_parse(p, &p3reloc, p->idx); 162 if (r) { 163 return r; 164 } 165 p->idx += p3reloc.count + 2; 166 if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { 167 DRM_ERROR("No packet3 for relocation for packet at %d.\n", 168 p3reloc.idx); 169 return -EINVAL; 170 } 171 idx = radeon_get_ib_value(p, p3reloc.idx + 1); 172 if (idx >= relocs_chunk->length_dw) { 173 DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", 174 idx, relocs_chunk->length_dw); 175 return -EINVAL; 176 } 177 *cs_reloc = p->relocs; 178 (*cs_reloc)->lobj.gpu_offset = (u64)relocs_chunk->kdata[idx + 3] << 32; 179 (*cs_reloc)->lobj.gpu_offset |= relocs_chunk->kdata[idx + 0]; 180 return 0; 181 } 182 183 /** 184 * r600_cs_packet_next_is_pkt3_nop() - test if next packet is packet3 nop for reloc 185 * @parser: parser structure holding parsing context. 186 * 187 * Check next packet is relocation packet3, do bo validation and compute 188 * GPU offset using the provided start. 189 **/ 190 static inline int r600_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p) 191 { 192 struct radeon_cs_packet p3reloc; 193 int r; 194 195 r = r600_cs_packet_parse(p, &p3reloc, p->idx); 196 if (r) { 197 return 0; 198 } 199 if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) { 200 return 0; 201 } 202 return 1; 203 } 204 205 /** 206 * r600_cs_packet_next_vline() - parse userspace VLINE packet 207 * @parser: parser structure holding parsing context. 208 * 209 * Userspace sends a special sequence for VLINE waits. 210 * PACKET0 - VLINE_START_END + value 211 * PACKET3 - WAIT_REG_MEM poll vline status reg 212 * RELOC (P3) - crtc_id in reloc. 213 * 214 * This function parses this and relocates the VLINE START END 215 * and WAIT_REG_MEM packets to the correct crtc. 216 * It also detects a switched off crtc and nulls out the 217 * wait in that case. 218 */ 219 static int r600_cs_packet_parse_vline(struct radeon_cs_parser *p) 220 { 221 struct drm_mode_object *obj; 222 struct drm_crtc *crtc; 223 struct radeon_crtc *radeon_crtc; 224 struct radeon_cs_packet p3reloc, wait_reg_mem; 225 int crtc_id; 226 int r; 227 uint32_t header, h_idx, reg, wait_reg_mem_info; 228 volatile uint32_t *ib; 229 230 ib = p->ib->ptr; 231 232 /* parse the WAIT_REG_MEM */ 233 r = r600_cs_packet_parse(p, &wait_reg_mem, p->idx); 234 if (r) 235 return r; 236 237 /* check its a WAIT_REG_MEM */ 238 if (wait_reg_mem.type != PACKET_TYPE3 || 239 wait_reg_mem.opcode != PACKET3_WAIT_REG_MEM) { 240 DRM_ERROR("vline wait missing WAIT_REG_MEM segment\n"); 241 r = -EINVAL; 242 return r; 243 } 244 245 wait_reg_mem_info = radeon_get_ib_value(p, wait_reg_mem.idx + 1); 246 /* bit 4 is reg (0) or mem (1) */ 247 if (wait_reg_mem_info & 0x10) { 248 DRM_ERROR("vline WAIT_REG_MEM waiting on MEM rather than REG\n"); 249 r = -EINVAL; 250 return r; 251 } 252 /* waiting for value to be equal */ 253 if ((wait_reg_mem_info & 0x7) != 0x3) { 254 DRM_ERROR("vline WAIT_REG_MEM function not equal\n"); 255 r = -EINVAL; 256 return r; 257 } 258 if ((radeon_get_ib_value(p, wait_reg_mem.idx + 2) << 2) != AVIVO_D1MODE_VLINE_STATUS) { 259 DRM_ERROR("vline WAIT_REG_MEM bad reg\n"); 260 r = -EINVAL; 261 return r; 262 } 263 264 if (radeon_get_ib_value(p, wait_reg_mem.idx + 5) != AVIVO_D1MODE_VLINE_STAT) { 265 DRM_ERROR("vline WAIT_REG_MEM bad bit mask\n"); 266 r = -EINVAL; 267 return r; 268 } 269 270 /* jump over the NOP */ 271 r = r600_cs_packet_parse(p, &p3reloc, p->idx + wait_reg_mem.count + 2); 272 if (r) 273 return r; 274 275 h_idx = p->idx - 2; 276 p->idx += wait_reg_mem.count + 2; 277 p->idx += p3reloc.count + 2; 278 279 header = radeon_get_ib_value(p, h_idx); 280 crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1); 281 reg = CP_PACKET0_GET_REG(header); 282 mutex_lock(&p->rdev->ddev->mode_config.mutex); 283 obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC); 284 if (!obj) { 285 DRM_ERROR("cannot find crtc %d\n", crtc_id); 286 r = -EINVAL; 287 goto out; 288 } 289 crtc = obj_to_crtc(obj); 290 radeon_crtc = to_radeon_crtc(crtc); 291 crtc_id = radeon_crtc->crtc_id; 292 293 if (!crtc->enabled) { 294 /* if the CRTC isn't enabled - we need to nop out the WAIT_REG_MEM */ 295 ib[h_idx + 2] = PACKET2(0); 296 ib[h_idx + 3] = PACKET2(0); 297 ib[h_idx + 4] = PACKET2(0); 298 ib[h_idx + 5] = PACKET2(0); 299 ib[h_idx + 6] = PACKET2(0); 300 ib[h_idx + 7] = PACKET2(0); 301 ib[h_idx + 8] = PACKET2(0); 302 } else if (crtc_id == 1) { 303 switch (reg) { 304 case AVIVO_D1MODE_VLINE_START_END: 305 header &= ~R600_CP_PACKET0_REG_MASK; 306 header |= AVIVO_D2MODE_VLINE_START_END >> 2; 307 break; 308 default: 309 DRM_ERROR("unknown crtc reloc\n"); 310 r = -EINVAL; 311 goto out; 312 } 313 ib[h_idx] = header; 314 ib[h_idx + 4] = AVIVO_D2MODE_VLINE_STATUS >> 2; 315 } 316 out: 317 mutex_unlock(&p->rdev->ddev->mode_config.mutex); 318 return r; 319 } 320 321 static int r600_packet0_check(struct radeon_cs_parser *p, 322 struct radeon_cs_packet *pkt, 323 unsigned idx, unsigned reg) 324 { 325 int r; 326 327 switch (reg) { 328 case AVIVO_D1MODE_VLINE_START_END: 329 r = r600_cs_packet_parse_vline(p); 330 if (r) { 331 DRM_ERROR("No reloc for ib[%d]=0x%04X\n", 332 idx, reg); 333 return r; 334 } 335 break; 336 default: 337 printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", 338 reg, idx); 339 return -EINVAL; 340 } 341 return 0; 342 } 343 344 static int r600_cs_parse_packet0(struct radeon_cs_parser *p, 345 struct radeon_cs_packet *pkt) 346 { 347 unsigned reg, i; 348 unsigned idx; 349 int r; 350 351 idx = pkt->idx + 1; 352 reg = pkt->reg; 353 for (i = 0; i <= pkt->count; i++, idx++, reg += 4) { 354 r = r600_packet0_check(p, pkt, idx, reg); 355 if (r) { 356 return r; 357 } 358 } 359 return 0; 360 } 361 362 static int r600_packet3_check(struct radeon_cs_parser *p, 363 struct radeon_cs_packet *pkt) 364 { 365 struct radeon_cs_reloc *reloc; 366 struct r600_cs_track *track; 367 volatile u32 *ib; 368 unsigned idx; 369 unsigned i; 370 unsigned start_reg, end_reg, reg; 371 int r; 372 u32 idx_value; 373 374 track = (struct r600_cs_track *)p->track; 375 ib = p->ib->ptr; 376 idx = pkt->idx + 1; 377 idx_value = radeon_get_ib_value(p, idx); 378 379 switch (pkt->opcode) { 380 case PACKET3_START_3D_CMDBUF: 381 if (p->family >= CHIP_RV770 || pkt->count) { 382 DRM_ERROR("bad START_3D\n"); 383 return -EINVAL; 384 } 385 break; 386 case PACKET3_CONTEXT_CONTROL: 387 if (pkt->count != 1) { 388 DRM_ERROR("bad CONTEXT_CONTROL\n"); 389 return -EINVAL; 390 } 391 break; 392 case PACKET3_INDEX_TYPE: 393 case PACKET3_NUM_INSTANCES: 394 if (pkt->count) { 395 DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES\n"); 396 return -EINVAL; 397 } 398 break; 399 case PACKET3_DRAW_INDEX: 400 if (pkt->count != 3) { 401 DRM_ERROR("bad DRAW_INDEX\n"); 402 return -EINVAL; 403 } 404 r = r600_cs_packet_next_reloc(p, &reloc); 405 if (r) { 406 DRM_ERROR("bad DRAW_INDEX\n"); 407 return -EINVAL; 408 } 409 ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff); 410 ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; 411 break; 412 case PACKET3_DRAW_INDEX_AUTO: 413 if (pkt->count != 1) { 414 DRM_ERROR("bad DRAW_INDEX_AUTO\n"); 415 return -EINVAL; 416 } 417 break; 418 case PACKET3_DRAW_INDEX_IMMD_BE: 419 case PACKET3_DRAW_INDEX_IMMD: 420 if (pkt->count < 2) { 421 DRM_ERROR("bad DRAW_INDEX_IMMD\n"); 422 return -EINVAL; 423 } 424 break; 425 case PACKET3_WAIT_REG_MEM: 426 if (pkt->count != 5) { 427 DRM_ERROR("bad WAIT_REG_MEM\n"); 428 return -EINVAL; 429 } 430 /* bit 4 is reg (0) or mem (1) */ 431 if (idx_value & 0x10) { 432 r = r600_cs_packet_next_reloc(p, &reloc); 433 if (r) { 434 DRM_ERROR("bad WAIT_REG_MEM\n"); 435 return -EINVAL; 436 } 437 ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); 438 ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; 439 } 440 break; 441 case PACKET3_SURFACE_SYNC: 442 if (pkt->count != 3) { 443 DRM_ERROR("bad SURFACE_SYNC\n"); 444 return -EINVAL; 445 } 446 /* 0xffffffff/0x0 is flush all cache flag */ 447 if (radeon_get_ib_value(p, idx + 1) != 0xffffffff || 448 radeon_get_ib_value(p, idx + 2) != 0) { 449 r = r600_cs_packet_next_reloc(p, &reloc); 450 if (r) { 451 DRM_ERROR("bad SURFACE_SYNC\n"); 452 return -EINVAL; 453 } 454 ib[idx+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); 455 } 456 break; 457 case PACKET3_EVENT_WRITE: 458 if (pkt->count != 2 && pkt->count != 0) { 459 DRM_ERROR("bad EVENT_WRITE\n"); 460 return -EINVAL; 461 } 462 if (pkt->count) { 463 r = r600_cs_packet_next_reloc(p, &reloc); 464 if (r) { 465 DRM_ERROR("bad EVENT_WRITE\n"); 466 return -EINVAL; 467 } 468 ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); 469 ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; 470 } 471 break; 472 case PACKET3_EVENT_WRITE_EOP: 473 if (pkt->count != 4) { 474 DRM_ERROR("bad EVENT_WRITE_EOP\n"); 475 return -EINVAL; 476 } 477 r = r600_cs_packet_next_reloc(p, &reloc); 478 if (r) { 479 DRM_ERROR("bad EVENT_WRITE\n"); 480 return -EINVAL; 481 } 482 ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff); 483 ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; 484 break; 485 case PACKET3_SET_CONFIG_REG: 486 start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_OFFSET; 487 end_reg = 4 * pkt->count + start_reg - 4; 488 if ((start_reg < PACKET3_SET_CONFIG_REG_OFFSET) || 489 (start_reg >= PACKET3_SET_CONFIG_REG_END) || 490 (end_reg >= PACKET3_SET_CONFIG_REG_END)) { 491 DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n"); 492 return -EINVAL; 493 } 494 for (i = 0; i < pkt->count; i++) { 495 reg = start_reg + (4 * i); 496 switch (reg) { 497 case SQ_ESGS_RING_BASE: 498 case SQ_GSVS_RING_BASE: 499 case SQ_ESTMP_RING_BASE: 500 case SQ_GSTMP_RING_BASE: 501 case SQ_VSTMP_RING_BASE: 502 case SQ_PSTMP_RING_BASE: 503 case SQ_FBUF_RING_BASE: 504 case SQ_REDUC_RING_BASE: 505 case SX_MEMORY_EXPORT_BASE: 506 r = r600_cs_packet_next_reloc(p, &reloc); 507 if (r) { 508 DRM_ERROR("bad SET_CONFIG_REG " 509 "0x%04X\n", reg); 510 return -EINVAL; 511 } 512 ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); 513 break; 514 case CP_COHER_BASE: 515 /* use PACKET3_SURFACE_SYNC */ 516 return -EINVAL; 517 default: 518 break; 519 } 520 } 521 break; 522 case PACKET3_SET_CONTEXT_REG: 523 start_reg = (idx_value << 2) + PACKET3_SET_CONTEXT_REG_OFFSET; 524 end_reg = 4 * pkt->count + start_reg - 4; 525 if ((start_reg < PACKET3_SET_CONTEXT_REG_OFFSET) || 526 (start_reg >= PACKET3_SET_CONTEXT_REG_END) || 527 (end_reg >= PACKET3_SET_CONTEXT_REG_END)) { 528 DRM_ERROR("bad PACKET3_SET_CONTEXT_REG\n"); 529 return -EINVAL; 530 } 531 for (i = 0; i < pkt->count; i++) { 532 reg = start_reg + (4 * i); 533 switch (reg) { 534 /* This register were added late, there is userspace 535 * which does provide relocation for those but set 536 * 0 offset. In order to avoid breaking old userspace 537 * we detect this and set address to point to last 538 * CB_COLOR0_BASE, note that if userspace doesn't set 539 * CB_COLOR0_BASE before this register we will report 540 * error. Old userspace always set CB_COLOR0_BASE 541 * before any of this. 542 */ 543 case R_0280E0_CB_COLOR0_FRAG: 544 case R_0280E4_CB_COLOR1_FRAG: 545 case R_0280E8_CB_COLOR2_FRAG: 546 case R_0280EC_CB_COLOR3_FRAG: 547 case R_0280F0_CB_COLOR4_FRAG: 548 case R_0280F4_CB_COLOR5_FRAG: 549 case R_0280F8_CB_COLOR6_FRAG: 550 case R_0280FC_CB_COLOR7_FRAG: 551 case R_0280C0_CB_COLOR0_TILE: 552 case R_0280C4_CB_COLOR1_TILE: 553 case R_0280C8_CB_COLOR2_TILE: 554 case R_0280CC_CB_COLOR3_TILE: 555 case R_0280D0_CB_COLOR4_TILE: 556 case R_0280D4_CB_COLOR5_TILE: 557 case R_0280D8_CB_COLOR6_TILE: 558 case R_0280DC_CB_COLOR7_TILE: 559 if (!r600_cs_packet_next_is_pkt3_nop(p)) { 560 if (!track->cb_color0_base_last) { 561 dev_err(p->dev, "Broken old userspace ? no cb_color0_base supplied before trying to write 0x%08X\n", reg); 562 return -EINVAL; 563 } 564 ib[idx+1+i] = track->cb_color0_base_last; 565 printk_once(KERN_WARNING "radeon: You have old & broken userspace " 566 "please consider updating mesa & xf86-video-ati\n"); 567 } else { 568 r = r600_cs_packet_next_reloc(p, &reloc); 569 if (r) { 570 dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); 571 return -EINVAL; 572 } 573 ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); 574 } 575 break; 576 case DB_DEPTH_BASE: 577 case DB_HTILE_DATA_BASE: 578 case CB_COLOR0_BASE: 579 r = r600_cs_packet_next_reloc(p, &reloc); 580 if (r) { 581 DRM_ERROR("bad SET_CONTEXT_REG " 582 "0x%04X\n", reg); 583 return -EINVAL; 584 } 585 ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); 586 track->cb_color0_base_last = ib[idx+1+i]; 587 break; 588 case CB_COLOR1_BASE: 589 case CB_COLOR2_BASE: 590 case CB_COLOR3_BASE: 591 case CB_COLOR4_BASE: 592 case CB_COLOR5_BASE: 593 case CB_COLOR6_BASE: 594 case CB_COLOR7_BASE: 595 case SQ_PGM_START_FS: 596 case SQ_PGM_START_ES: 597 case SQ_PGM_START_VS: 598 case SQ_PGM_START_GS: 599 case SQ_PGM_START_PS: 600 r = r600_cs_packet_next_reloc(p, &reloc); 601 if (r) { 602 DRM_ERROR("bad SET_CONTEXT_REG " 603 "0x%04X\n", reg); 604 return -EINVAL; 605 } 606 ib[idx+1+i] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); 607 break; 608 case VGT_DMA_BASE: 609 case VGT_DMA_BASE_HI: 610 /* These should be handled by DRAW_INDEX packet 3 */ 611 case VGT_STRMOUT_BASE_OFFSET_0: 612 case VGT_STRMOUT_BASE_OFFSET_1: 613 case VGT_STRMOUT_BASE_OFFSET_2: 614 case VGT_STRMOUT_BASE_OFFSET_3: 615 case VGT_STRMOUT_BASE_OFFSET_HI_0: 616 case VGT_STRMOUT_BASE_OFFSET_HI_1: 617 case VGT_STRMOUT_BASE_OFFSET_HI_2: 618 case VGT_STRMOUT_BASE_OFFSET_HI_3: 619 case VGT_STRMOUT_BUFFER_BASE_0: 620 case VGT_STRMOUT_BUFFER_BASE_1: 621 case VGT_STRMOUT_BUFFER_BASE_2: 622 case VGT_STRMOUT_BUFFER_BASE_3: 623 case VGT_STRMOUT_BUFFER_OFFSET_0: 624 case VGT_STRMOUT_BUFFER_OFFSET_1: 625 case VGT_STRMOUT_BUFFER_OFFSET_2: 626 case VGT_STRMOUT_BUFFER_OFFSET_3: 627 /* These should be handled by STRMOUT_BUFFER packet 3 */ 628 DRM_ERROR("bad context reg: 0x%08x\n", reg); 629 return -EINVAL; 630 default: 631 break; 632 } 633 } 634 break; 635 case PACKET3_SET_RESOURCE: 636 if (pkt->count % 7) { 637 DRM_ERROR("bad SET_RESOURCE\n"); 638 return -EINVAL; 639 } 640 start_reg = (idx_value << 2) + PACKET3_SET_RESOURCE_OFFSET; 641 end_reg = 4 * pkt->count + start_reg - 4; 642 if ((start_reg < PACKET3_SET_RESOURCE_OFFSET) || 643 (start_reg >= PACKET3_SET_RESOURCE_END) || 644 (end_reg >= PACKET3_SET_RESOURCE_END)) { 645 DRM_ERROR("bad SET_RESOURCE\n"); 646 return -EINVAL; 647 } 648 for (i = 0; i < (pkt->count / 7); i++) { 649 switch (G__SQ_VTX_CONSTANT_TYPE(radeon_get_ib_value(p, idx+(i*7)+6+1))) { 650 case SQ_TEX_VTX_VALID_TEXTURE: 651 /* tex base */ 652 r = r600_cs_packet_next_reloc(p, &reloc); 653 if (r) { 654 DRM_ERROR("bad SET_RESOURCE\n"); 655 return -EINVAL; 656 } 657 ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); 658 /* tex mip base */ 659 r = r600_cs_packet_next_reloc(p, &reloc); 660 if (r) { 661 DRM_ERROR("bad SET_RESOURCE\n"); 662 return -EINVAL; 663 } 664 ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); 665 break; 666 case SQ_TEX_VTX_VALID_BUFFER: 667 /* vtx base */ 668 r = r600_cs_packet_next_reloc(p, &reloc); 669 if (r) { 670 DRM_ERROR("bad SET_RESOURCE\n"); 671 return -EINVAL; 672 } 673 ib[idx+1+(i*7)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff); 674 ib[idx+1+(i*7)+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff; 675 break; 676 case SQ_TEX_VTX_INVALID_TEXTURE: 677 case SQ_TEX_VTX_INVALID_BUFFER: 678 default: 679 DRM_ERROR("bad SET_RESOURCE\n"); 680 return -EINVAL; 681 } 682 } 683 break; 684 case PACKET3_SET_ALU_CONST: 685 start_reg = (idx_value << 2) + PACKET3_SET_ALU_CONST_OFFSET; 686 end_reg = 4 * pkt->count + start_reg - 4; 687 if ((start_reg < PACKET3_SET_ALU_CONST_OFFSET) || 688 (start_reg >= PACKET3_SET_ALU_CONST_END) || 689 (end_reg >= PACKET3_SET_ALU_CONST_END)) { 690 DRM_ERROR("bad SET_ALU_CONST\n"); 691 return -EINVAL; 692 } 693 break; 694 case PACKET3_SET_BOOL_CONST: 695 start_reg = (idx_value << 2) + PACKET3_SET_BOOL_CONST_OFFSET; 696 end_reg = 4 * pkt->count + start_reg - 4; 697 if ((start_reg < PACKET3_SET_BOOL_CONST_OFFSET) || 698 (start_reg >= PACKET3_SET_BOOL_CONST_END) || 699 (end_reg >= PACKET3_SET_BOOL_CONST_END)) { 700 DRM_ERROR("bad SET_BOOL_CONST\n"); 701 return -EINVAL; 702 } 703 break; 704 case PACKET3_SET_LOOP_CONST: 705 start_reg = (idx_value << 2) + PACKET3_SET_LOOP_CONST_OFFSET; 706 end_reg = 4 * pkt->count + start_reg - 4; 707 if ((start_reg < PACKET3_SET_LOOP_CONST_OFFSET) || 708 (start_reg >= PACKET3_SET_LOOP_CONST_END) || 709 (end_reg >= PACKET3_SET_LOOP_CONST_END)) { 710 DRM_ERROR("bad SET_LOOP_CONST\n"); 711 return -EINVAL; 712 } 713 break; 714 case PACKET3_SET_CTL_CONST: 715 start_reg = (idx_value << 2) + PACKET3_SET_CTL_CONST_OFFSET; 716 end_reg = 4 * pkt->count + start_reg - 4; 717 if ((start_reg < PACKET3_SET_CTL_CONST_OFFSET) || 718 (start_reg >= PACKET3_SET_CTL_CONST_END) || 719 (end_reg >= PACKET3_SET_CTL_CONST_END)) { 720 DRM_ERROR("bad SET_CTL_CONST\n"); 721 return -EINVAL; 722 } 723 break; 724 case PACKET3_SET_SAMPLER: 725 if (pkt->count % 3) { 726 DRM_ERROR("bad SET_SAMPLER\n"); 727 return -EINVAL; 728 } 729 start_reg = (idx_value << 2) + PACKET3_SET_SAMPLER_OFFSET; 730 end_reg = 4 * pkt->count + start_reg - 4; 731 if ((start_reg < PACKET3_SET_SAMPLER_OFFSET) || 732 (start_reg >= PACKET3_SET_SAMPLER_END) || 733 (end_reg >= PACKET3_SET_SAMPLER_END)) { 734 DRM_ERROR("bad SET_SAMPLER\n"); 735 return -EINVAL; 736 } 737 break; 738 case PACKET3_SURFACE_BASE_UPDATE: 739 if (p->family >= CHIP_RV770 || p->family == CHIP_R600) { 740 DRM_ERROR("bad SURFACE_BASE_UPDATE\n"); 741 return -EINVAL; 742 } 743 if (pkt->count) { 744 DRM_ERROR("bad SURFACE_BASE_UPDATE\n"); 745 return -EINVAL; 746 } 747 break; 748 case PACKET3_NOP: 749 break; 750 default: 751 DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode); 752 return -EINVAL; 753 } 754 return 0; 755 } 756 757 int r600_cs_parse(struct radeon_cs_parser *p) 758 { 759 struct radeon_cs_packet pkt; 760 struct r600_cs_track *track; 761 int r; 762 763 track = kzalloc(sizeof(*track), GFP_KERNEL); 764 p->track = track; 765 do { 766 r = r600_cs_packet_parse(p, &pkt, p->idx); 767 if (r) { 768 return r; 769 } 770 p->idx += pkt.count + 2; 771 switch (pkt.type) { 772 case PACKET_TYPE0: 773 r = r600_cs_parse_packet0(p, &pkt); 774 break; 775 case PACKET_TYPE2: 776 break; 777 case PACKET_TYPE3: 778 r = r600_packet3_check(p, &pkt); 779 break; 780 default: 781 DRM_ERROR("Unknown packet type %d !\n", pkt.type); 782 return -EINVAL; 783 } 784 if (r) { 785 return r; 786 } 787 } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); 788 #if 0 789 for (r = 0; r < p->ib->length_dw; r++) { 790 printk(KERN_INFO "%05d 0x%08X\n", r, p->ib->ptr[r]); 791 mdelay(1); 792 } 793 #endif 794 return 0; 795 } 796 797 static int r600_cs_parser_relocs_legacy(struct radeon_cs_parser *p) 798 { 799 if (p->chunk_relocs_idx == -1) { 800 return 0; 801 } 802 p->relocs = kzalloc(sizeof(struct radeon_cs_reloc), GFP_KERNEL); 803 if (p->relocs == NULL) { 804 return -ENOMEM; 805 } 806 return 0; 807 } 808 809 /** 810 * cs_parser_fini() - clean parser states 811 * @parser: parser structure holding parsing context. 812 * @error: error number 813 * 814 * If error is set than unvalidate buffer, otherwise just free memory 815 * used by parsing context. 816 **/ 817 static void r600_cs_parser_fini(struct radeon_cs_parser *parser, int error) 818 { 819 unsigned i; 820 821 kfree(parser->relocs); 822 for (i = 0; i < parser->nchunks; i++) { 823 kfree(parser->chunks[i].kdata); 824 kfree(parser->chunks[i].kpage[0]); 825 kfree(parser->chunks[i].kpage[1]); 826 } 827 kfree(parser->chunks); 828 kfree(parser->chunks_array); 829 } 830 831 int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp, 832 unsigned family, u32 *ib, int *l) 833 { 834 struct radeon_cs_parser parser; 835 struct radeon_cs_chunk *ib_chunk; 836 struct radeon_ib fake_ib; 837 int r; 838 839 /* initialize parser */ 840 memset(&parser, 0, sizeof(struct radeon_cs_parser)); 841 parser.filp = filp; 842 parser.dev = &dev->pdev->dev; 843 parser.rdev = NULL; 844 parser.family = family; 845 parser.ib = &fake_ib; 846 fake_ib.ptr = ib; 847 r = radeon_cs_parser_init(&parser, data); 848 if (r) { 849 DRM_ERROR("Failed to initialize parser !\n"); 850 r600_cs_parser_fini(&parser, r); 851 return r; 852 } 853 r = r600_cs_parser_relocs_legacy(&parser); 854 if (r) { 855 DRM_ERROR("Failed to parse relocation !\n"); 856 r600_cs_parser_fini(&parser, r); 857 return r; 858 } 859 /* Copy the packet into the IB, the parser will read from the 860 * input memory (cached) and write to the IB (which can be 861 * uncached). */ 862 ib_chunk = &parser.chunks[parser.chunk_ib_idx]; 863 parser.ib->length_dw = ib_chunk->length_dw; 864 *l = parser.ib->length_dw; 865 r = r600_cs_parse(&parser); 866 if (r) { 867 DRM_ERROR("Invalid command stream !\n"); 868 r600_cs_parser_fini(&parser, r); 869 return r; 870 } 871 r = radeon_cs_finish_pages(&parser); 872 if (r) { 873 DRM_ERROR("Invalid command stream !\n"); 874 r600_cs_parser_fini(&parser, r); 875 return r; 876 } 877 r600_cs_parser_fini(&parser, r); 878 return r; 879 } 880 881 void r600_cs_legacy_init(void) 882 { 883 r600_cs_packet_next_reloc = &r600_cs_packet_next_reloc_nomm; 884 } 885