Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2013 Advanced Micro Devices, Inc.
0003  * All Rights Reserved.
0004  *
0005  * Permission is hereby granted, free of charge, to any person obtaining a
0006  * copy of this software and associated documentation files (the
0007  * "Software"), to deal in the Software without restriction, including
0008  * without limitation the rights to use, copy, modify, merge, publish,
0009  * distribute, sub license, and/or sell copies of the Software, and to
0010  * permit persons to whom the Software is furnished to do so, subject to
0011  * the following conditions:
0012  *
0013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0014  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0015  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
0016  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
0017  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
0018  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
0019  * USE OR OTHER DEALINGS IN THE SOFTWARE.
0020  *
0021  * The above copyright notice and this permission notice (including the
0022  * next paragraph) shall be included in all copies or substantial portions
0023  * of the Software.
0024  *
0025  * Authors: Christian König <christian.koenig@amd.com>
0026  */
0027 
0028 #include <linux/firmware.h>
0029 #include <linux/module.h>
0030 
0031 #include <drm/drm.h>
0032 
0033 #include "radeon.h"
0034 #include "radeon_asic.h"
0035 #include "sid.h"
0036 
0037 /* 1 second timeout */
0038 #define VCE_IDLE_TIMEOUT_MS 1000
0039 
0040 /* Firmware Names */
0041 #define FIRMWARE_TAHITI "radeon/TAHITI_vce.bin"
0042 #define FIRMWARE_BONAIRE    "radeon/BONAIRE_vce.bin"
0043 
0044 MODULE_FIRMWARE(FIRMWARE_TAHITI);
0045 MODULE_FIRMWARE(FIRMWARE_BONAIRE);
0046 
0047 static void radeon_vce_idle_work_handler(struct work_struct *work);
0048 
0049 /**
0050  * radeon_vce_init - allocate memory, load vce firmware
0051  *
0052  * @rdev: radeon_device pointer
0053  *
0054  * First step to get VCE online, allocate memory and load the firmware
0055  */
0056 int radeon_vce_init(struct radeon_device *rdev)
0057 {
0058     static const char *fw_version = "[ATI LIB=VCEFW,";
0059     static const char *fb_version = "[ATI LIB=VCEFWSTATS,";
0060     unsigned long size;
0061     const char *fw_name, *c;
0062     uint8_t start, mid, end;
0063     int i, r;
0064 
0065     INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler);
0066 
0067     switch (rdev->family) {
0068     case CHIP_TAHITI:
0069     case CHIP_PITCAIRN:
0070     case CHIP_VERDE:
0071     case CHIP_ARUBA:
0072         fw_name = FIRMWARE_TAHITI;
0073         break;
0074 
0075     case CHIP_BONAIRE:
0076     case CHIP_KAVERI:
0077     case CHIP_KABINI:
0078     case CHIP_HAWAII:
0079     case CHIP_MULLINS:
0080         fw_name = FIRMWARE_BONAIRE;
0081         break;
0082 
0083     default:
0084         return -EINVAL;
0085     }
0086 
0087     r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev);
0088     if (r) {
0089         dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n",
0090             fw_name);
0091         return r;
0092     }
0093 
0094     /* search for firmware version */
0095 
0096     size = rdev->vce_fw->size - strlen(fw_version) - 9;
0097     c = rdev->vce_fw->data;
0098     for (;size > 0; --size, ++c)
0099         if (strncmp(c, fw_version, strlen(fw_version)) == 0)
0100             break;
0101 
0102     if (size == 0)
0103         return -EINVAL;
0104 
0105     c += strlen(fw_version);
0106     if (sscanf(c, "%2hhd.%2hhd.%2hhd]", &start, &mid, &end) != 3)
0107         return -EINVAL;
0108 
0109     /* search for feedback version */
0110 
0111     size = rdev->vce_fw->size - strlen(fb_version) - 3;
0112     c = rdev->vce_fw->data;
0113     for (;size > 0; --size, ++c)
0114         if (strncmp(c, fb_version, strlen(fb_version)) == 0)
0115             break;
0116 
0117     if (size == 0)
0118         return -EINVAL;
0119 
0120     c += strlen(fb_version);
0121     if (sscanf(c, "%2u]", &rdev->vce.fb_version) != 1)
0122         return -EINVAL;
0123 
0124     DRM_INFO("Found VCE firmware/feedback version %d.%d.%d / %d!\n",
0125          start, mid, end, rdev->vce.fb_version);
0126 
0127     rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8);
0128 
0129     /* we can only work with this fw version for now */
0130     if ((rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) &&
0131         (rdev->vce.fw_version != ((50 << 24) | (0 << 16) | (1 << 8))) &&
0132         (rdev->vce.fw_version != ((50 << 24) | (1 << 16) | (2 << 8))))
0133         return -EINVAL;
0134 
0135     /* allocate firmware, stack and heap BO */
0136 
0137     if (rdev->family < CHIP_BONAIRE)
0138         size = vce_v1_0_bo_size(rdev);
0139     else
0140         size = vce_v2_0_bo_size(rdev);
0141     r = radeon_bo_create(rdev, size, PAGE_SIZE, true,
0142                  RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL,
0143                  &rdev->vce.vcpu_bo);
0144     if (r) {
0145         dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r);
0146         return r;
0147     }
0148 
0149     r = radeon_bo_reserve(rdev->vce.vcpu_bo, false);
0150     if (r) {
0151         radeon_bo_unref(&rdev->vce.vcpu_bo);
0152         dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r);
0153         return r;
0154     }
0155 
0156     r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM,
0157               &rdev->vce.gpu_addr);
0158     radeon_bo_unreserve(rdev->vce.vcpu_bo);
0159     if (r) {
0160         radeon_bo_unref(&rdev->vce.vcpu_bo);
0161         dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r);
0162         return r;
0163     }
0164 
0165     for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
0166         atomic_set(&rdev->vce.handles[i], 0);
0167         rdev->vce.filp[i] = NULL;
0168     }
0169 
0170     return 0;
0171 }
0172 
0173 /**
0174  * radeon_vce_fini - free memory
0175  *
0176  * @rdev: radeon_device pointer
0177  *
0178  * Last step on VCE teardown, free firmware memory
0179  */
0180 void radeon_vce_fini(struct radeon_device *rdev)
0181 {
0182     if (rdev->vce.vcpu_bo == NULL)
0183         return;
0184 
0185     radeon_bo_unref(&rdev->vce.vcpu_bo);
0186 
0187     release_firmware(rdev->vce_fw);
0188 }
0189 
0190 /**
0191  * radeon_vce_suspend - unpin VCE fw memory
0192  *
0193  * @rdev: radeon_device pointer
0194  *
0195  */
0196 int radeon_vce_suspend(struct radeon_device *rdev)
0197 {
0198     int i;
0199 
0200     if (rdev->vce.vcpu_bo == NULL)
0201         return 0;
0202 
0203     for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i)
0204         if (atomic_read(&rdev->vce.handles[i]))
0205             break;
0206 
0207     if (i == RADEON_MAX_VCE_HANDLES)
0208         return 0;
0209 
0210     /* TODO: suspending running encoding sessions isn't supported */
0211     return -EINVAL;
0212 }
0213 
0214 /**
0215  * radeon_vce_resume - pin VCE fw memory
0216  *
0217  * @rdev: radeon_device pointer
0218  *
0219  */
0220 int radeon_vce_resume(struct radeon_device *rdev)
0221 {
0222     void *cpu_addr;
0223     int r;
0224 
0225     if (rdev->vce.vcpu_bo == NULL)
0226         return -EINVAL;
0227 
0228     r = radeon_bo_reserve(rdev->vce.vcpu_bo, false);
0229     if (r) {
0230         dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r);
0231         return r;
0232     }
0233 
0234     r = radeon_bo_kmap(rdev->vce.vcpu_bo, &cpu_addr);
0235     if (r) {
0236         radeon_bo_unreserve(rdev->vce.vcpu_bo);
0237         dev_err(rdev->dev, "(%d) VCE map failed\n", r);
0238         return r;
0239     }
0240 
0241     memset(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo));
0242     if (rdev->family < CHIP_BONAIRE)
0243         r = vce_v1_0_load_fw(rdev, cpu_addr);
0244     else
0245         memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size);
0246 
0247     radeon_bo_kunmap(rdev->vce.vcpu_bo);
0248 
0249     radeon_bo_unreserve(rdev->vce.vcpu_bo);
0250 
0251     return r;
0252 }
0253 
0254 /**
0255  * radeon_vce_idle_work_handler - power off VCE
0256  *
0257  * @work: pointer to work structure
0258  *
0259  * power of VCE when it's not used any more
0260  */
0261 static void radeon_vce_idle_work_handler(struct work_struct *work)
0262 {
0263     struct radeon_device *rdev =
0264         container_of(work, struct radeon_device, vce.idle_work.work);
0265 
0266     if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX) == 0) &&
0267         (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX) == 0)) {
0268         if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
0269             radeon_dpm_enable_vce(rdev, false);
0270         } else {
0271             radeon_set_vce_clocks(rdev, 0, 0);
0272         }
0273     } else {
0274         schedule_delayed_work(&rdev->vce.idle_work,
0275                       msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
0276     }
0277 }
0278 
0279 /**
0280  * radeon_vce_note_usage - power up VCE
0281  *
0282  * @rdev: radeon_device pointer
0283  *
0284  * Make sure VCE is powerd up when we want to use it
0285  */
0286 void radeon_vce_note_usage(struct radeon_device *rdev)
0287 {
0288     bool streams_changed = false;
0289     bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work);
0290     set_clocks &= schedule_delayed_work(&rdev->vce.idle_work,
0291                         msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
0292 
0293     if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
0294         /* XXX figure out if the streams changed */
0295         streams_changed = false;
0296     }
0297 
0298     if (set_clocks || streams_changed) {
0299         if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
0300             radeon_dpm_enable_vce(rdev, true);
0301         } else {
0302             radeon_set_vce_clocks(rdev, 53300, 40000);
0303         }
0304     }
0305 }
0306 
0307 /**
0308  * radeon_vce_free_handles - free still open VCE handles
0309  *
0310  * @rdev: radeon_device pointer
0311  * @filp: drm file pointer
0312  *
0313  * Close all VCE handles still open by this file pointer
0314  */
0315 void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp)
0316 {
0317     int i, r;
0318     for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
0319         uint32_t handle = atomic_read(&rdev->vce.handles[i]);
0320         if (!handle || rdev->vce.filp[i] != filp)
0321             continue;
0322 
0323         radeon_vce_note_usage(rdev);
0324 
0325         r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX,
0326                            handle, NULL);
0327         if (r)
0328             DRM_ERROR("Error destroying VCE handle (%d)!\n", r);
0329 
0330         rdev->vce.filp[i] = NULL;
0331         atomic_set(&rdev->vce.handles[i], 0);
0332     }
0333 }
0334 
0335 /**
0336  * radeon_vce_get_create_msg - generate a VCE create msg
0337  *
0338  * @rdev: radeon_device pointer
0339  * @ring: ring we should submit the msg to
0340  * @handle: VCE session handle to use
0341  * @fence: optional fence to return
0342  *
0343  * Open up a stream for HW test
0344  */
0345 int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring,
0346                   uint32_t handle, struct radeon_fence **fence)
0347 {
0348     const unsigned ib_size_dw = 1024;
0349     struct radeon_ib ib;
0350     uint64_t dummy;
0351     int i, r;
0352 
0353     r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4);
0354     if (r) {
0355         DRM_ERROR("radeon: failed to get ib (%d).\n", r);
0356         return r;
0357     }
0358 
0359     dummy = ib.gpu_addr + 1024;
0360 
0361     /* stitch together an VCE create msg */
0362     ib.length_dw = 0;
0363     ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */
0364     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */
0365     ib.ptr[ib.length_dw++] = cpu_to_le32(handle);
0366 
0367     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000030); /* len */
0368     ib.ptr[ib.length_dw++] = cpu_to_le32(0x01000001); /* create cmd */
0369     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000);
0370     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000042);
0371     ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000a);
0372     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
0373     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000080);
0374     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000060);
0375     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100);
0376     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100);
0377     ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c);
0378     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000);
0379 
0380     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */
0381     ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */
0382     ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy));
0383     ib.ptr[ib.length_dw++] = cpu_to_le32(dummy);
0384     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
0385 
0386     for (i = ib.length_dw; i < ib_size_dw; ++i)
0387         ib.ptr[i] = cpu_to_le32(0x0);
0388 
0389     r = radeon_ib_schedule(rdev, &ib, NULL, false);
0390     if (r)
0391         DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
0392 
0393 
0394     if (fence)
0395         *fence = radeon_fence_ref(ib.fence);
0396 
0397     radeon_ib_free(rdev, &ib);
0398 
0399     return r;
0400 }
0401 
0402 /**
0403  * radeon_vce_get_destroy_msg - generate a VCE destroy msg
0404  *
0405  * @rdev: radeon_device pointer
0406  * @ring: ring we should submit the msg to
0407  * @handle: VCE session handle to use
0408  * @fence: optional fence to return
0409  *
0410  * Close up a stream for HW test or if userspace failed to do so
0411  */
0412 int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring,
0413                    uint32_t handle, struct radeon_fence **fence)
0414 {
0415     const unsigned ib_size_dw = 1024;
0416     struct radeon_ib ib;
0417     uint64_t dummy;
0418     int i, r;
0419 
0420     r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4);
0421     if (r) {
0422         DRM_ERROR("radeon: failed to get ib (%d).\n", r);
0423         return r;
0424     }
0425 
0426     dummy = ib.gpu_addr + 1024;
0427 
0428     /* stitch together an VCE destroy msg */
0429     ib.length_dw = 0;
0430     ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */
0431     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */
0432     ib.ptr[ib.length_dw++] = cpu_to_le32(handle);
0433 
0434     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */
0435     ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */
0436     ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy));
0437     ib.ptr[ib.length_dw++] = cpu_to_le32(dummy);
0438     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
0439 
0440     ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008); /* len */
0441     ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001); /* destroy cmd */
0442 
0443     for (i = ib.length_dw; i < ib_size_dw; ++i)
0444         ib.ptr[i] = cpu_to_le32(0x0);
0445 
0446     r = radeon_ib_schedule(rdev, &ib, NULL, false);
0447     if (r) {
0448         DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
0449     }
0450 
0451     if (fence)
0452         *fence = radeon_fence_ref(ib.fence);
0453 
0454     radeon_ib_free(rdev, &ib);
0455 
0456     return r;
0457 }
0458 
0459 /**
0460  * radeon_vce_cs_reloc - command submission relocation
0461  *
0462  * @p: parser context
0463  * @lo: address of lower dword
0464  * @hi: address of higher dword
0465  * @size: size of checker for relocation buffer
0466  *
0467  * Patch relocation inside command stream with real buffer address
0468  */
0469 int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi,
0470             unsigned size)
0471 {
0472     struct radeon_cs_chunk *relocs_chunk;
0473     struct radeon_bo_list *reloc;
0474     uint64_t start, end, offset;
0475     unsigned idx;
0476 
0477     relocs_chunk = p->chunk_relocs;
0478     offset = radeon_get_ib_value(p, lo);
0479     idx = radeon_get_ib_value(p, hi);
0480 
0481     if (idx >= relocs_chunk->length_dw) {
0482         DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
0483               idx, relocs_chunk->length_dw);
0484         return -EINVAL;
0485     }
0486 
0487     reloc = &p->relocs[(idx / 4)];
0488     start = reloc->gpu_offset;
0489     end = start + radeon_bo_size(reloc->robj);
0490     start += offset;
0491 
0492     p->ib.ptr[lo] = start & 0xFFFFFFFF;
0493     p->ib.ptr[hi] = start >> 32;
0494 
0495     if (end <= start) {
0496         DRM_ERROR("invalid reloc offset %llX!\n", offset);
0497         return -EINVAL;
0498     }
0499     if ((end - start) < size) {
0500         DRM_ERROR("buffer to small (%d / %d)!\n",
0501             (unsigned)(end - start), size);
0502         return -EINVAL;
0503     }
0504 
0505     return 0;
0506 }
0507 
0508 /**
0509  * radeon_vce_validate_handle - validate stream handle
0510  *
0511  * @p: parser context
0512  * @handle: handle to validate
0513  * @allocated: allocated a new handle?
0514  *
0515  * Validates the handle and return the found session index or -EINVAL
0516  * we don't have another free session index.
0517  */
0518 static int radeon_vce_validate_handle(struct radeon_cs_parser *p,
0519                       uint32_t handle, bool *allocated)
0520 {
0521     unsigned i;
0522 
0523     *allocated = false;
0524 
0525     /* validate the handle */
0526     for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
0527         if (atomic_read(&p->rdev->vce.handles[i]) == handle) {
0528             if (p->rdev->vce.filp[i] != p->filp) {
0529                 DRM_ERROR("VCE handle collision detected!\n");
0530                 return -EINVAL;
0531             }
0532             return i;
0533         }
0534     }
0535 
0536     /* handle not found try to alloc a new one */
0537     for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
0538         if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) {
0539             p->rdev->vce.filp[i] = p->filp;
0540             p->rdev->vce.img_size[i] = 0;
0541             *allocated = true;
0542             return i;
0543         }
0544     }
0545 
0546     DRM_ERROR("No more free VCE handles!\n");
0547     return -EINVAL;
0548 }
0549 
0550 /**
0551  * radeon_vce_cs_parse - parse and validate the command stream
0552  *
0553  * @p: parser context
0554  *
0555  */
0556 int radeon_vce_cs_parse(struct radeon_cs_parser *p)
0557 {
0558     int session_idx = -1;
0559     bool destroyed = false, created = false, allocated = false;
0560     uint32_t tmp, handle = 0;
0561     uint32_t *size = &tmp;
0562     int i, r = 0;
0563 
0564     while (p->idx < p->chunk_ib->length_dw) {
0565         uint32_t len = radeon_get_ib_value(p, p->idx);
0566         uint32_t cmd = radeon_get_ib_value(p, p->idx + 1);
0567 
0568         if ((len < 8) || (len & 3)) {
0569             DRM_ERROR("invalid VCE command length (%d)!\n", len);
0570             r = -EINVAL;
0571             goto out;
0572         }
0573 
0574         if (destroyed) {
0575             DRM_ERROR("No other command allowed after destroy!\n");
0576             r = -EINVAL;
0577             goto out;
0578         }
0579 
0580         switch (cmd) {
0581         case 0x00000001: // session
0582             handle = radeon_get_ib_value(p, p->idx + 2);
0583             session_idx = radeon_vce_validate_handle(p, handle,
0584                                  &allocated);
0585             if (session_idx < 0)
0586                 return session_idx;
0587             size = &p->rdev->vce.img_size[session_idx];
0588             break;
0589 
0590         case 0x00000002: // task info
0591             break;
0592 
0593         case 0x01000001: // create
0594             created = true;
0595             if (!allocated) {
0596                 DRM_ERROR("Handle already in use!\n");
0597                 r = -EINVAL;
0598                 goto out;
0599             }
0600 
0601             *size = radeon_get_ib_value(p, p->idx + 8) *
0602                 radeon_get_ib_value(p, p->idx + 10) *
0603                 8 * 3 / 2;
0604             break;
0605 
0606         case 0x04000001: // config extension
0607         case 0x04000002: // pic control
0608         case 0x04000005: // rate control
0609         case 0x04000007: // motion estimation
0610         case 0x04000008: // rdo
0611         case 0x04000009: // vui
0612             break;
0613 
0614         case 0x03000001: // encode
0615             r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9,
0616                         *size);
0617             if (r)
0618                 goto out;
0619 
0620             r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11,
0621                         *size / 3);
0622             if (r)
0623                 goto out;
0624             break;
0625 
0626         case 0x02000001: // destroy
0627             destroyed = true;
0628             break;
0629 
0630         case 0x05000001: // context buffer
0631             r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
0632                         *size * 2);
0633             if (r)
0634                 goto out;
0635             break;
0636 
0637         case 0x05000004: // video bitstream buffer
0638             tmp = radeon_get_ib_value(p, p->idx + 4);
0639             r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
0640                         tmp);
0641             if (r)
0642                 goto out;
0643             break;
0644 
0645         case 0x05000005: // feedback buffer
0646             r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2,
0647                         4096);
0648             if (r)
0649                 goto out;
0650             break;
0651 
0652         default:
0653             DRM_ERROR("invalid VCE command (0x%x)!\n", cmd);
0654             r = -EINVAL;
0655             goto out;
0656         }
0657 
0658         if (session_idx == -1) {
0659             DRM_ERROR("no session command at start of IB\n");
0660             r = -EINVAL;
0661             goto out;
0662         }
0663 
0664         p->idx += len / 4;
0665     }
0666 
0667     if (allocated && !created) {
0668         DRM_ERROR("New session without create command!\n");
0669         r = -ENOENT;
0670     }
0671 
0672 out:
0673     if ((!r && destroyed) || (r && allocated)) {
0674         /*
0675          * IB contains a destroy msg or we have allocated an
0676          * handle and got an error, anyway free the handle
0677          */
0678         for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i)
0679             atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0);
0680     }
0681 
0682     return r;
0683 }
0684 
0685 /**
0686  * radeon_vce_semaphore_emit - emit a semaphore command
0687  *
0688  * @rdev: radeon_device pointer
0689  * @ring: engine to use
0690  * @semaphore: address of semaphore
0691  * @emit_wait: true=emit wait, false=emit signal
0692  *
0693  */
0694 bool radeon_vce_semaphore_emit(struct radeon_device *rdev,
0695                    struct radeon_ring *ring,
0696                    struct radeon_semaphore *semaphore,
0697                    bool emit_wait)
0698 {
0699     uint64_t addr = semaphore->gpu_addr;
0700 
0701     radeon_ring_write(ring, cpu_to_le32(VCE_CMD_SEMAPHORE));
0702     radeon_ring_write(ring, cpu_to_le32((addr >> 3) & 0x000FFFFF));
0703     radeon_ring_write(ring, cpu_to_le32((addr >> 23) & 0x000FFFFF));
0704     radeon_ring_write(ring, cpu_to_le32(0x01003000 | (emit_wait ? 1 : 0)));
0705     if (!emit_wait)
0706         radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
0707 
0708     return true;
0709 }
0710 
0711 /**
0712  * radeon_vce_ib_execute - execute indirect buffer
0713  *
0714  * @rdev: radeon_device pointer
0715  * @ib: the IB to execute
0716  *
0717  */
0718 void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
0719 {
0720     struct radeon_ring *ring = &rdev->ring[ib->ring];
0721     radeon_ring_write(ring, cpu_to_le32(VCE_CMD_IB));
0722     radeon_ring_write(ring, cpu_to_le32(ib->gpu_addr));
0723     radeon_ring_write(ring, cpu_to_le32(upper_32_bits(ib->gpu_addr)));
0724     radeon_ring_write(ring, cpu_to_le32(ib->length_dw));
0725 }
0726 
0727 /**
0728  * radeon_vce_fence_emit - add a fence command to the ring
0729  *
0730  * @rdev: radeon_device pointer
0731  * @fence: the fence
0732  *
0733  */
0734 void radeon_vce_fence_emit(struct radeon_device *rdev,
0735                struct radeon_fence *fence)
0736 {
0737     struct radeon_ring *ring = &rdev->ring[fence->ring];
0738     uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;
0739 
0740     radeon_ring_write(ring, cpu_to_le32(VCE_CMD_FENCE));
0741     radeon_ring_write(ring, cpu_to_le32(addr));
0742     radeon_ring_write(ring, cpu_to_le32(upper_32_bits(addr)));
0743     radeon_ring_write(ring, cpu_to_le32(fence->seq));
0744     radeon_ring_write(ring, cpu_to_le32(VCE_CMD_TRAP));
0745     radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
0746 }
0747 
0748 /**
0749  * radeon_vce_ring_test - test if VCE ring is working
0750  *
0751  * @rdev: radeon_device pointer
0752  * @ring: the engine to test on
0753  *
0754  */
0755 int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
0756 {
0757     uint32_t rptr = vce_v1_0_get_rptr(rdev, ring);
0758     unsigned i;
0759     int r;
0760 
0761     r = radeon_ring_lock(rdev, ring, 16);
0762     if (r) {
0763         DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n",
0764               ring->idx, r);
0765         return r;
0766     }
0767     radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
0768     radeon_ring_unlock_commit(rdev, ring, false);
0769 
0770     for (i = 0; i < rdev->usec_timeout; i++) {
0771         if (vce_v1_0_get_rptr(rdev, ring) != rptr)
0772             break;
0773         udelay(1);
0774     }
0775 
0776     if (i < rdev->usec_timeout) {
0777         DRM_INFO("ring test on %d succeeded in %d usecs\n",
0778              ring->idx, i);
0779     } else {
0780         DRM_ERROR("radeon: ring %d test failed\n",
0781              ring->idx);
0782         r = -ETIMEDOUT;
0783     }
0784 
0785     return r;
0786 }
0787 
0788 /**
0789  * radeon_vce_ib_test - test if VCE IBs are working
0790  *
0791  * @rdev: radeon_device pointer
0792  * @ring: the engine to test on
0793  *
0794  */
0795 int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
0796 {
0797     struct radeon_fence *fence = NULL;
0798     int r;
0799 
0800     r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL);
0801     if (r) {
0802         DRM_ERROR("radeon: failed to get create msg (%d).\n", r);
0803         goto error;
0804     }
0805 
0806     r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence);
0807     if (r) {
0808         DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r);
0809         goto error;
0810     }
0811 
0812     r = radeon_fence_wait_timeout(fence, false, usecs_to_jiffies(
0813         RADEON_USEC_IB_TEST_TIMEOUT));
0814     if (r < 0) {
0815         DRM_ERROR("radeon: fence wait failed (%d).\n", r);
0816     } else if (r == 0) {
0817         DRM_ERROR("radeon: fence wait timed out.\n");
0818         r = -ETIMEDOUT;
0819     } else {
0820         DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
0821         r = 0;
0822     }
0823 error:
0824     radeon_fence_unref(&fence);
0825     return r;
0826 }