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