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