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