diff options
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | 203 | ||||
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | 3 |
2 files changed, 206 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 97b09b63753c..9bb59cc33ace 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c | |||
| @@ -112,6 +112,15 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) | |||
| 112 | return r; | 112 | return r; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | ring = &adev->vcn.ring_enc[0]; | ||
| 116 | rq = &ring->sched.sched_rq[AMD_SCHED_PRIORITY_NORMAL]; | ||
| 117 | r = amd_sched_entity_init(&ring->sched, &adev->vcn.entity_enc, | ||
| 118 | rq, amdgpu_sched_jobs); | ||
| 119 | if (r != 0) { | ||
| 120 | DRM_ERROR("Failed setting up VCN enc run queue.\n"); | ||
| 121 | return r; | ||
| 122 | } | ||
| 123 | |||
| 115 | return 0; | 124 | return 0; |
| 116 | } | 125 | } |
| 117 | 126 | ||
| @@ -121,6 +130,8 @@ int amdgpu_vcn_sw_fini(struct amdgpu_device *adev) | |||
| 121 | 130 | ||
| 122 | amd_sched_entity_fini(&adev->vcn.ring_dec.sched, &adev->vcn.entity_dec); | 131 | amd_sched_entity_fini(&adev->vcn.ring_dec.sched, &adev->vcn.entity_dec); |
| 123 | 132 | ||
| 133 | amd_sched_entity_fini(&adev->vcn.ring_enc[0].sched, &adev->vcn.entity_enc); | ||
| 134 | |||
| 124 | amdgpu_bo_free_kernel(&adev->vcn.vcpu_bo, | 135 | amdgpu_bo_free_kernel(&adev->vcn.vcpu_bo, |
| 125 | &adev->vcn.gpu_addr, | 136 | &adev->vcn.gpu_addr, |
| 126 | (void **)&adev->vcn.cpu_addr); | 137 | (void **)&adev->vcn.cpu_addr); |
| @@ -423,3 +434,195 @@ int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout) | |||
| 423 | error: | 434 | error: |
| 424 | return r; | 435 | return r; |
| 425 | } | 436 | } |
| 437 | |||
| 438 | static int amdgpu_vcn_enc_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, | ||
| 439 | struct dma_fence **fence) | ||
| 440 | { | ||
| 441 | const unsigned ib_size_dw = 1024; | ||
| 442 | struct amdgpu_job *job; | ||
| 443 | struct amdgpu_ib *ib; | ||
| 444 | struct dma_fence *f = NULL; | ||
| 445 | uint64_t dummy; | ||
| 446 | int i, r; | ||
| 447 | |||
| 448 | r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job); | ||
| 449 | if (r) | ||
| 450 | return r; | ||
| 451 | |||
| 452 | ib = &job->ibs[0]; | ||
| 453 | |||
| 454 | dummy = ib->gpu_addr + 1024; | ||
| 455 | |||
| 456 | /* stitch together an VCN enc create msg */ | ||
| 457 | ib->length_dw = 0; | ||
| 458 | ib->ptr[ib->length_dw++] = 0x0000000c; /* len */ | ||
| 459 | ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */ | ||
| 460 | ib->ptr[ib->length_dw++] = handle; | ||
| 461 | |||
| 462 | ib->ptr[ib->length_dw++] = 0x00000040; /* len */ | ||
| 463 | ib->ptr[ib->length_dw++] = 0x01000001; /* create cmd */ | ||
| 464 | ib->ptr[ib->length_dw++] = 0x00000000; | ||
| 465 | ib->ptr[ib->length_dw++] = 0x00000042; | ||
| 466 | ib->ptr[ib->length_dw++] = 0x0000000a; | ||
| 467 | ib->ptr[ib->length_dw++] = 0x00000001; | ||
| 468 | ib->ptr[ib->length_dw++] = 0x00000080; | ||
| 469 | ib->ptr[ib->length_dw++] = 0x00000060; | ||
| 470 | ib->ptr[ib->length_dw++] = 0x00000100; | ||
| 471 | ib->ptr[ib->length_dw++] = 0x00000100; | ||
| 472 | ib->ptr[ib->length_dw++] = 0x0000000c; | ||
| 473 | ib->ptr[ib->length_dw++] = 0x00000000; | ||
| 474 | ib->ptr[ib->length_dw++] = 0x00000000; | ||
| 475 | ib->ptr[ib->length_dw++] = 0x00000000; | ||
| 476 | ib->ptr[ib->length_dw++] = 0x00000000; | ||
| 477 | ib->ptr[ib->length_dw++] = 0x00000000; | ||
| 478 | |||
| 479 | ib->ptr[ib->length_dw++] = 0x00000014; /* len */ | ||
| 480 | ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */ | ||
| 481 | ib->ptr[ib->length_dw++] = upper_32_bits(dummy); | ||
| 482 | ib->ptr[ib->length_dw++] = dummy; | ||
| 483 | ib->ptr[ib->length_dw++] = 0x00000001; | ||
| 484 | |||
| 485 | for (i = ib->length_dw; i < ib_size_dw; ++i) | ||
| 486 | ib->ptr[i] = 0x0; | ||
| 487 | |||
| 488 | r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); | ||
| 489 | job->fence = dma_fence_get(f); | ||
| 490 | if (r) | ||
| 491 | goto err; | ||
| 492 | |||
| 493 | amdgpu_job_free(job); | ||
| 494 | if (fence) | ||
| 495 | *fence = dma_fence_get(f); | ||
| 496 | dma_fence_put(f); | ||
| 497 | return 0; | ||
| 498 | |||
| 499 | err: | ||
| 500 | amdgpu_job_free(job); | ||
| 501 | return r; | ||
| 502 | } | ||
| 503 | |||
| 504 | static int amdgpu_vcn_enc_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, | ||
| 505 | bool direct, struct dma_fence **fence) | ||
| 506 | { | ||
| 507 | const unsigned ib_size_dw = 1024; | ||
| 508 | struct amdgpu_job *job; | ||
| 509 | struct amdgpu_ib *ib; | ||
| 510 | struct dma_fence *f = NULL; | ||
| 511 | int i, r; | ||
| 512 | |||
| 513 | r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job); | ||
| 514 | if (r) | ||
| 515 | return r; | ||
| 516 | |||
| 517 | ib = &job->ibs[0]; | ||
| 518 | |||
| 519 | /* stitch together an VCN enc destroy msg */ | ||
| 520 | ib->length_dw = 0; | ||
| 521 | ib->ptr[ib->length_dw++] = 0x0000000c; /* len */ | ||
| 522 | ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */ | ||
| 523 | ib->ptr[ib->length_dw++] = handle; | ||
| 524 | |||
| 525 | ib->ptr[ib->length_dw++] = 0x00000020; /* len */ | ||
| 526 | ib->ptr[ib->length_dw++] = 0x00000002; /* task info */ | ||
| 527 | ib->ptr[ib->length_dw++] = 0xffffffff; /* next task info, set to 0xffffffff if no */ | ||
| 528 | ib->ptr[ib->length_dw++] = 0x00000001; /* destroy session */ | ||
| 529 | ib->ptr[ib->length_dw++] = 0x00000000; | ||
| 530 | ib->ptr[ib->length_dw++] = 0x00000000; | ||
| 531 | ib->ptr[ib->length_dw++] = 0xffffffff; /* feedback is not needed, set to 0xffffffff and firmware will not output feedback */ | ||
| 532 | ib->ptr[ib->length_dw++] = 0x00000000; | ||
| 533 | |||
| 534 | ib->ptr[ib->length_dw++] = 0x00000008; /* len */ | ||
| 535 | ib->ptr[ib->length_dw++] = 0x02000001; /* destroy cmd */ | ||
| 536 | |||
| 537 | for (i = ib->length_dw; i < ib_size_dw; ++i) | ||
| 538 | ib->ptr[i] = 0x0; | ||
| 539 | |||
| 540 | if (direct) { | ||
| 541 | r = amdgpu_ib_schedule(ring, 1, ib, NULL, &f); | ||
| 542 | job->fence = dma_fence_get(f); | ||
| 543 | if (r) | ||
| 544 | goto err; | ||
| 545 | |||
| 546 | amdgpu_job_free(job); | ||
| 547 | } else { | ||
| 548 | r = amdgpu_job_submit(job, ring, &ring->adev->vcn.entity_enc, | ||
| 549 | AMDGPU_FENCE_OWNER_UNDEFINED, &f); | ||
| 550 | if (r) | ||
| 551 | goto err; | ||
| 552 | } | ||
| 553 | |||
| 554 | if (fence) | ||
| 555 | *fence = dma_fence_get(f); | ||
| 556 | dma_fence_put(f); | ||
| 557 | return 0; | ||
| 558 | |||
| 559 | err: | ||
| 560 | amdgpu_job_free(job); | ||
| 561 | return r; | ||
| 562 | } | ||
| 563 | |||
| 564 | int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring) | ||
| 565 | { | ||
| 566 | struct amdgpu_device *adev = ring->adev; | ||
| 567 | uint32_t rptr = amdgpu_ring_get_rptr(ring); | ||
| 568 | unsigned i; | ||
| 569 | int r; | ||
| 570 | |||
| 571 | r = amdgpu_ring_alloc(ring, 16); | ||
| 572 | if (r) { | ||
| 573 | DRM_ERROR("amdgpu: vcn enc failed to lock ring %d (%d).\n", | ||
| 574 | ring->idx, r); | ||
| 575 | return r; | ||
| 576 | } | ||
| 577 | amdgpu_ring_write(ring, VCE_CMD_END); | ||
| 578 | amdgpu_ring_commit(ring); | ||
| 579 | |||
| 580 | for (i = 0; i < adev->usec_timeout; i++) { | ||
| 581 | if (amdgpu_ring_get_rptr(ring) != rptr) | ||
| 582 | break; | ||
| 583 | DRM_UDELAY(1); | ||
| 584 | } | ||
| 585 | |||
| 586 | if (i < adev->usec_timeout) { | ||
| 587 | DRM_INFO("ring test on %d succeeded in %d usecs\n", | ||
| 588 | ring->idx, i); | ||
| 589 | } else { | ||
| 590 | DRM_ERROR("amdgpu: ring %d test failed\n", | ||
| 591 | ring->idx); | ||
| 592 | r = -ETIMEDOUT; | ||
| 593 | } | ||
| 594 | |||
| 595 | return r; | ||
| 596 | } | ||
| 597 | |||
| 598 | int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout) | ||
| 599 | { | ||
| 600 | struct dma_fence *fence = NULL; | ||
| 601 | long r; | ||
| 602 | |||
| 603 | r = amdgpu_vcn_enc_get_create_msg(ring, 1, NULL); | ||
| 604 | if (r) { | ||
| 605 | DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r); | ||
| 606 | goto error; | ||
| 607 | } | ||
| 608 | |||
| 609 | r = amdgpu_vcn_enc_get_destroy_msg(ring, 1, true, &fence); | ||
| 610 | if (r) { | ||
| 611 | DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r); | ||
| 612 | goto error; | ||
| 613 | } | ||
| 614 | |||
| 615 | r = dma_fence_wait_timeout(fence, false, timeout); | ||
| 616 | if (r == 0) { | ||
| 617 | DRM_ERROR("amdgpu: IB test timed out.\n"); | ||
| 618 | r = -ETIMEDOUT; | ||
| 619 | } else if (r < 0) { | ||
| 620 | DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r); | ||
| 621 | } else { | ||
| 622 | DRM_INFO("ib test on ring %d succeeded\n", ring->idx); | ||
| 623 | r = 0; | ||
| 624 | } | ||
| 625 | error: | ||
| 626 | dma_fence_put(fence); | ||
| 627 | return r; | ||
| 628 | } | ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index a32182cd2575..ec4d7ca7ed61 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h | |||
| @@ -32,4 +32,7 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring); | |||
| 32 | void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring); | 32 | void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring); |
| 33 | int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout); | 33 | int amdgpu_vcn_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout); |
| 34 | 34 | ||
| 35 | int amdgpu_vcn_enc_ring_test_ring(struct amdgpu_ring *ring); | ||
| 36 | int amdgpu_vcn_enc_ring_test_ib(struct amdgpu_ring *ring, long timeout); | ||
| 37 | |||
| 35 | #endif | 38 | #endif |
