1 /* 2 * Copyright 2013 Advanced Micro Devices, Inc. 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 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19 * USE OR OTHER DEALINGS IN THE SOFTWARE. 20 * 21 * The above copyright notice and this permission notice (including the 22 * next paragraph) shall be included in all copies or substantial portions 23 * of the Software. 24 * 25 * Authors: Christian König <christian.koenig@amd.com> 26 */ 27 28 #include <linux/firmware.h> 29 #include <linux/module.h> 30 #include <drm/drmP.h> 31 32 #include "radeon.h" 33 #include "radeon_asic.h" 34 #include "sid.h" 35 36 /* 1 second timeout */ 37 #define VCE_IDLE_TIMEOUT_MS 1000 38 39 /* Firmware Names */ 40 #define FIRMWARE_BONAIRE "radeonkmsfw_BONAIRE_vce" 41 42 MODULE_FIRMWARE(FIRMWARE_BONAIRE); 43 44 static void radeon_vce_idle_work_handler(struct work_struct *work); 45 46 /** 47 * radeon_vce_init - allocate memory, load vce firmware 48 * 49 * @rdev: radeon_device pointer 50 * 51 * First step to get VCE online, allocate memory and load the firmware 52 */ 53 int radeon_vce_init(struct radeon_device *rdev) 54 { 55 static const char *fw_version = "[ATI LIB=VCEFW,"; 56 static const char *fb_version = "[ATI LIB=VCEFWSTATS,"; 57 unsigned long size; 58 const char *fw_name, *c; 59 uint8_t start, mid, end; 60 int i, r; 61 62 INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler); 63 64 switch (rdev->family) { 65 case CHIP_BONAIRE: 66 case CHIP_KAVERI: 67 case CHIP_KABINI: 68 case CHIP_HAWAII: 69 case CHIP_MULLINS: 70 fw_name = FIRMWARE_BONAIRE; 71 break; 72 73 default: 74 return -EINVAL; 75 } 76 77 r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev); 78 if (r) { 79 dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n", 80 fw_name); 81 return r; 82 } 83 84 /* search for firmware version */ 85 86 size = rdev->vce_fw->datasize - strlen(fw_version) - 9; 87 c = rdev->vce_fw->data; 88 for (;size > 0; --size, ++c) 89 if (strncmp(c, fw_version, strlen(fw_version)) == 0) 90 break; 91 92 if (size == 0) 93 return -EINVAL; 94 95 c += strlen(fw_version); 96 if (ksscanf(c, "%2hhd.%2hhd.%2hhd]", &start, &mid, &end) != 3) 97 return -EINVAL; 98 99 /* search for feedback version */ 100 101 size = rdev->vce_fw->datasize - strlen(fb_version) - 3; 102 c = rdev->vce_fw->data; 103 for (;size > 0; --size, ++c) 104 if (strncmp(c, fb_version, strlen(fb_version)) == 0) 105 break; 106 107 if (size == 0) 108 return -EINVAL; 109 110 c += strlen(fb_version); 111 if (ksscanf(c, "%2u]", &rdev->vce.fb_version) != 1) 112 return -EINVAL; 113 114 DRM_INFO("Found VCE firmware/feedback version %hhd.%hhd.%hhd / %d!\n", 115 start, mid, end, rdev->vce.fb_version); 116 117 rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8); 118 119 /* we can only work with this fw version for now */ 120 if (rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) 121 return -EINVAL; 122 123 /* allocate firmware, stack and heap BO */ 124 125 size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->datasize) + 126 RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE; 127 r = radeon_bo_create(rdev, size, PAGE_SIZE, true, 128 RADEON_GEM_DOMAIN_VRAM, 0, NULL, &rdev->vce.vcpu_bo); 129 if (r) { 130 dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r); 131 return r; 132 } 133 134 r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); 135 if (r) { 136 radeon_bo_unref(&rdev->vce.vcpu_bo); 137 dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); 138 return r; 139 } 140 141 r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, 142 &rdev->vce.gpu_addr); 143 radeon_bo_unreserve(rdev->vce.vcpu_bo); 144 if (r) { 145 radeon_bo_unref(&rdev->vce.vcpu_bo); 146 dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r); 147 return r; 148 } 149 150 for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 151 atomic_set(&rdev->vce.handles[i], 0); 152 rdev->vce.filp[i] = NULL; 153 } 154 155 return 0; 156 } 157 158 /** 159 * radeon_vce_fini - free memory 160 * 161 * @rdev: radeon_device pointer 162 * 163 * Last step on VCE teardown, free firmware memory 164 */ 165 void radeon_vce_fini(struct radeon_device *rdev) 166 { 167 if (rdev->vce.vcpu_bo == NULL) 168 return; 169 170 radeon_bo_unref(&rdev->vce.vcpu_bo); 171 172 release_firmware(rdev->vce_fw); 173 } 174 175 /** 176 * radeon_vce_suspend - unpin VCE fw memory 177 * 178 * @rdev: radeon_device pointer 179 * 180 */ 181 int radeon_vce_suspend(struct radeon_device *rdev) 182 { 183 int i; 184 185 if (rdev->vce.vcpu_bo == NULL) 186 return 0; 187 188 for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) 189 if (atomic_read(&rdev->vce.handles[i])) 190 break; 191 192 if (i == RADEON_MAX_VCE_HANDLES) 193 return 0; 194 195 /* TODO: suspending running encoding sessions isn't supported */ 196 return -EINVAL; 197 } 198 199 /** 200 * radeon_vce_resume - pin VCE fw memory 201 * 202 * @rdev: radeon_device pointer 203 * 204 */ 205 int radeon_vce_resume(struct radeon_device *rdev) 206 { 207 void *cpu_addr; 208 int r; 209 210 if (rdev->vce.vcpu_bo == NULL) 211 return -EINVAL; 212 213 r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); 214 if (r) { 215 dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); 216 return r; 217 } 218 219 r = radeon_bo_kmap(rdev->vce.vcpu_bo, &cpu_addr); 220 if (r) { 221 radeon_bo_unreserve(rdev->vce.vcpu_bo); 222 dev_err(rdev->dev, "(%d) VCE map failed\n", r); 223 return r; 224 } 225 226 memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->datasize); 227 228 radeon_bo_kunmap(rdev->vce.vcpu_bo); 229 230 radeon_bo_unreserve(rdev->vce.vcpu_bo); 231 232 return 0; 233 } 234 235 /** 236 * radeon_vce_idle_work_handler - power off VCE 237 * 238 * @work: pointer to work structure 239 * 240 * power of VCE when it's not used any more 241 */ 242 static void radeon_vce_idle_work_handler(struct work_struct *work) 243 { 244 struct radeon_device *rdev = 245 container_of(work, struct radeon_device, vce.idle_work.work); 246 247 if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX) == 0) && 248 (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX) == 0)) { 249 if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 250 radeon_dpm_enable_vce(rdev, false); 251 } else { 252 radeon_set_vce_clocks(rdev, 0, 0); 253 } 254 } else { 255 schedule_delayed_work(&rdev->vce.idle_work, 256 msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); 257 } 258 } 259 260 /** 261 * radeon_vce_note_usage - power up VCE 262 * 263 * @rdev: radeon_device pointer 264 * 265 * Make sure VCE is powerd up when we want to use it 266 */ 267 void radeon_vce_note_usage(struct radeon_device *rdev) 268 { 269 bool streams_changed = false; 270 bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work); 271 set_clocks &= schedule_delayed_work(&rdev->vce.idle_work, 272 msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); 273 274 if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 275 /* XXX figure out if the streams changed */ 276 streams_changed = false; 277 } 278 279 if (set_clocks || streams_changed) { 280 if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 281 radeon_dpm_enable_vce(rdev, true); 282 } else { 283 radeon_set_vce_clocks(rdev, 53300, 40000); 284 } 285 } 286 } 287 288 /** 289 * radeon_vce_free_handles - free still open VCE handles 290 * 291 * @rdev: radeon_device pointer 292 * @filp: drm file pointer 293 * 294 * Close all VCE handles still open by this file pointer 295 */ 296 void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) 297 { 298 int i, r; 299 for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 300 uint32_t handle = atomic_read(&rdev->vce.handles[i]); 301 if (!handle || rdev->vce.filp[i] != filp) 302 continue; 303 304 radeon_vce_note_usage(rdev); 305 306 r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, 307 handle, NULL); 308 if (r) 309 DRM_ERROR("Error destroying VCE handle (%d)!\n", r); 310 311 rdev->vce.filp[i] = NULL; 312 atomic_set(&rdev->vce.handles[i], 0); 313 } 314 } 315 316 /** 317 * radeon_vce_get_create_msg - generate a VCE create msg 318 * 319 * @rdev: radeon_device pointer 320 * @ring: ring we should submit the msg to 321 * @handle: VCE session handle to use 322 * @fence: optional fence to return 323 * 324 * Open up a stream for HW test 325 */ 326 int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, 327 uint32_t handle, struct radeon_fence **fence) 328 { 329 const unsigned ib_size_dw = 1024; 330 struct radeon_ib ib; 331 uint64_t dummy; 332 int i, r; 333 334 r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); 335 if (r) { 336 DRM_ERROR("radeon: failed to get ib (%d).\n", r); 337 return r; 338 } 339 340 dummy = ib.gpu_addr + 1024; 341 342 /* stitch together an VCE create msg */ 343 ib.length_dw = 0; 344 ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ 345 ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ 346 ib.ptr[ib.length_dw++] = handle; 347 348 ib.ptr[ib.length_dw++] = 0x00000030; /* len */ 349 ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */ 350 ib.ptr[ib.length_dw++] = 0x00000000; 351 ib.ptr[ib.length_dw++] = 0x00000042; 352 ib.ptr[ib.length_dw++] = 0x0000000a; 353 ib.ptr[ib.length_dw++] = 0x00000001; 354 ib.ptr[ib.length_dw++] = 0x00000080; 355 ib.ptr[ib.length_dw++] = 0x00000060; 356 ib.ptr[ib.length_dw++] = 0x00000100; 357 ib.ptr[ib.length_dw++] = 0x00000100; 358 ib.ptr[ib.length_dw++] = 0x0000000c; 359 ib.ptr[ib.length_dw++] = 0x00000000; 360 361 ib.ptr[ib.length_dw++] = 0x00000014; /* len */ 362 ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ 363 ib.ptr[ib.length_dw++] = upper_32_bits(dummy); 364 ib.ptr[ib.length_dw++] = dummy; 365 ib.ptr[ib.length_dw++] = 0x00000001; 366 367 for (i = ib.length_dw; i < ib_size_dw; ++i) 368 ib.ptr[i] = 0x0; 369 370 r = radeon_ib_schedule(rdev, &ib, NULL, false); 371 if (r) { 372 DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 373 } 374 375 if (fence) 376 *fence = radeon_fence_ref(ib.fence); 377 378 radeon_ib_free(rdev, &ib); 379 380 return r; 381 } 382 383 /** 384 * radeon_vce_get_destroy_msg - generate a VCE destroy msg 385 * 386 * @rdev: radeon_device pointer 387 * @ring: ring we should submit the msg to 388 * @handle: VCE session handle to use 389 * @fence: optional fence to return 390 * 391 * Close up a stream for HW test or if userspace failed to do so 392 */ 393 int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, 394 uint32_t handle, struct radeon_fence **fence) 395 { 396 const unsigned ib_size_dw = 1024; 397 struct radeon_ib ib; 398 uint64_t dummy; 399 int i, r; 400 401 r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); 402 if (r) { 403 DRM_ERROR("radeon: failed to get ib (%d).\n", r); 404 return r; 405 } 406 407 dummy = ib.gpu_addr + 1024; 408 409 /* stitch together an VCE destroy msg */ 410 ib.length_dw = 0; 411 ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ 412 ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ 413 ib.ptr[ib.length_dw++] = handle; 414 415 ib.ptr[ib.length_dw++] = 0x00000014; /* len */ 416 ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ 417 ib.ptr[ib.length_dw++] = upper_32_bits(dummy); 418 ib.ptr[ib.length_dw++] = dummy; 419 ib.ptr[ib.length_dw++] = 0x00000001; 420 421 ib.ptr[ib.length_dw++] = 0x00000008; /* len */ 422 ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */ 423 424 for (i = ib.length_dw; i < ib_size_dw; ++i) 425 ib.ptr[i] = 0x0; 426 427 r = radeon_ib_schedule(rdev, &ib, NULL, false); 428 if (r) { 429 DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 430 } 431 432 if (fence) 433 *fence = radeon_fence_ref(ib.fence); 434 435 radeon_ib_free(rdev, &ib); 436 437 return r; 438 } 439 440 /** 441 * radeon_vce_cs_reloc - command submission relocation 442 * 443 * @p: parser context 444 * @lo: address of lower dword 445 * @hi: address of higher dword 446 * @size: size of checker for relocation buffer 447 * 448 * Patch relocation inside command stream with real buffer address 449 */ 450 int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi, 451 unsigned size) 452 { 453 struct radeon_cs_chunk *relocs_chunk; 454 struct radeon_cs_reloc *reloc; 455 uint64_t start, end, offset; 456 unsigned idx; 457 458 relocs_chunk = &p->chunks[p->chunk_relocs_idx]; 459 offset = radeon_get_ib_value(p, lo); 460 idx = radeon_get_ib_value(p, hi); 461 462 if (idx >= relocs_chunk->length_dw) { 463 DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", 464 idx, relocs_chunk->length_dw); 465 return -EINVAL; 466 } 467 468 reloc = p->relocs_ptr[(idx / 4)]; 469 start = reloc->gpu_offset; 470 end = start + radeon_bo_size(reloc->robj); 471 start += offset; 472 473 p->ib.ptr[lo] = start & 0xFFFFFFFF; 474 p->ib.ptr[hi] = start >> 32; 475 476 if (end <= start) { 477 DRM_ERROR("invalid reloc offset %lX!\n", offset); 478 return -EINVAL; 479 } 480 if ((end - start) < size) { 481 DRM_ERROR("buffer to small (%d / %d)!\n", 482 (unsigned)(end - start), size); 483 return -EINVAL; 484 } 485 486 return 0; 487 } 488 489 /** 490 * radeon_vce_validate_handle - validate stream handle 491 * 492 * @p: parser context 493 * @handle: handle to validate 494 * 495 * Validates the handle and return the found session index or -EINVAL 496 * we we don't have another free session index. 497 */ 498 static int radeon_vce_validate_handle(struct radeon_cs_parser *p, uint32_t handle) 499 { 500 unsigned i; 501 502 /* validate the handle */ 503 for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 504 if (atomic_read(&p->rdev->vce.handles[i]) == handle) 505 return i; 506 } 507 508 /* handle not found try to alloc a new one */ 509 for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 510 if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { 511 p->rdev->vce.filp[i] = p->filp; 512 p->rdev->vce.img_size[i] = 0; 513 return i; 514 } 515 } 516 517 DRM_ERROR("No more free VCE handles!\n"); 518 return -EINVAL; 519 } 520 521 /** 522 * radeon_vce_cs_parse - parse and validate the command stream 523 * 524 * @p: parser context 525 * 526 */ 527 int radeon_vce_cs_parse(struct radeon_cs_parser *p) 528 { 529 int session_idx = -1; 530 bool destroyed = false; 531 uint32_t tmp, handle = 0; 532 uint32_t *size = &tmp; 533 int i, r; 534 535 while (p->idx < p->chunks[p->chunk_ib_idx].length_dw) { 536 uint32_t len = radeon_get_ib_value(p, p->idx); 537 uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); 538 539 if ((len < 8) || (len & 3)) { 540 DRM_ERROR("invalid VCE command length (%d)!\n", len); 541 return -EINVAL; 542 } 543 544 if (destroyed) { 545 DRM_ERROR("No other command allowed after destroy!\n"); 546 return -EINVAL; 547 } 548 549 switch (cmd) { 550 case 0x00000001: // session 551 handle = radeon_get_ib_value(p, p->idx + 2); 552 session_idx = radeon_vce_validate_handle(p, handle); 553 if (session_idx < 0) 554 return session_idx; 555 size = &p->rdev->vce.img_size[session_idx]; 556 break; 557 558 case 0x00000002: // task info 559 break; 560 561 case 0x01000001: // create 562 *size = radeon_get_ib_value(p, p->idx + 8) * 563 radeon_get_ib_value(p, p->idx + 10) * 564 8 * 3 / 2; 565 break; 566 567 case 0x04000001: // config extension 568 case 0x04000002: // pic control 569 case 0x04000005: // rate control 570 case 0x04000007: // motion estimation 571 case 0x04000008: // rdo 572 break; 573 574 case 0x03000001: // encode 575 r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9, 576 *size); 577 if (r) 578 return r; 579 580 r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11, 581 *size / 3); 582 if (r) 583 return r; 584 break; 585 586 case 0x02000001: // destroy 587 destroyed = true; 588 break; 589 590 case 0x05000001: // context buffer 591 r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 592 *size * 2); 593 if (r) 594 return r; 595 break; 596 597 case 0x05000004: // video bitstream buffer 598 tmp = radeon_get_ib_value(p, p->idx + 4); 599 r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 600 tmp); 601 if (r) 602 return r; 603 break; 604 605 case 0x05000005: // feedback buffer 606 r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 607 4096); 608 if (r) 609 return r; 610 break; 611 612 default: 613 DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); 614 return -EINVAL; 615 } 616 617 if (session_idx == -1) { 618 DRM_ERROR("no session command at start of IB\n"); 619 return -EINVAL; 620 } 621 622 p->idx += len / 4; 623 } 624 625 if (destroyed) { 626 /* IB contains a destroy msg, free the handle */ 627 for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) 628 atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0); 629 } 630 631 return 0; 632 } 633 634 /** 635 * radeon_vce_semaphore_emit - emit a semaphore command 636 * 637 * @rdev: radeon_device pointer 638 * @ring: engine to use 639 * @semaphore: address of semaphore 640 * @emit_wait: true=emit wait, false=emit signal 641 * 642 */ 643 bool radeon_vce_semaphore_emit(struct radeon_device *rdev, 644 struct radeon_ring *ring, 645 struct radeon_semaphore *semaphore, 646 bool emit_wait) 647 { 648 uint64_t addr = semaphore->gpu_addr; 649 650 radeon_ring_write(ring, VCE_CMD_SEMAPHORE); 651 radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); 652 radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); 653 radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0)); 654 if (!emit_wait) 655 radeon_ring_write(ring, VCE_CMD_END); 656 657 return true; 658 } 659 660 /** 661 * radeon_vce_ib_execute - execute indirect buffer 662 * 663 * @rdev: radeon_device pointer 664 * @ib: the IB to execute 665 * 666 */ 667 void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) 668 { 669 struct radeon_ring *ring = &rdev->ring[ib->ring]; 670 radeon_ring_write(ring, VCE_CMD_IB); 671 radeon_ring_write(ring, ib->gpu_addr); 672 radeon_ring_write(ring, upper_32_bits(ib->gpu_addr)); 673 radeon_ring_write(ring, ib->length_dw); 674 } 675 676 /** 677 * radeon_vce_fence_emit - add a fence command to the ring 678 * 679 * @rdev: radeon_device pointer 680 * @fence: the fence 681 * 682 */ 683 void radeon_vce_fence_emit(struct radeon_device *rdev, 684 struct radeon_fence *fence) 685 { 686 struct radeon_ring *ring = &rdev->ring[fence->ring]; 687 uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; 688 689 radeon_ring_write(ring, VCE_CMD_FENCE); 690 radeon_ring_write(ring, addr); 691 radeon_ring_write(ring, upper_32_bits(addr)); 692 radeon_ring_write(ring, fence->seq); 693 radeon_ring_write(ring, VCE_CMD_TRAP); 694 radeon_ring_write(ring, VCE_CMD_END); 695 } 696 697 /** 698 * radeon_vce_ring_test - test if VCE ring is working 699 * 700 * @rdev: radeon_device pointer 701 * @ring: the engine to test on 702 * 703 */ 704 int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) 705 { 706 uint32_t rptr = vce_v1_0_get_rptr(rdev, ring); 707 unsigned i; 708 int r; 709 710 r = radeon_ring_lock(rdev, ring, 16); 711 if (r) { 712 DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n", 713 ring->idx, r); 714 return r; 715 } 716 radeon_ring_write(ring, VCE_CMD_END); 717 radeon_ring_unlock_commit(rdev, ring, false); 718 719 for (i = 0; i < rdev->usec_timeout; i++) { 720 if (vce_v1_0_get_rptr(rdev, ring) != rptr) 721 break; 722 DRM_UDELAY(1); 723 } 724 725 if (i < rdev->usec_timeout) { 726 DRM_INFO("ring test on %d succeeded in %d usecs\n", 727 ring->idx, i); 728 } else { 729 DRM_ERROR("radeon: ring %d test failed\n", 730 ring->idx); 731 r = -ETIMEDOUT; 732 } 733 734 return r; 735 } 736 737 /** 738 * radeon_vce_ib_test - test if VCE IBs are working 739 * 740 * @rdev: radeon_device pointer 741 * @ring: the engine to test on 742 * 743 */ 744 int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) 745 { 746 struct radeon_fence *fence = NULL; 747 int r; 748 749 r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL); 750 if (r) { 751 DRM_ERROR("radeon: failed to get create msg (%d).\n", r); 752 goto error; 753 } 754 755 r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence); 756 if (r) { 757 DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); 758 goto error; 759 } 760 761 r = radeon_fence_wait(fence, false); 762 if (r) { 763 DRM_ERROR("radeon: fence wait failed (%d).\n", r); 764 } else { 765 DRM_INFO("ib test on ring %d succeeded\n", ring->idx); 766 } 767 error: 768 radeon_fence_unref(&fence); 769 return r; 770 } 771