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

          Line data    Source code
       1             : /*
       2             :  * Copyright 2011 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             :  */
      26             : /*
      27             :  * Authors:
      28             :  *    Christian König <deathsimple@vodafone.de>
      29             :  */
      30             : 
      31             : #include <dev/pci/drm/drmP.h>
      32             : #include <dev/pci/drm/drm.h>
      33             : 
      34             : #include "radeon.h"
      35             : #include "r600d.h"
      36             : 
      37             : /* 1 second timeout */
      38             : #define UVD_IDLE_TIMEOUT_MS     1000
      39             : 
      40             : /* Firmware Names */
      41             : #define FIRMWARE_R600           "radeon/R600_uvd.bin"
      42             : #define FIRMWARE_RS780          "radeon/RS780_uvd.bin"
      43             : #define FIRMWARE_RV770          "radeon/RV770_uvd.bin"
      44             : #define FIRMWARE_RV710          "radeon/RV710_uvd.bin"
      45             : #define FIRMWARE_CYPRESS        "radeon/CYPRESS_uvd.bin"
      46             : #define FIRMWARE_SUMO           "radeon/SUMO_uvd.bin"
      47             : #define FIRMWARE_TAHITI         "radeon/TAHITI_uvd.bin"
      48             : #define FIRMWARE_BONAIRE        "radeon/BONAIRE_uvd.bin"
      49             : 
      50             : MODULE_FIRMWARE(FIRMWARE_R600);
      51             : MODULE_FIRMWARE(FIRMWARE_RS780);
      52             : MODULE_FIRMWARE(FIRMWARE_RV770);
      53             : MODULE_FIRMWARE(FIRMWARE_RV710);
      54             : MODULE_FIRMWARE(FIRMWARE_CYPRESS);
      55             : MODULE_FIRMWARE(FIRMWARE_SUMO);
      56             : MODULE_FIRMWARE(FIRMWARE_TAHITI);
      57             : MODULE_FIRMWARE(FIRMWARE_BONAIRE);
      58             : 
      59             : static void radeon_uvd_idle_work_handler(struct work_struct *work);
      60             : 
      61           0 : int radeon_uvd_init(struct radeon_device *rdev)
      62             : {
      63             :         unsigned long bo_size;
      64             :         const char *fw_name;
      65             :         int i, r;
      66             : 
      67           0 :         INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler);
      68             : 
      69           0 :         switch (rdev->family) {
      70             :         case CHIP_RV610:
      71             :         case CHIP_RV630:
      72             :         case CHIP_RV670:
      73             :         case CHIP_RV620:
      74             :         case CHIP_RV635:
      75             :                 fw_name = FIRMWARE_R600;
      76           0 :                 break;
      77             : 
      78             :         case CHIP_RS780:
      79             :         case CHIP_RS880:
      80             :                 fw_name = FIRMWARE_RS780;
      81           0 :                 break;
      82             : 
      83             :         case CHIP_RV770:
      84             :                 fw_name = FIRMWARE_RV770;
      85           0 :                 break;
      86             : 
      87             :         case CHIP_RV710:
      88             :         case CHIP_RV730:
      89             :         case CHIP_RV740:
      90             :                 fw_name = FIRMWARE_RV710;
      91           0 :                 break;
      92             : 
      93             :         case CHIP_CYPRESS:
      94             :         case CHIP_HEMLOCK:
      95             :         case CHIP_JUNIPER:
      96             :         case CHIP_REDWOOD:
      97             :         case CHIP_CEDAR:
      98             :                 fw_name = FIRMWARE_CYPRESS;
      99           0 :                 break;
     100             : 
     101             :         case CHIP_SUMO:
     102             :         case CHIP_SUMO2:
     103             :         case CHIP_PALM:
     104             :         case CHIP_CAYMAN:
     105             :         case CHIP_BARTS:
     106             :         case CHIP_TURKS:
     107             :         case CHIP_CAICOS:
     108             :                 fw_name = FIRMWARE_SUMO;
     109           0 :                 break;
     110             : 
     111             :         case CHIP_TAHITI:
     112             :         case CHIP_VERDE:
     113             :         case CHIP_PITCAIRN:
     114             :         case CHIP_ARUBA:
     115             :         case CHIP_OLAND:
     116             :                 fw_name = FIRMWARE_TAHITI;
     117           0 :                 break;
     118             : 
     119             :         case CHIP_BONAIRE:
     120             :         case CHIP_KABINI:
     121             :         case CHIP_KAVERI:
     122             :         case CHIP_HAWAII:
     123             :         case CHIP_MULLINS:
     124             :                 fw_name = FIRMWARE_BONAIRE;
     125           0 :                 break;
     126             : 
     127             :         default:
     128           0 :                 return -EINVAL;
     129             :         }
     130             : 
     131           0 :         r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev);
     132           0 :         if (r) {
     133           0 :                 dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n",
     134             :                         fw_name);
     135           0 :                 return r;
     136             :         }
     137             : 
     138           0 :         bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) +
     139           0 :                   RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE +
     140             :                   RADEON_GPU_PAGE_SIZE;
     141           0 :         r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
     142             :                              RADEON_GEM_DOMAIN_VRAM, 0, NULL,
     143           0 :                              NULL, &rdev->uvd.vcpu_bo);
     144           0 :         if (r) {
     145           0 :                 dev_err(rdev->dev, "(%d) failed to allocate UVD bo\n", r);
     146           0 :                 return r;
     147             :         }
     148             : 
     149           0 :         r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
     150           0 :         if (r) {
     151           0 :                 radeon_bo_unref(&rdev->uvd.vcpu_bo);
     152           0 :                 dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r);
     153           0 :                 return r;
     154             :         }
     155             : 
     156           0 :         r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM,
     157           0 :                           &rdev->uvd.gpu_addr);
     158           0 :         if (r) {
     159           0 :                 radeon_bo_unreserve(rdev->uvd.vcpu_bo);
     160           0 :                 radeon_bo_unref(&rdev->uvd.vcpu_bo);
     161           0 :                 dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r);
     162           0 :                 return r;
     163             :         }
     164             : 
     165           0 :         r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr);
     166           0 :         if (r) {
     167           0 :                 dev_err(rdev->dev, "(%d) UVD map failed\n", r);
     168           0 :                 return r;
     169             :         }
     170             : 
     171           0 :         radeon_bo_unreserve(rdev->uvd.vcpu_bo);
     172             : 
     173           0 :         for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
     174           0 :                 atomic_set(&rdev->uvd.handles[i], 0);
     175           0 :                 rdev->uvd.filp[i] = NULL;
     176           0 :                 rdev->uvd.img_size[i] = 0;
     177             :         }
     178             : 
     179           0 :         return 0;
     180           0 : }
     181             : 
     182           0 : void radeon_uvd_fini(struct radeon_device *rdev)
     183             : {
     184             :         int r;
     185             : 
     186           0 :         if (rdev->uvd.vcpu_bo == NULL)
     187           0 :                 return;
     188             : 
     189           0 :         r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
     190           0 :         if (!r) {
     191           0 :                 radeon_bo_kunmap(rdev->uvd.vcpu_bo);
     192           0 :                 radeon_bo_unpin(rdev->uvd.vcpu_bo);
     193           0 :                 radeon_bo_unreserve(rdev->uvd.vcpu_bo);
     194           0 :         }
     195             : 
     196           0 :         radeon_bo_unref(&rdev->uvd.vcpu_bo);
     197             : 
     198           0 :         radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX]);
     199             : 
     200           0 :         release_firmware(rdev->uvd_fw);
     201           0 : }
     202             : 
     203           0 : int radeon_uvd_suspend(struct radeon_device *rdev)
     204             : {
     205             :         int i, r;
     206             : 
     207           0 :         if (rdev->uvd.vcpu_bo == NULL)
     208           0 :                 return 0;
     209             : 
     210           0 :         for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
     211           0 :                 uint32_t handle = atomic_read(&rdev->uvd.handles[i]);
     212           0 :                 if (handle != 0) {
     213           0 :                         struct radeon_fence *fence;
     214             : 
     215           0 :                         radeon_uvd_note_usage(rdev);
     216             : 
     217           0 :                         r = radeon_uvd_get_destroy_msg(rdev,
     218             :                                 R600_RING_TYPE_UVD_INDEX, handle, &fence);
     219           0 :                         if (r) {
     220           0 :                                 DRM_ERROR("Error destroying UVD (%d)!\n", r);
     221           0 :                                 continue;
     222             :                         }
     223             : 
     224           0 :                         radeon_fence_wait(fence, false);
     225           0 :                         radeon_fence_unref(&fence);
     226             : 
     227           0 :                         rdev->uvd.filp[i] = NULL;
     228           0 :                         atomic_set(&rdev->uvd.handles[i], 0);
     229           0 :                 }
     230           0 :         }
     231             : 
     232           0 :         return 0;
     233           0 : }
     234             : 
     235           0 : int radeon_uvd_resume(struct radeon_device *rdev)
     236             : {
     237             :         unsigned size;
     238             :         void *ptr;
     239             : 
     240           0 :         if (rdev->uvd.vcpu_bo == NULL)
     241           0 :                 return -EINVAL;
     242             : 
     243           0 :         memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size);
     244             : 
     245           0 :         size = radeon_bo_size(rdev->uvd.vcpu_bo);
     246           0 :         size -= rdev->uvd_fw->size;
     247             : 
     248           0 :         ptr = rdev->uvd.cpu_addr;
     249           0 :         ptr += rdev->uvd_fw->size;
     250             : 
     251           0 :         memset(ptr, 0, size);
     252             : 
     253           0 :         return 0;
     254           0 : }
     255             : 
     256           0 : void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo,
     257             :                                        uint32_t allowed_domains)
     258             : {
     259             :         int i;
     260             : 
     261           0 :         for (i = 0; i < rbo->placement.num_placement; ++i) {
     262           0 :                 rbo->placements[i].fpfn = 0 >> PAGE_SHIFT;
     263           0 :                 rbo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
     264             :         }
     265             : 
     266             :         /* If it must be in VRAM it must be in the first segment as well */
     267           0 :         if (allowed_domains == RADEON_GEM_DOMAIN_VRAM)
     268           0 :                 return;
     269             : 
     270             :         /* abort if we already have more than one placement */
     271           0 :         if (rbo->placement.num_placement > 1)
     272           0 :                 return;
     273             : 
     274             :         /* add another 256MB segment */
     275           0 :         rbo->placements[1] = rbo->placements[0];
     276           0 :         rbo->placements[1].fpfn += (256 * 1024 * 1024) >> PAGE_SHIFT;
     277           0 :         rbo->placements[1].lpfn += (256 * 1024 * 1024) >> PAGE_SHIFT;
     278           0 :         rbo->placement.num_placement++;
     279           0 :         rbo->placement.num_busy_placement++;
     280           0 : }
     281             : 
     282           0 : void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp)
     283             : {
     284             :         int i, r;
     285           0 :         for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
     286           0 :                 uint32_t handle = atomic_read(&rdev->uvd.handles[i]);
     287           0 :                 if (handle != 0 && rdev->uvd.filp[i] == filp) {
     288           0 :                         struct radeon_fence *fence;
     289             : 
     290           0 :                         radeon_uvd_note_usage(rdev);
     291             : 
     292           0 :                         r = radeon_uvd_get_destroy_msg(rdev,
     293             :                                 R600_RING_TYPE_UVD_INDEX, handle, &fence);
     294           0 :                         if (r) {
     295           0 :                                 DRM_ERROR("Error destroying UVD (%d)!\n", r);
     296           0 :                                 continue;
     297             :                         }
     298             : 
     299           0 :                         radeon_fence_wait(fence, false);
     300           0 :                         radeon_fence_unref(&fence);
     301             : 
     302           0 :                         rdev->uvd.filp[i] = NULL;
     303           0 :                         atomic_set(&rdev->uvd.handles[i], 0);
     304           0 :                 }
     305           0 :         }
     306           0 : }
     307             : 
     308           0 : static int radeon_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
     309             : {
     310           0 :         unsigned stream_type = msg[4];
     311           0 :         unsigned width = msg[6];
     312           0 :         unsigned height = msg[7];
     313           0 :         unsigned dpb_size = msg[9];
     314           0 :         unsigned pitch = msg[28];
     315             : 
     316           0 :         unsigned width_in_mb = width / 16;
     317           0 :         unsigned height_in_mb = roundup2(height / 16, 2);
     318             : 
     319             :         unsigned image_size, tmp, min_dpb_size;
     320             : 
     321           0 :         image_size = width * height;
     322           0 :         image_size += image_size / 2;
     323           0 :         image_size = roundup2(image_size, 1024);
     324             : 
     325           0 :         switch (stream_type) {
     326             :         case 0: /* H264 */
     327             : 
     328             :                 /* reference picture buffer */
     329           0 :                 min_dpb_size = image_size * 17;
     330             : 
     331             :                 /* macroblock context buffer */
     332           0 :                 min_dpb_size += width_in_mb * height_in_mb * 17 * 192;
     333             : 
     334             :                 /* IT surface buffer */
     335           0 :                 min_dpb_size += width_in_mb * height_in_mb * 32;
     336           0 :                 break;
     337             : 
     338             :         case 1: /* VC1 */
     339             : 
     340             :                 /* reference picture buffer */
     341           0 :                 min_dpb_size = image_size * 3;
     342             : 
     343             :                 /* CONTEXT_BUFFER */
     344           0 :                 min_dpb_size += width_in_mb * height_in_mb * 128;
     345             : 
     346             :                 /* IT surface buffer */
     347           0 :                 min_dpb_size += width_in_mb * 64;
     348             : 
     349             :                 /* DB surface buffer */
     350           0 :                 min_dpb_size += width_in_mb * 128;
     351             : 
     352             :                 /* BP */
     353           0 :                 tmp = max(width_in_mb, height_in_mb);
     354           0 :                 min_dpb_size += roundup2(tmp * 7 * 16, 64);
     355           0 :                 break;
     356             : 
     357             :         case 3: /* MPEG2 */
     358             : 
     359             :                 /* reference picture buffer */
     360           0 :                 min_dpb_size = image_size * 3;
     361           0 :                 break;
     362             : 
     363             :         case 4: /* MPEG4 */
     364             : 
     365             :                 /* reference picture buffer */
     366           0 :                 min_dpb_size = image_size * 3;
     367             : 
     368             :                 /* CM */
     369           0 :                 min_dpb_size += width_in_mb * height_in_mb * 64;
     370             : 
     371             :                 /* IT surface buffer */
     372           0 :                 min_dpb_size += roundup2(width_in_mb * height_in_mb * 32, 64);
     373           0 :                 break;
     374             : 
     375             :         default:
     376           0 :                 DRM_ERROR("UVD codec not handled %d!\n", stream_type);
     377           0 :                 return -EINVAL;
     378             :         }
     379             : 
     380           0 :         if (width > pitch) {
     381           0 :                 DRM_ERROR("Invalid UVD decoding target pitch!\n");
     382           0 :                 return -EINVAL;
     383             :         }
     384             : 
     385           0 :         if (dpb_size < min_dpb_size) {
     386           0 :                 DRM_ERROR("Invalid dpb_size in UVD message (%d / %d)!\n",
     387             :                           dpb_size, min_dpb_size);
     388           0 :                 return -EINVAL;
     389             :         }
     390             : 
     391           0 :         buf_sizes[0x1] = dpb_size;
     392           0 :         buf_sizes[0x2] = image_size;
     393           0 :         return 0;
     394           0 : }
     395             : 
     396           0 : static int radeon_uvd_validate_codec(struct radeon_cs_parser *p,
     397             :                                      unsigned stream_type)
     398             : {
     399           0 :         switch (stream_type) {
     400             :         case 0: /* H264 */
     401             :         case 1: /* VC1 */
     402             :                 /* always supported */
     403           0 :                 return 0;
     404             : 
     405             :         case 3: /* MPEG2 */
     406             :         case 4: /* MPEG4 */
     407             :                 /* only since UVD 3 */
     408           0 :                 if (p->rdev->family >= CHIP_PALM)
     409           0 :                         return 0;
     410             : 
     411             :                 /* fall through */
     412             :         default:
     413           0 :                 DRM_ERROR("UVD codec not supported by hardware %d!\n",
     414             :                           stream_type);
     415           0 :                 return -EINVAL;
     416             :         }
     417           0 : }
     418             : 
     419           0 : static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
     420             :                              unsigned offset, unsigned buf_sizes[])
     421             : {
     422             :         int32_t *msg, msg_type, handle;
     423             :         unsigned img_size = 0;
     424             :         struct fence *f;
     425           0 :         void *ptr;
     426             : 
     427             :         int i, r;
     428             : 
     429           0 :         if (offset & 0x3F) {
     430           0 :                 DRM_ERROR("UVD messages must be 64 byte aligned!\n");
     431           0 :                 return -EINVAL;
     432             :         }
     433             : 
     434           0 :         f = reservation_object_get_excl(bo->tbo.resv);
     435           0 :         if (f) {
     436           0 :                 r = radeon_fence_wait((struct radeon_fence *)f, false);
     437           0 :                 if (r) {
     438           0 :                         DRM_ERROR("Failed waiting for UVD message (%d)!\n", r);
     439           0 :                         return r;
     440             :                 }
     441             :         }
     442             : 
     443           0 :         r = radeon_bo_kmap(bo, &ptr);
     444           0 :         if (r) {
     445           0 :                 DRM_ERROR("Failed mapping the UVD message (%d)!\n", r);
     446           0 :                 return r;
     447             :         }
     448             : 
     449           0 :         msg = ptr + offset;
     450             : 
     451           0 :         msg_type = msg[1];
     452           0 :         handle = msg[2];
     453             : 
     454           0 :         if (handle == 0) {
     455           0 :                 DRM_ERROR("Invalid UVD handle!\n");
     456           0 :                 return -EINVAL;
     457             :         }
     458             : 
     459           0 :         switch (msg_type) {
     460             :         case 0:
     461             :                 /* it's a create msg, calc image size (width * height) */
     462           0 :                 img_size = msg[7] * msg[8];
     463             : 
     464           0 :                 r = radeon_uvd_validate_codec(p, msg[4]);
     465           0 :                 radeon_bo_kunmap(bo);
     466           0 :                 if (r)
     467           0 :                         return r;
     468             : 
     469             :                 /* try to alloc a new handle */
     470           0 :                 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
     471           0 :                         if (atomic_read(&p->rdev->uvd.handles[i]) == handle) {
     472           0 :                                 DRM_ERROR("Handle 0x%x already in use!\n", handle);
     473           0 :                                 return -EINVAL;
     474             :                         }
     475             : 
     476           0 :                         if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) {
     477           0 :                                 p->rdev->uvd.filp[i] = p->filp;
     478           0 :                                 p->rdev->uvd.img_size[i] = img_size;
     479           0 :                                 return 0;
     480             :                         }
     481             :                 }
     482             : 
     483           0 :                 DRM_ERROR("No more free UVD handles!\n");
     484           0 :                 return -EINVAL;
     485             : 
     486             :         case 1:
     487             :                 /* it's a decode msg, validate codec and calc buffer sizes */
     488           0 :                 r = radeon_uvd_validate_codec(p, msg[4]);
     489           0 :                 if (!r)
     490           0 :                         r = radeon_uvd_cs_msg_decode(msg, buf_sizes);
     491           0 :                 radeon_bo_kunmap(bo);
     492           0 :                 if (r)
     493           0 :                         return r;
     494             : 
     495             :                 /* validate the handle */
     496           0 :                 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
     497           0 :                         if (atomic_read(&p->rdev->uvd.handles[i]) == handle) {
     498           0 :                                 if (p->rdev->uvd.filp[i] != p->filp) {
     499           0 :                                         DRM_ERROR("UVD handle collision detected!\n");
     500           0 :                                         return -EINVAL;
     501             :                                 }
     502           0 :                                 return 0;
     503             :                         }
     504             :                 }
     505             : 
     506           0 :                 DRM_ERROR("Invalid UVD handle 0x%x!\n", handle);
     507           0 :                 return -ENOENT;
     508             : 
     509             :         case 2:
     510             :                 /* it's a destroy msg, free the handle */
     511           0 :                 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i)
     512           0 :                         atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0);
     513           0 :                 radeon_bo_kunmap(bo);
     514           0 :                 return 0;
     515             : 
     516             :         default:
     517             : 
     518           0 :                 DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
     519           0 :                 return -EINVAL;
     520             :         }
     521             : 
     522             :         BUG();
     523             :         return -EINVAL;
     524           0 : }
     525             : 
     526           0 : static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
     527             :                                int data0, int data1,
     528             :                                unsigned buf_sizes[], bool *has_msg_cmd)
     529             : {
     530             :         struct radeon_cs_chunk *relocs_chunk;
     531             :         struct radeon_bo_list *reloc;
     532             :         unsigned idx, cmd, offset;
     533             :         uint64_t start, end;
     534             :         int r;
     535             : 
     536           0 :         relocs_chunk = p->chunk_relocs;
     537           0 :         offset = radeon_get_ib_value(p, data0);
     538           0 :         idx = radeon_get_ib_value(p, data1);
     539           0 :         if (idx >= relocs_chunk->length_dw) {
     540           0 :                 DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
     541             :                           idx, relocs_chunk->length_dw);
     542           0 :                 return -EINVAL;
     543             :         }
     544             : 
     545           0 :         reloc = &p->relocs[(idx / 4)];
     546           0 :         start = reloc->gpu_offset;
     547           0 :         end = start + radeon_bo_size(reloc->robj);
     548           0 :         start += offset;
     549             : 
     550           0 :         p->ib.ptr[data0] = start & 0xFFFFFFFF;
     551           0 :         p->ib.ptr[data1] = start >> 32;
     552             : 
     553           0 :         cmd = radeon_get_ib_value(p, p->idx) >> 1;
     554             : 
     555           0 :         if (cmd < 0x4) {
     556           0 :                 if (end <= start) {
     557           0 :                         DRM_ERROR("invalid reloc offset %X!\n", offset);
     558           0 :                         return -EINVAL;
     559             :                 }
     560           0 :                 if ((end - start) < buf_sizes[cmd]) {
     561           0 :                         DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
     562             :                                   (unsigned)(end - start), buf_sizes[cmd]);
     563           0 :                         return -EINVAL;
     564             :                 }
     565             : 
     566           0 :         } else if (cmd != 0x100) {
     567           0 :                 DRM_ERROR("invalid UVD command %X!\n", cmd);
     568           0 :                 return -EINVAL;
     569             :         }
     570             : 
     571           0 :         if ((start >> 28) != ((end - 1) >> 28)) {
     572           0 :                 DRM_ERROR("reloc %llX-%llX crossing 256MB boundary!\n",
     573             :                           start, end);
     574           0 :                 return -EINVAL;
     575             :         }
     576             : 
     577             :         /* TODO: is this still necessary on NI+ ? */
     578           0 :         if ((cmd == 0 || cmd == 0x3) &&
     579           0 :             (start >> 28) != (p->rdev->uvd.gpu_addr >> 28)) {
     580           0 :                 DRM_ERROR("msg/fb buffer %llX-%llX out of 256MB segment!\n",
     581             :                           start, end);
     582           0 :                 return -EINVAL;
     583             :         }
     584             : 
     585           0 :         if (cmd == 0) {
     586           0 :                 if (*has_msg_cmd) {
     587           0 :                         DRM_ERROR("More than one message in a UVD-IB!\n");
     588           0 :                         return -EINVAL;
     589             :                 }
     590           0 :                 *has_msg_cmd = true;
     591           0 :                 r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes);
     592           0 :                 if (r)
     593           0 :                         return r;
     594           0 :         } else if (!*has_msg_cmd) {
     595           0 :                 DRM_ERROR("Message needed before other commands are send!\n");
     596           0 :                 return -EINVAL;
     597             :         }
     598             : 
     599           0 :         return 0;
     600           0 : }
     601             : 
     602           0 : static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
     603             :                              struct radeon_cs_packet *pkt,
     604             :                              int *data0, int *data1,
     605             :                              unsigned buf_sizes[],
     606             :                              bool *has_msg_cmd)
     607             : {
     608             :         int i, r;
     609             : 
     610           0 :         p->idx++;
     611           0 :         for (i = 0; i <= pkt->count; ++i) {
     612           0 :                 switch (pkt->reg + i*4) {
     613             :                 case UVD_GPCOM_VCPU_DATA0:
     614           0 :                         *data0 = p->idx;
     615           0 :                         break;
     616             :                 case UVD_GPCOM_VCPU_DATA1:
     617           0 :                         *data1 = p->idx;
     618           0 :                         break;
     619             :                 case UVD_GPCOM_VCPU_CMD:
     620           0 :                         r = radeon_uvd_cs_reloc(p, *data0, *data1,
     621             :                                                 buf_sizes, has_msg_cmd);
     622           0 :                         if (r)
     623           0 :                                 return r;
     624             :                         break;
     625             :                 case UVD_ENGINE_CNTL:
     626             :                         break;
     627             :                 default:
     628           0 :                         DRM_ERROR("Invalid reg 0x%X!\n",
     629             :                                   pkt->reg + i*4);
     630           0 :                         return -EINVAL;
     631             :                 }
     632           0 :                 p->idx++;
     633             :         }
     634           0 :         return 0;
     635           0 : }
     636             : 
     637           0 : int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
     638             : {
     639           0 :         struct radeon_cs_packet pkt;
     640           0 :         int r, data0 = 0, data1 = 0;
     641             : 
     642             :         /* does the IB has a msg command */
     643           0 :         bool has_msg_cmd = false;
     644             : 
     645             :         /* minimum buffer sizes */
     646           0 :         unsigned buf_sizes[] = {
     647             :                 [0x00000000]    =       2048,
     648             :                 [0x00000001]    =       32 * 1024 * 1024,
     649             :                 [0x00000002]    =       2048 * 1152 * 3,
     650             :                 [0x00000003]    =       2048,
     651             :         };
     652             : 
     653           0 :         if (p->chunk_ib->length_dw % 16) {
     654           0 :                 DRM_ERROR("UVD IB length (%d) not 16 dwords aligned!\n",
     655             :                           p->chunk_ib->length_dw);
     656           0 :                 return -EINVAL;
     657             :         }
     658             : 
     659           0 :         if (p->chunk_relocs == NULL) {
     660           0 :                 DRM_ERROR("No relocation chunk !\n");
     661           0 :                 return -EINVAL;
     662             :         }
     663             : 
     664             : 
     665           0 :         do {
     666           0 :                 r = radeon_cs_packet_parse(p, &pkt, p->idx);
     667           0 :                 if (r)
     668           0 :                         return r;
     669           0 :                 switch (pkt.type) {
     670             :                 case RADEON_PACKET_TYPE0:
     671           0 :                         r = radeon_uvd_cs_reg(p, &pkt, &data0, &data1,
     672           0 :                                               buf_sizes, &has_msg_cmd);
     673           0 :                         if (r)
     674           0 :                                 return r;
     675             :                         break;
     676             :                 case RADEON_PACKET_TYPE2:
     677           0 :                         p->idx += pkt.count + 2;
     678           0 :                         break;
     679             :                 default:
     680           0 :                         DRM_ERROR("Unknown packet type %d !\n", pkt.type);
     681           0 :                         return -EINVAL;
     682             :                 }
     683           0 :         } while (p->idx < p->chunk_ib->length_dw);
     684             : 
     685           0 :         if (!has_msg_cmd) {
     686           0 :                 DRM_ERROR("UVD-IBs need a msg command!\n");
     687           0 :                 return -EINVAL;
     688             :         }
     689             : 
     690           0 :         return 0;
     691           0 : }
     692             : 
     693           0 : static int radeon_uvd_send_msg(struct radeon_device *rdev,
     694             :                                int ring, uint64_t addr,
     695             :                                struct radeon_fence **fence)
     696             : {
     697           0 :         struct radeon_ib ib;
     698             :         int i, r;
     699             : 
     700           0 :         r = radeon_ib_get(rdev, ring, &ib, NULL, 64);
     701           0 :         if (r)
     702           0 :                 return r;
     703             : 
     704           0 :         ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0);
     705           0 :         ib.ptr[1] = addr;
     706           0 :         ib.ptr[2] = PACKET0(UVD_GPCOM_VCPU_DATA1, 0);
     707           0 :         ib.ptr[3] = addr >> 32;
     708           0 :         ib.ptr[4] = PACKET0(UVD_GPCOM_VCPU_CMD, 0);
     709           0 :         ib.ptr[5] = 0;
     710           0 :         for (i = 6; i < 16; ++i)
     711           0 :                 ib.ptr[i] = PACKET2(0);
     712           0 :         ib.length_dw = 16;
     713             : 
     714           0 :         r = radeon_ib_schedule(rdev, &ib, NULL, false);
     715             : 
     716           0 :         if (fence)
     717           0 :                 *fence = radeon_fence_ref(ib.fence);
     718             : 
     719           0 :         radeon_ib_free(rdev, &ib);
     720           0 :         return r;
     721           0 : }
     722             : 
     723             : /* multiple fence commands without any stream commands in between can
     724             :    crash the vcpu so just try to emmit a dummy create/destroy msg to
     725             :    avoid this */
     726           0 : int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
     727             :                               uint32_t handle, struct radeon_fence **fence)
     728             : {
     729             :         /* we use the last page of the vcpu bo for the UVD message */
     730           0 :         uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) -
     731             :                 RADEON_GPU_PAGE_SIZE;
     732             : 
     733           0 :         uint32_t *msg = rdev->uvd.cpu_addr + offs;
     734           0 :         uint64_t addr = rdev->uvd.gpu_addr + offs;
     735             : 
     736             :         int r, i;
     737             : 
     738           0 :         r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true);
     739           0 :         if (r)
     740           0 :                 return r;
     741             : 
     742             :         /* stitch together an UVD create msg */
     743           0 :         msg[0] = cpu_to_le32(0x00000de4);
     744           0 :         msg[1] = cpu_to_le32(0x00000000);
     745           0 :         msg[2] = cpu_to_le32(handle);
     746           0 :         msg[3] = cpu_to_le32(0x00000000);
     747           0 :         msg[4] = cpu_to_le32(0x00000000);
     748           0 :         msg[5] = cpu_to_le32(0x00000000);
     749           0 :         msg[6] = cpu_to_le32(0x00000000);
     750           0 :         msg[7] = cpu_to_le32(0x00000780);
     751           0 :         msg[8] = cpu_to_le32(0x00000440);
     752           0 :         msg[9] = cpu_to_le32(0x00000000);
     753           0 :         msg[10] = cpu_to_le32(0x01b37000);
     754           0 :         for (i = 11; i < 1024; ++i)
     755           0 :                 msg[i] = cpu_to_le32(0x0);
     756             : 
     757           0 :         r = radeon_uvd_send_msg(rdev, ring, addr, fence);
     758           0 :         radeon_bo_unreserve(rdev->uvd.vcpu_bo);
     759           0 :         return r;
     760           0 : }
     761             : 
     762           0 : int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
     763             :                                uint32_t handle, struct radeon_fence **fence)
     764             : {
     765             :         /* we use the last page of the vcpu bo for the UVD message */
     766           0 :         uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) -
     767             :                 RADEON_GPU_PAGE_SIZE;
     768             : 
     769           0 :         uint32_t *msg = rdev->uvd.cpu_addr + offs;
     770           0 :         uint64_t addr = rdev->uvd.gpu_addr + offs;
     771             : 
     772             :         int r, i;
     773             : 
     774           0 :         r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true);
     775           0 :         if (r)
     776           0 :                 return r;
     777             : 
     778             :         /* stitch together an UVD destroy msg */
     779           0 :         msg[0] = cpu_to_le32(0x00000de4);
     780           0 :         msg[1] = cpu_to_le32(0x00000002);
     781           0 :         msg[2] = cpu_to_le32(handle);
     782           0 :         msg[3] = cpu_to_le32(0x00000000);
     783           0 :         for (i = 4; i < 1024; ++i)
     784           0 :                 msg[i] = cpu_to_le32(0x0);
     785             : 
     786           0 :         r = radeon_uvd_send_msg(rdev, ring, addr, fence);
     787           0 :         radeon_bo_unreserve(rdev->uvd.vcpu_bo);
     788           0 :         return r;
     789           0 : }
     790             : 
     791             : /**
     792             :  * radeon_uvd_count_handles - count number of open streams
     793             :  *
     794             :  * @rdev: radeon_device pointer
     795             :  * @sd: number of SD streams
     796             :  * @hd: number of HD streams
     797             :  *
     798             :  * Count the number of open SD/HD streams as a hint for power mangement
     799             :  */
     800           0 : static void radeon_uvd_count_handles(struct radeon_device *rdev,
     801             :                                      unsigned *sd, unsigned *hd)
     802             : {
     803             :         unsigned i;
     804             : 
     805           0 :         *sd = 0;
     806           0 :         *hd = 0;
     807             : 
     808           0 :         for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
     809           0 :                 if (!atomic_read(&rdev->uvd.handles[i]))
     810             :                         continue;
     811             : 
     812           0 :                 if (rdev->uvd.img_size[i] >= 720*576)
     813           0 :                         ++(*hd);
     814             :                 else
     815           0 :                         ++(*sd);
     816             :         }
     817           0 : }
     818             : 
     819           0 : static void radeon_uvd_idle_work_handler(struct work_struct *work)
     820             : {
     821             :         struct radeon_device *rdev =
     822           0 :                 container_of(work, struct radeon_device, uvd.idle_work.work);
     823             : 
     824           0 :         if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0) {
     825           0 :                 if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
     826           0 :                         radeon_uvd_count_handles(rdev, &rdev->pm.dpm.sd,
     827           0 :                                                  &rdev->pm.dpm.hd);
     828           0 :                         radeon_dpm_enable_uvd(rdev, false);
     829           0 :                 } else {
     830           0 :                         radeon_set_uvd_clocks(rdev, 0, 0);
     831             :                 }
     832             :         } else {
     833           0 :                 schedule_delayed_work(&rdev->uvd.idle_work,
     834           0 :                                       msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
     835             :         }
     836           0 : }
     837             : 
     838           0 : void radeon_uvd_note_usage(struct radeon_device *rdev)
     839             : {
     840             :         bool streams_changed = false;
     841           0 :         bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work);
     842           0 :         set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work,
     843           0 :                                             msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
     844             : 
     845           0 :         if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
     846           0 :                 unsigned hd = 0, sd = 0;
     847           0 :                 radeon_uvd_count_handles(rdev, &sd, &hd);
     848           0 :                 if ((rdev->pm.dpm.sd != sd) ||
     849           0 :                     (rdev->pm.dpm.hd != hd)) {
     850           0 :                         rdev->pm.dpm.sd = sd;
     851           0 :                         rdev->pm.dpm.hd = hd;
     852             :                         /* disable this for now */
     853             :                         /*streams_changed = true;*/
     854           0 :                 }
     855           0 :         }
     856             : 
     857           0 :         if (set_clocks || streams_changed) {
     858           0 :                 if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
     859           0 :                         radeon_dpm_enable_uvd(rdev, true);
     860           0 :                 } else {
     861           0 :                         radeon_set_uvd_clocks(rdev, 53300, 40000);
     862             :                 }
     863             :         }
     864           0 : }
     865             : 
     866           0 : static unsigned radeon_uvd_calc_upll_post_div(unsigned vco_freq,
     867             :                                               unsigned target_freq,
     868             :                                               unsigned pd_min,
     869             :                                               unsigned pd_even)
     870             : {
     871           0 :         unsigned post_div = vco_freq / target_freq;
     872             : 
     873             :         /* adjust to post divider minimum value */
     874           0 :         if (post_div < pd_min)
     875           0 :                 post_div = pd_min;
     876             : 
     877             :         /* we alway need a frequency less than or equal the target */
     878           0 :         if ((vco_freq / post_div) > target_freq)
     879           0 :                 post_div += 1;
     880             : 
     881             :         /* post dividers above a certain value must be even */
     882           0 :         if (post_div > pd_even && post_div % 2)
     883           0 :                 post_div += 1;
     884             : 
     885           0 :         return post_div;
     886             : }
     887             : 
     888             : /**
     889             :  * radeon_uvd_calc_upll_dividers - calc UPLL clock dividers
     890             :  *
     891             :  * @rdev: radeon_device pointer
     892             :  * @vclk: wanted VCLK
     893             :  * @dclk: wanted DCLK
     894             :  * @vco_min: minimum VCO frequency
     895             :  * @vco_max: maximum VCO frequency
     896             :  * @fb_factor: factor to multiply vco freq with
     897             :  * @fb_mask: limit and bitmask for feedback divider
     898             :  * @pd_min: post divider minimum
     899             :  * @pd_max: post divider maximum
     900             :  * @pd_even: post divider must be even above this value
     901             :  * @optimal_fb_div: resulting feedback divider
     902             :  * @optimal_vclk_div: resulting vclk post divider
     903             :  * @optimal_dclk_div: resulting dclk post divider
     904             :  *
     905             :  * Calculate dividers for UVDs UPLL (R6xx-SI, except APUs).
     906             :  * Returns zero on success -EINVAL on error.
     907             :  */
     908           0 : int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev,
     909             :                                   unsigned vclk, unsigned dclk,
     910             :                                   unsigned vco_min, unsigned vco_max,
     911             :                                   unsigned fb_factor, unsigned fb_mask,
     912             :                                   unsigned pd_min, unsigned pd_max,
     913             :                                   unsigned pd_even,
     914             :                                   unsigned *optimal_fb_div,
     915             :                                   unsigned *optimal_vclk_div,
     916             :                                   unsigned *optimal_dclk_div)
     917             : {
     918           0 :         unsigned vco_freq, ref_freq = rdev->clock.spll.reference_freq;
     919             : 
     920             :         /* start off with something large */
     921             :         unsigned optimal_score = ~0;
     922             : 
     923             :         /* loop through vco from low to high */
     924           0 :         vco_min = max(max(vco_min, vclk), dclk);
     925           0 :         for (vco_freq = vco_min; vco_freq <= vco_max; vco_freq += 100) {
     926             : 
     927           0 :                 uint64_t fb_div = (uint64_t)vco_freq * fb_factor;
     928             :                 unsigned vclk_div, dclk_div, score;
     929             : 
     930           0 :                 do_div(fb_div, ref_freq);
     931             : 
     932             :                 /* fb div out of range ? */
     933           0 :                 if (fb_div > fb_mask)
     934           0 :                         break; /* it can oly get worse */
     935             : 
     936           0 :                 fb_div &= fb_mask;
     937             : 
     938             :                 /* calc vclk divider with current vco freq */
     939           0 :                 vclk_div = radeon_uvd_calc_upll_post_div(vco_freq, vclk,
     940             :                                                          pd_min, pd_even);
     941           0 :                 if (vclk_div > pd_max)
     942           0 :                         break; /* vco is too big, it has to stop */
     943             : 
     944             :                 /* calc dclk divider with current vco freq */
     945           0 :                 dclk_div = radeon_uvd_calc_upll_post_div(vco_freq, dclk,
     946             :                                                          pd_min, pd_even);
     947           0 :                 if (dclk_div > pd_max)
     948           0 :                         break; /* vco is too big, it has to stop */
     949             : 
     950             :                 /* calc score with current vco freq */
     951           0 :                 score = vclk - (vco_freq / vclk_div) + dclk - (vco_freq / dclk_div);
     952             : 
     953             :                 /* determine if this vco setting is better than current optimal settings */
     954           0 :                 if (score < optimal_score) {
     955           0 :                         *optimal_fb_div = fb_div;
     956           0 :                         *optimal_vclk_div = vclk_div;
     957           0 :                         *optimal_dclk_div = dclk_div;
     958             :                         optimal_score = score;
     959           0 :                         if (optimal_score == 0)
     960           0 :                                 break; /* it can't get better than this */
     961             :                 }
     962           0 :         }
     963             : 
     964             :         /* did we found a valid setup ? */
     965           0 :         if (optimal_score == ~0)
     966           0 :                 return -EINVAL;
     967             : 
     968           0 :         return 0;
     969           0 : }
     970             : 
     971           0 : int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev,
     972             :                                 unsigned cg_upll_func_cntl)
     973             : {
     974             :         unsigned i;
     975             : 
     976             :         /* make sure UPLL_CTLREQ is deasserted */
     977           0 :         WREG32_P(cg_upll_func_cntl, 0, ~UPLL_CTLREQ_MASK);
     978             : 
     979           0 :         mdelay(10);
     980             : 
     981             :         /* assert UPLL_CTLREQ */
     982           0 :         WREG32_P(cg_upll_func_cntl, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK);
     983             : 
     984             :         /* wait for CTLACK and CTLACK2 to get asserted */
     985           0 :         for (i = 0; i < 100; ++i) {
     986             :                 uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK;
     987           0 :                 if ((RREG32(cg_upll_func_cntl) & mask) == mask)
     988           0 :                         break;
     989           0 :                 mdelay(10);
     990           0 :         }
     991             : 
     992             :         /* deassert UPLL_CTLREQ */
     993           0 :         WREG32_P(cg_upll_func_cntl, 0, ~UPLL_CTLREQ_MASK);
     994             : 
     995           0 :         if (i == 100) {
     996           0 :                 DRM_ERROR("Timeout setting UVD clocks!\n");
     997           0 :                 return -ETIMEDOUT;
     998             :         }
     999             : 
    1000           0 :         return 0;
    1001           0 : }

Generated by: LCOV version 1.13