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 #ifdef zRJ_TODO 511 if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { 512 #else 513 if (!atomic_cmpset(&p->rdev->vce.handles[i], 0, handle)) { 514 #endif 515 p->rdev->vce.filp[i] = p->filp; 516 p->rdev->vce.img_size[i] = 0; 517 return i; 518 } 519 } 520 521 DRM_ERROR("No more free VCE handles!\n"); 522 return -EINVAL; 523 } 524 525 /** 526 * radeon_vce_cs_parse - parse and validate the command stream 527 * 528 * @p: parser context 529 * 530 */ 531 int radeon_vce_cs_parse(struct radeon_cs_parser *p) 532 { 533 int session_idx = -1; 534 bool destroyed = false; 535 uint32_t tmp, handle = 0; 536 uint32_t *size = &tmp; 537 int i, r; 538 539 while (p->idx < p->chunks[p->chunk_ib_idx].length_dw) { 540 uint32_t len = radeon_get_ib_value(p, p->idx); 541 uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); 542 543 if ((len < 8) || (len & 3)) { 544 DRM_ERROR("invalid VCE command length (%d)!\n", len); 545 return -EINVAL; 546 } 547 548 if (destroyed) { 549 DRM_ERROR("No other command allowed after destroy!\n"); 550 return -EINVAL; 551 } 552 553 switch (cmd) { 554 case 0x00000001: // session 555 handle = radeon_get_ib_value(p, p->idx + 2); 556 session_idx = radeon_vce_validate_handle(p, handle); 557 if (session_idx < 0) 558 return session_idx; 559 size = &p->rdev->vce.img_size[session_idx]; 560 break; 561 562 case 0x00000002: // task info 563 break; 564 565 case 0x01000001: // create 566 *size = radeon_get_ib_value(p, p->idx + 8) * 567 radeon_get_ib_value(p, p->idx + 10) * 568 8 * 3 / 2; 569 break; 570 571 case 0x04000001: // config extension 572 case 0x04000002: // pic control 573 case 0x04000005: // rate control 574 case 0x04000007: // motion estimation 575 case 0x04000008: // rdo 576 break; 577 578 case 0x03000001: // encode 579 r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9, 580 *size); 581 if (r) 582 return r; 583 584 r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11, 585 *size / 3); 586 if (r) 587 return r; 588 break; 589 590 case 0x02000001: // destroy 591 destroyed = true; 592 break; 593 594 case 0x05000001: // context buffer 595 r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 596 *size * 2); 597 if (r) 598 return r; 599 break; 600 601 case 0x05000004: // video bitstream buffer 602 tmp = radeon_get_ib_value(p, p->idx + 4); 603 r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 604 tmp); 605 if (r) 606 return r; 607 break; 608 609 case 0x05000005: // feedback buffer 610 r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 611 4096); 612 if (r) 613 return r; 614 break; 615 616 default: 617 DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); 618 return -EINVAL; 619 } 620 621 if (session_idx == -1) { 622 DRM_ERROR("no session command at start of IB\n"); 623 return -EINVAL; 624 } 625 626 p->idx += len / 4; 627 } 628 629 if (destroyed) { 630 /* IB contains a destroy msg, free the handle */ 631 for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) 632 atomic_cmpset(&p->rdev->vce.handles[i], handle, 0); 633 } 634 635 return 0; 636 } 637 638 /** 639 * radeon_vce_semaphore_emit - emit a semaphore command 640 * 641 * @rdev: radeon_device pointer 642 * @ring: engine to use 643 * @semaphore: address of semaphore 644 * @emit_wait: true=emit wait, false=emit signal 645 * 646 */ 647 bool radeon_vce_semaphore_emit(struct radeon_device *rdev, 648 struct radeon_ring *ring, 649 struct radeon_semaphore *semaphore, 650 bool emit_wait) 651 { 652 uint64_t addr = semaphore->gpu_addr; 653 654 radeon_ring_write(ring, VCE_CMD_SEMAPHORE); 655 radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); 656 radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); 657 radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0)); 658 if (!emit_wait) 659 radeon_ring_write(ring, VCE_CMD_END); 660 661 return true; 662 } 663 664 /** 665 * radeon_vce_ib_execute - execute indirect buffer 666 * 667 * @rdev: radeon_device pointer 668 * @ib: the IB to execute 669 * 670 */ 671 void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) 672 { 673 struct radeon_ring *ring = &rdev->ring[ib->ring]; 674 radeon_ring_write(ring, VCE_CMD_IB); 675 radeon_ring_write(ring, ib->gpu_addr); 676 radeon_ring_write(ring, upper_32_bits(ib->gpu_addr)); 677 radeon_ring_write(ring, ib->length_dw); 678 } 679 680 /** 681 * radeon_vce_fence_emit - add a fence command to the ring 682 * 683 * @rdev: radeon_device pointer 684 * @fence: the fence 685 * 686 */ 687 void radeon_vce_fence_emit(struct radeon_device *rdev, 688 struct radeon_fence *fence) 689 { 690 struct radeon_ring *ring = &rdev->ring[fence->ring]; 691 uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; 692 693 radeon_ring_write(ring, VCE_CMD_FENCE); 694 radeon_ring_write(ring, addr); 695 radeon_ring_write(ring, upper_32_bits(addr)); 696 radeon_ring_write(ring, fence->seq); 697 radeon_ring_write(ring, VCE_CMD_TRAP); 698 radeon_ring_write(ring, VCE_CMD_END); 699 } 700 701 /** 702 * radeon_vce_ring_test - test if VCE ring is working 703 * 704 * @rdev: radeon_device pointer 705 * @ring: the engine to test on 706 * 707 */ 708 int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) 709 { 710 uint32_t rptr = vce_v1_0_get_rptr(rdev, ring); 711 unsigned i; 712 int r; 713 714 r = radeon_ring_lock(rdev, ring, 16); 715 if (r) { 716 DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n", 717 ring->idx, r); 718 return r; 719 } 720 radeon_ring_write(ring, VCE_CMD_END); 721 radeon_ring_unlock_commit(rdev, ring, false); 722 723 for (i = 0; i < rdev->usec_timeout; i++) { 724 if (vce_v1_0_get_rptr(rdev, ring) != rptr) 725 break; 726 DRM_UDELAY(1); 727 } 728 729 if (i < rdev->usec_timeout) { 730 DRM_INFO("ring test on %d succeeded in %d usecs\n", 731 ring->idx, i); 732 } else { 733 DRM_ERROR("radeon: ring %d test failed\n", 734 ring->idx); 735 r = -ETIMEDOUT; 736 } 737 738 return r; 739 } 740 741 /** 742 * radeon_vce_ib_test - test if VCE IBs are working 743 * 744 * @rdev: radeon_device pointer 745 * @ring: the engine to test on 746 * 747 */ 748 int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) 749 { 750 struct radeon_fence *fence = NULL; 751 int r; 752 753 r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL); 754 if (r) { 755 DRM_ERROR("radeon: failed to get create msg (%d).\n", r); 756 goto error; 757 } 758 759 r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence); 760 if (r) { 761 DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); 762 goto error; 763 } 764 765 r = radeon_fence_wait(fence, false); 766 if (r) { 767 DRM_ERROR("radeon: fence wait failed (%d).\n", r); 768 } else { 769 DRM_INFO("ib test on ring %d succeeded\n", ring->idx); 770 } 771 error: 772 radeon_fence_unref(&fence); 773 return r; 774 } 775