aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c170
1 files changed, 91 insertions, 79 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 875626a2eccb..05865ce35351 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -36,7 +36,7 @@
36#include "cikd.h" 36#include "cikd.h"
37 37
38/* 1 second timeout */ 38/* 1 second timeout */
39#define VCE_IDLE_TIMEOUT_MS 1000 39#define VCE_IDLE_TIMEOUT msecs_to_jiffies(1000)
40 40
41/* Firmware Names */ 41/* Firmware Names */
42#ifdef CONFIG_DRM_AMDGPU_CIK 42#ifdef CONFIG_DRM_AMDGPU_CIK
@@ -85,8 +85,6 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
85 unsigned ucode_version, version_major, version_minor, binary_id; 85 unsigned ucode_version, version_major, version_minor, binary_id;
86 int i, r; 86 int i, r;
87 87
88 INIT_DELAYED_WORK(&adev->vce.idle_work, amdgpu_vce_idle_work_handler);
89
90 switch (adev->asic_type) { 88 switch (adev->asic_type) {
91#ifdef CONFIG_DRM_AMDGPU_CIK 89#ifdef CONFIG_DRM_AMDGPU_CIK
92 case CHIP_BONAIRE: 90 case CHIP_BONAIRE:
@@ -197,6 +195,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
197 adev->vce.filp[i] = NULL; 195 adev->vce.filp[i] = NULL;
198 } 196 }
199 197
198 INIT_DELAYED_WORK(&adev->vce.idle_work, amdgpu_vce_idle_work_handler);
199 mutex_init(&adev->vce.idle_mutex);
200
200 return 0; 201 return 0;
201} 202}
202 203
@@ -220,6 +221,7 @@ int amdgpu_vce_sw_fini(struct amdgpu_device *adev)
220 amdgpu_ring_fini(&adev->vce.ring[1]); 221 amdgpu_ring_fini(&adev->vce.ring[1]);
221 222
222 release_firmware(adev->vce.fw); 223 release_firmware(adev->vce.fw);
224 mutex_destroy(&adev->vce.idle_mutex);
223 225
224 return 0; 226 return 0;
225} 227}
@@ -310,37 +312,44 @@ static void amdgpu_vce_idle_work_handler(struct work_struct *work)
310 amdgpu_asic_set_vce_clocks(adev, 0, 0); 312 amdgpu_asic_set_vce_clocks(adev, 0, 0);
311 } 313 }
312 } else { 314 } else {
313 schedule_delayed_work(&adev->vce.idle_work, 315 schedule_delayed_work(&adev->vce.idle_work, VCE_IDLE_TIMEOUT);
314 msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
315 } 316 }
316} 317}
317 318
318/** 319/**
319 * amdgpu_vce_note_usage - power up VCE 320 * amdgpu_vce_ring_begin_use - power up VCE
320 * 321 *
321 * @adev: amdgpu_device pointer 322 * @ring: amdgpu ring
322 * 323 *
323 * Make sure VCE is powerd up when we want to use it 324 * Make sure VCE is powerd up when we want to use it
324 */ 325 */
325static void amdgpu_vce_note_usage(struct amdgpu_device *adev) 326void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring)
326{ 327{
327 bool streams_changed = false; 328 struct amdgpu_device *adev = ring->adev;
328 bool set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work); 329 bool set_clocks;
329 set_clocks &= schedule_delayed_work(&adev->vce.idle_work,
330 msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
331
332 if (adev->pm.dpm_enabled) {
333 /* XXX figure out if the streams changed */
334 streams_changed = false;
335 }
336 330
337 if (set_clocks || streams_changed) { 331 mutex_lock(&adev->vce.idle_mutex);
332 set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work);
333 if (set_clocks) {
338 if (adev->pm.dpm_enabled) { 334 if (adev->pm.dpm_enabled) {
339 amdgpu_dpm_enable_vce(adev, true); 335 amdgpu_dpm_enable_vce(adev, true);
340 } else { 336 } else {
341 amdgpu_asic_set_vce_clocks(adev, 53300, 40000); 337 amdgpu_asic_set_vce_clocks(adev, 53300, 40000);
342 } 338 }
343 } 339 }
340 mutex_unlock(&adev->vce.idle_mutex);
341}
342
343/**
344 * amdgpu_vce_ring_end_use - power VCE down
345 *
346 * @ring: amdgpu ring
347 *
348 * Schedule work to power VCE down again
349 */
350void amdgpu_vce_ring_end_use(struct amdgpu_ring *ring)
351{
352 schedule_delayed_work(&ring->adev->vce.idle_work, VCE_IDLE_TIMEOUT);
344} 353}
345 354
346/** 355/**
@@ -357,11 +366,10 @@ void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
357 int i, r; 366 int i, r;
358 for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { 367 for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
359 uint32_t handle = atomic_read(&adev->vce.handles[i]); 368 uint32_t handle = atomic_read(&adev->vce.handles[i]);
369
360 if (!handle || adev->vce.filp[i] != filp) 370 if (!handle || adev->vce.filp[i] != filp)
361 continue; 371 continue;
362 372
363 amdgpu_vce_note_usage(adev);
364
365 r = amdgpu_vce_get_destroy_msg(ring, handle, false, NULL); 373 r = amdgpu_vce_get_destroy_msg(ring, handle, false, NULL);
366 if (r) 374 if (r)
367 DRM_ERROR("Error destroying VCE handle (%d)!\n", r); 375 DRM_ERROR("Error destroying VCE handle (%d)!\n", r);
@@ -437,7 +445,7 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
437 ib->ptr[i] = 0x0; 445 ib->ptr[i] = 0x0;
438 446
439 r = amdgpu_ib_schedule(ring, 1, ib, NULL, NULL, &f); 447 r = amdgpu_ib_schedule(ring, 1, ib, NULL, NULL, &f);
440 job->fence = f; 448 job->fence = fence_get(f);
441 if (r) 449 if (r)
442 goto err; 450 goto err;
443 451
@@ -469,7 +477,6 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
469 struct amdgpu_job *job; 477 struct amdgpu_job *job;
470 struct amdgpu_ib *ib; 478 struct amdgpu_ib *ib;
471 struct fence *f = NULL; 479 struct fence *f = NULL;
472 uint64_t dummy;
473 int i, r; 480 int i, r;
474 481
475 r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job); 482 r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job);
@@ -477,7 +484,6 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
477 return r; 484 return r;
478 485
479 ib = &job->ibs[0]; 486 ib = &job->ibs[0];
480 dummy = ib->gpu_addr + 1024;
481 487
482 /* stitch together an VCE destroy msg */ 488 /* stitch together an VCE destroy msg */
483 ib->length_dw = 0; 489 ib->length_dw = 0;
@@ -485,11 +491,14 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
485 ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */ 491 ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
486 ib->ptr[ib->length_dw++] = handle; 492 ib->ptr[ib->length_dw++] = handle;
487 493
488 ib->ptr[ib->length_dw++] = 0x00000014; /* len */ 494 ib->ptr[ib->length_dw++] = 0x00000020; /* len */
489 ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */ 495 ib->ptr[ib->length_dw++] = 0x00000002; /* task info */
490 ib->ptr[ib->length_dw++] = upper_32_bits(dummy); 496 ib->ptr[ib->length_dw++] = 0xffffffff; /* next task info, set to 0xffffffff if no */
491 ib->ptr[ib->length_dw++] = dummy; 497 ib->ptr[ib->length_dw++] = 0x00000001; /* destroy session */
492 ib->ptr[ib->length_dw++] = 0x00000001; 498 ib->ptr[ib->length_dw++] = 0x00000000;
499 ib->ptr[ib->length_dw++] = 0x00000000;
500 ib->ptr[ib->length_dw++] = 0xffffffff; /* feedback is not needed, set to 0xffffffff and firmware will not output feedback */
501 ib->ptr[ib->length_dw++] = 0x00000000;
493 502
494 ib->ptr[ib->length_dw++] = 0x00000008; /* len */ 503 ib->ptr[ib->length_dw++] = 0x00000008; /* len */
495 ib->ptr[ib->length_dw++] = 0x02000001; /* destroy cmd */ 504 ib->ptr[ib->length_dw++] = 0x02000001; /* destroy cmd */
@@ -499,7 +508,7 @@ int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
499 508
500 if (direct) { 509 if (direct) {
501 r = amdgpu_ib_schedule(ring, 1, ib, NULL, NULL, &f); 510 r = amdgpu_ib_schedule(ring, 1, ib, NULL, NULL, &f);
502 job->fence = f; 511 job->fence = fence_get(f);
503 if (r) 512 if (r)
504 goto err; 513 goto err;
505 514
@@ -580,12 +589,10 @@ static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx,
580 * we we don't have another free session index. 589 * we we don't have another free session index.
581 */ 590 */
582static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p, 591static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p,
583 uint32_t handle, bool *allocated) 592 uint32_t handle, uint32_t *allocated)
584{ 593{
585 unsigned i; 594 unsigned i;
586 595
587 *allocated = false;
588
589 /* validate the handle */ 596 /* validate the handle */
590 for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { 597 for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
591 if (atomic_read(&p->adev->vce.handles[i]) == handle) { 598 if (atomic_read(&p->adev->vce.handles[i]) == handle) {
@@ -602,7 +609,7 @@ static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p,
602 if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) { 609 if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) {
603 p->adev->vce.filp[i] = p->filp; 610 p->adev->vce.filp[i] = p->filp;
604 p->adev->vce.img_size[i] = 0; 611 p->adev->vce.img_size[i] = 0;
605 *allocated = true; 612 *allocated |= 1 << i;
606 return i; 613 return i;
607 } 614 }
608 } 615 }
@@ -622,15 +629,13 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
622 struct amdgpu_ib *ib = &p->job->ibs[ib_idx]; 629 struct amdgpu_ib *ib = &p->job->ibs[ib_idx];
623 unsigned fb_idx = 0, bs_idx = 0; 630 unsigned fb_idx = 0, bs_idx = 0;
624 int session_idx = -1; 631 int session_idx = -1;
625 bool destroyed = false; 632 uint32_t destroyed = 0;
626 bool created = false; 633 uint32_t created = 0;
627 bool allocated = false; 634 uint32_t allocated = 0;
628 uint32_t tmp, handle = 0; 635 uint32_t tmp, handle = 0;
629 uint32_t *size = &tmp; 636 uint32_t *size = &tmp;
630 int i, r = 0, idx = 0; 637 int i, r = 0, idx = 0;
631 638
632 amdgpu_vce_note_usage(p->adev);
633
634 while (idx < ib->length_dw) { 639 while (idx < ib->length_dw) {
635 uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx); 640 uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
636 uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1); 641 uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
@@ -641,30 +646,30 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
641 goto out; 646 goto out;
642 } 647 }
643 648
644 if (destroyed) {
645 DRM_ERROR("No other command allowed after destroy!\n");
646 r = -EINVAL;
647 goto out;
648 }
649
650 switch (cmd) { 649 switch (cmd) {
651 case 0x00000001: // session 650 case 0x00000001: /* session */
652 handle = amdgpu_get_ib_value(p, ib_idx, idx + 2); 651 handle = amdgpu_get_ib_value(p, ib_idx, idx + 2);
653 session_idx = amdgpu_vce_validate_handle(p, handle, 652 session_idx = amdgpu_vce_validate_handle(p, handle,
654 &allocated); 653 &allocated);
655 if (session_idx < 0) 654 if (session_idx < 0) {
656 return session_idx; 655 r = session_idx;
656 goto out;
657 }
657 size = &p->adev->vce.img_size[session_idx]; 658 size = &p->adev->vce.img_size[session_idx];
658 break; 659 break;
659 660
660 case 0x00000002: // task info 661 case 0x00000002: /* task info */
661 fb_idx = amdgpu_get_ib_value(p, ib_idx, idx + 6); 662 fb_idx = amdgpu_get_ib_value(p, ib_idx, idx + 6);
662 bs_idx = amdgpu_get_ib_value(p, ib_idx, idx + 7); 663 bs_idx = amdgpu_get_ib_value(p, ib_idx, idx + 7);
663 break; 664 break;
664 665
665 case 0x01000001: // create 666 case 0x01000001: /* create */
666 created = true; 667 created |= 1 << session_idx;
667 if (!allocated) { 668 if (destroyed & (1 << session_idx)) {
669 destroyed &= ~(1 << session_idx);
670 allocated |= 1 << session_idx;
671
672 } else if (!(allocated & (1 << session_idx))) {
668 DRM_ERROR("Handle already in use!\n"); 673 DRM_ERROR("Handle already in use!\n");
669 r = -EINVAL; 674 r = -EINVAL;
670 goto out; 675 goto out;
@@ -675,16 +680,16 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
675 8 * 3 / 2; 680 8 * 3 / 2;
676 break; 681 break;
677 682
678 case 0x04000001: // config extension 683 case 0x04000001: /* config extension */
679 case 0x04000002: // pic control 684 case 0x04000002: /* pic control */
680 case 0x04000005: // rate control 685 case 0x04000005: /* rate control */
681 case 0x04000007: // motion estimation 686 case 0x04000007: /* motion estimation */
682 case 0x04000008: // rdo 687 case 0x04000008: /* rdo */
683 case 0x04000009: // vui 688 case 0x04000009: /* vui */
684 case 0x05000002: // auxiliary buffer 689 case 0x05000002: /* auxiliary buffer */
685 break; 690 break;
686 691
687 case 0x03000001: // encode 692 case 0x03000001: /* encode */
688 r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9, 693 r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9,
689 *size, 0); 694 *size, 0);
690 if (r) 695 if (r)
@@ -696,18 +701,18 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
696 goto out; 701 goto out;
697 break; 702 break;
698 703
699 case 0x02000001: // destroy 704 case 0x02000001: /* destroy */
700 destroyed = true; 705 destroyed |= 1 << session_idx;
701 break; 706 break;
702 707
703 case 0x05000001: // context buffer 708 case 0x05000001: /* context buffer */
704 r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, 709 r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
705 *size * 2, 0); 710 *size * 2, 0);
706 if (r) 711 if (r)
707 goto out; 712 goto out;
708 break; 713 break;
709 714
710 case 0x05000004: // video bitstream buffer 715 case 0x05000004: /* video bitstream buffer */
711 tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4); 716 tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4);
712 r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, 717 r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
713 tmp, bs_idx); 718 tmp, bs_idx);
@@ -715,7 +720,7 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
715 goto out; 720 goto out;
716 break; 721 break;
717 722
718 case 0x05000005: // feedback buffer 723 case 0x05000005: /* feedback buffer */
719 r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, 724 r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
720 4096, fb_idx); 725 4096, fb_idx);
721 if (r) 726 if (r)
@@ -737,21 +742,24 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
737 idx += len / 4; 742 idx += len / 4;
738 } 743 }
739 744
740 if (allocated && !created) { 745 if (allocated & ~created) {
741 DRM_ERROR("New session without create command!\n"); 746 DRM_ERROR("New session without create command!\n");
742 r = -ENOENT; 747 r = -ENOENT;
743 } 748 }
744 749
745out: 750out:
746 if ((!r && destroyed) || (r && allocated)) { 751 if (!r) {
747 /* 752 /* No error, free all destroyed handle slots */
748 * IB contains a destroy msg or we have allocated an 753 tmp = destroyed;
749 * handle and got an error, anyway free the handle 754 } else {
750 */ 755 /* Error during parsing, free all allocated handle slots */
751 for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) 756 tmp = allocated;
752 atomic_cmpxchg(&p->adev->vce.handles[i], handle, 0);
753 } 757 }
754 758
759 for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
760 if (tmp & (1 << i))
761 atomic_set(&p->adev->vce.handles[i], 0);
762
755 return r; 763 return r;
756} 764}
757 765
@@ -837,10 +845,10 @@ int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
837 * @ring: the engine to test on 845 * @ring: the engine to test on
838 * 846 *
839 */ 847 */
840int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring) 848int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout)
841{ 849{
842 struct fence *fence = NULL; 850 struct fence *fence = NULL;
843 int r; 851 long r;
844 852
845 /* skip vce ring1 ib test for now, since it's not reliable */ 853 /* skip vce ring1 ib test for now, since it's not reliable */
846 if (ring == &ring->adev->vce.ring[1]) 854 if (ring == &ring->adev->vce.ring[1])
@@ -848,21 +856,25 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring)
848 856
849 r = amdgpu_vce_get_create_msg(ring, 1, NULL); 857 r = amdgpu_vce_get_create_msg(ring, 1, NULL);
850 if (r) { 858 if (r) {
851 DRM_ERROR("amdgpu: failed to get create msg (%d).\n", r); 859 DRM_ERROR("amdgpu: failed to get create msg (%ld).\n", r);
852 goto error; 860 goto error;
853 } 861 }
854 862
855 r = amdgpu_vce_get_destroy_msg(ring, 1, true, &fence); 863 r = amdgpu_vce_get_destroy_msg(ring, 1, true, &fence);
856 if (r) { 864 if (r) {
857 DRM_ERROR("amdgpu: failed to get destroy ib (%d).\n", r); 865 DRM_ERROR("amdgpu: failed to get destroy ib (%ld).\n", r);
858 goto error; 866 goto error;
859 } 867 }
860 868
861 r = fence_wait(fence, false); 869 r = fence_wait_timeout(fence, false, timeout);
862 if (r) { 870 if (r == 0) {
863 DRM_ERROR("amdgpu: fence wait failed (%d).\n", r); 871 DRM_ERROR("amdgpu: IB test timed out.\n");
872 r = -ETIMEDOUT;
873 } else if (r < 0) {
874 DRM_ERROR("amdgpu: fence wait failed (%ld).\n", r);
864 } else { 875 } else {
865 DRM_INFO("ib test on ring %d succeeded\n", ring->idx); 876 DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
877 r = 0;
866 } 878 }
867error: 879error:
868 fence_put(fence); 880 fence_put(fence);