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