Subversion Repositories Kolibri OS

Rev

Rev 6104 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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