LCOV - code coverage report
Current view: top level - dev/pci/drm/radeon - radeon_vce.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 368 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13