162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2013 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 662306a36Sopenharmony_ci * copy of this software and associated documentation files (the 762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 962306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1162306a36Sopenharmony_ci * the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1462306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1562306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 1662306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 1762306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 1862306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 1962306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 2262306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 2362306a36Sopenharmony_ci * of the Software. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * Authors: Christian König <christian.koenig@amd.com> 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include <linux/firmware.h> 2962306a36Sopenharmony_ci#include <linux/module.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <drm/drm.h> 3262306a36Sopenharmony_ci#include <drm/drm_drv.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "amdgpu.h" 3562306a36Sopenharmony_ci#include "amdgpu_pm.h" 3662306a36Sopenharmony_ci#include "amdgpu_vce.h" 3762306a36Sopenharmony_ci#include "amdgpu_cs.h" 3862306a36Sopenharmony_ci#include "cikd.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* 1 second timeout */ 4162306a36Sopenharmony_ci#define VCE_IDLE_TIMEOUT msecs_to_jiffies(1000) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Firmware Names */ 4462306a36Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_CIK 4562306a36Sopenharmony_ci#define FIRMWARE_BONAIRE "amdgpu/bonaire_vce.bin" 4662306a36Sopenharmony_ci#define FIRMWARE_KABINI "amdgpu/kabini_vce.bin" 4762306a36Sopenharmony_ci#define FIRMWARE_KAVERI "amdgpu/kaveri_vce.bin" 4862306a36Sopenharmony_ci#define FIRMWARE_HAWAII "amdgpu/hawaii_vce.bin" 4962306a36Sopenharmony_ci#define FIRMWARE_MULLINS "amdgpu/mullins_vce.bin" 5062306a36Sopenharmony_ci#endif 5162306a36Sopenharmony_ci#define FIRMWARE_TONGA "amdgpu/tonga_vce.bin" 5262306a36Sopenharmony_ci#define FIRMWARE_CARRIZO "amdgpu/carrizo_vce.bin" 5362306a36Sopenharmony_ci#define FIRMWARE_FIJI "amdgpu/fiji_vce.bin" 5462306a36Sopenharmony_ci#define FIRMWARE_STONEY "amdgpu/stoney_vce.bin" 5562306a36Sopenharmony_ci#define FIRMWARE_POLARIS10 "amdgpu/polaris10_vce.bin" 5662306a36Sopenharmony_ci#define FIRMWARE_POLARIS11 "amdgpu/polaris11_vce.bin" 5762306a36Sopenharmony_ci#define FIRMWARE_POLARIS12 "amdgpu/polaris12_vce.bin" 5862306a36Sopenharmony_ci#define FIRMWARE_VEGAM "amdgpu/vegam_vce.bin" 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define FIRMWARE_VEGA10 "amdgpu/vega10_vce.bin" 6162306a36Sopenharmony_ci#define FIRMWARE_VEGA12 "amdgpu/vega12_vce.bin" 6262306a36Sopenharmony_ci#define FIRMWARE_VEGA20 "amdgpu/vega20_vce.bin" 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_CIK 6562306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_BONAIRE); 6662306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_KABINI); 6762306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_KAVERI); 6862306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_HAWAII); 6962306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_MULLINS); 7062306a36Sopenharmony_ci#endif 7162306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_TONGA); 7262306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_CARRIZO); 7362306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_FIJI); 7462306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_STONEY); 7562306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_POLARIS10); 7662306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_POLARIS11); 7762306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_POLARIS12); 7862306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_VEGAM); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_VEGA10); 8162306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_VEGA12); 8262306a36Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_VEGA20); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void amdgpu_vce_idle_work_handler(struct work_struct *work); 8562306a36Sopenharmony_cistatic int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, 8662306a36Sopenharmony_ci struct dma_fence **fence); 8762306a36Sopenharmony_cistatic int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, 8862306a36Sopenharmony_ci bool direct, struct dma_fence **fence); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/** 9162306a36Sopenharmony_ci * amdgpu_vce_sw_init - allocate memory, load vce firmware 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * @adev: amdgpu_device pointer 9462306a36Sopenharmony_ci * @size: size for the new BO 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * First step to get VCE online, allocate memory and load the firmware 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ciint amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci const char *fw_name; 10162306a36Sopenharmony_ci const struct common_firmware_header *hdr; 10262306a36Sopenharmony_ci unsigned int ucode_version, version_major, version_minor, binary_id; 10362306a36Sopenharmony_ci int i, r; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci switch (adev->asic_type) { 10662306a36Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_CIK 10762306a36Sopenharmony_ci case CHIP_BONAIRE: 10862306a36Sopenharmony_ci fw_name = FIRMWARE_BONAIRE; 10962306a36Sopenharmony_ci break; 11062306a36Sopenharmony_ci case CHIP_KAVERI: 11162306a36Sopenharmony_ci fw_name = FIRMWARE_KAVERI; 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci case CHIP_KABINI: 11462306a36Sopenharmony_ci fw_name = FIRMWARE_KABINI; 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci case CHIP_HAWAII: 11762306a36Sopenharmony_ci fw_name = FIRMWARE_HAWAII; 11862306a36Sopenharmony_ci break; 11962306a36Sopenharmony_ci case CHIP_MULLINS: 12062306a36Sopenharmony_ci fw_name = FIRMWARE_MULLINS; 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci#endif 12362306a36Sopenharmony_ci case CHIP_TONGA: 12462306a36Sopenharmony_ci fw_name = FIRMWARE_TONGA; 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci case CHIP_CARRIZO: 12762306a36Sopenharmony_ci fw_name = FIRMWARE_CARRIZO; 12862306a36Sopenharmony_ci break; 12962306a36Sopenharmony_ci case CHIP_FIJI: 13062306a36Sopenharmony_ci fw_name = FIRMWARE_FIJI; 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci case CHIP_STONEY: 13362306a36Sopenharmony_ci fw_name = FIRMWARE_STONEY; 13462306a36Sopenharmony_ci break; 13562306a36Sopenharmony_ci case CHIP_POLARIS10: 13662306a36Sopenharmony_ci fw_name = FIRMWARE_POLARIS10; 13762306a36Sopenharmony_ci break; 13862306a36Sopenharmony_ci case CHIP_POLARIS11: 13962306a36Sopenharmony_ci fw_name = FIRMWARE_POLARIS11; 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci case CHIP_POLARIS12: 14262306a36Sopenharmony_ci fw_name = FIRMWARE_POLARIS12; 14362306a36Sopenharmony_ci break; 14462306a36Sopenharmony_ci case CHIP_VEGAM: 14562306a36Sopenharmony_ci fw_name = FIRMWARE_VEGAM; 14662306a36Sopenharmony_ci break; 14762306a36Sopenharmony_ci case CHIP_VEGA10: 14862306a36Sopenharmony_ci fw_name = FIRMWARE_VEGA10; 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci case CHIP_VEGA12: 15162306a36Sopenharmony_ci fw_name = FIRMWARE_VEGA12; 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci case CHIP_VEGA20: 15462306a36Sopenharmony_ci fw_name = FIRMWARE_VEGA20; 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci default: 15862306a36Sopenharmony_ci return -EINVAL; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci r = amdgpu_ucode_request(adev, &adev->vce.fw, fw_name); 16262306a36Sopenharmony_ci if (r) { 16362306a36Sopenharmony_ci dev_err(adev->dev, "amdgpu_vce: Can't validate firmware \"%s\"\n", 16462306a36Sopenharmony_ci fw_name); 16562306a36Sopenharmony_ci amdgpu_ucode_release(&adev->vce.fw); 16662306a36Sopenharmony_ci return r; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci hdr = (const struct common_firmware_header *)adev->vce.fw->data; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci ucode_version = le32_to_cpu(hdr->ucode_version); 17262306a36Sopenharmony_ci version_major = (ucode_version >> 20) & 0xfff; 17362306a36Sopenharmony_ci version_minor = (ucode_version >> 8) & 0xfff; 17462306a36Sopenharmony_ci binary_id = ucode_version & 0xff; 17562306a36Sopenharmony_ci DRM_INFO("Found VCE firmware Version: %d.%d Binary ID: %d\n", 17662306a36Sopenharmony_ci version_major, version_minor, binary_id); 17762306a36Sopenharmony_ci adev->vce.fw_version = ((version_major << 24) | (version_minor << 16) | 17862306a36Sopenharmony_ci (binary_id << 8)); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci r = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE, 18162306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_VRAM | 18262306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_GTT, 18362306a36Sopenharmony_ci &adev->vce.vcpu_bo, 18462306a36Sopenharmony_ci &adev->vce.gpu_addr, &adev->vce.cpu_addr); 18562306a36Sopenharmony_ci if (r) { 18662306a36Sopenharmony_ci dev_err(adev->dev, "(%d) failed to allocate VCE bo\n", r); 18762306a36Sopenharmony_ci return r; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { 19162306a36Sopenharmony_ci atomic_set(&adev->vce.handles[i], 0); 19262306a36Sopenharmony_ci adev->vce.filp[i] = NULL; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci INIT_DELAYED_WORK(&adev->vce.idle_work, amdgpu_vce_idle_work_handler); 19662306a36Sopenharmony_ci mutex_init(&adev->vce.idle_mutex); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return 0; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/** 20262306a36Sopenharmony_ci * amdgpu_vce_sw_fini - free memory 20362306a36Sopenharmony_ci * 20462306a36Sopenharmony_ci * @adev: amdgpu_device pointer 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * Last step on VCE teardown, free firmware memory 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ciint amdgpu_vce_sw_fini(struct amdgpu_device *adev) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci unsigned int i; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (adev->vce.vcpu_bo == NULL) 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci drm_sched_entity_destroy(&adev->vce.entity); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci amdgpu_bo_free_kernel(&adev->vce.vcpu_bo, &adev->vce.gpu_addr, 21862306a36Sopenharmony_ci (void **)&adev->vce.cpu_addr); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci for (i = 0; i < adev->vce.num_rings; i++) 22162306a36Sopenharmony_ci amdgpu_ring_fini(&adev->vce.ring[i]); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci amdgpu_ucode_release(&adev->vce.fw); 22462306a36Sopenharmony_ci mutex_destroy(&adev->vce.idle_mutex); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return 0; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/** 23062306a36Sopenharmony_ci * amdgpu_vce_entity_init - init entity 23162306a36Sopenharmony_ci * 23262306a36Sopenharmony_ci * @adev: amdgpu_device pointer 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_ciint amdgpu_vce_entity_init(struct amdgpu_device *adev) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct amdgpu_ring *ring; 23862306a36Sopenharmony_ci struct drm_gpu_scheduler *sched; 23962306a36Sopenharmony_ci int r; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci ring = &adev->vce.ring[0]; 24262306a36Sopenharmony_ci sched = &ring->sched; 24362306a36Sopenharmony_ci r = drm_sched_entity_init(&adev->vce.entity, DRM_SCHED_PRIORITY_NORMAL, 24462306a36Sopenharmony_ci &sched, 1, NULL); 24562306a36Sopenharmony_ci if (r != 0) { 24662306a36Sopenharmony_ci DRM_ERROR("Failed setting up VCE run queue.\n"); 24762306a36Sopenharmony_ci return r; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/** 25462306a36Sopenharmony_ci * amdgpu_vce_suspend - unpin VCE fw memory 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * @adev: amdgpu_device pointer 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ciint amdgpu_vce_suspend(struct amdgpu_device *adev) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci int i; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci cancel_delayed_work_sync(&adev->vce.idle_work); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (adev->vce.vcpu_bo == NULL) 26662306a36Sopenharmony_ci return 0; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) 26962306a36Sopenharmony_ci if (atomic_read(&adev->vce.handles[i])) 27062306a36Sopenharmony_ci break; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (i == AMDGPU_MAX_VCE_HANDLES) 27362306a36Sopenharmony_ci return 0; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* TODO: suspending running encoding sessions isn't supported */ 27662306a36Sopenharmony_ci return -EINVAL; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci/** 28062306a36Sopenharmony_ci * amdgpu_vce_resume - pin VCE fw memory 28162306a36Sopenharmony_ci * 28262306a36Sopenharmony_ci * @adev: amdgpu_device pointer 28362306a36Sopenharmony_ci * 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ciint amdgpu_vce_resume(struct amdgpu_device *adev) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci void *cpu_addr; 28862306a36Sopenharmony_ci const struct common_firmware_header *hdr; 28962306a36Sopenharmony_ci unsigned int offset; 29062306a36Sopenharmony_ci int r, idx; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (adev->vce.vcpu_bo == NULL) 29362306a36Sopenharmony_ci return -EINVAL; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci r = amdgpu_bo_reserve(adev->vce.vcpu_bo, false); 29662306a36Sopenharmony_ci if (r) { 29762306a36Sopenharmony_ci dev_err(adev->dev, "(%d) failed to reserve VCE bo\n", r); 29862306a36Sopenharmony_ci return r; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci r = amdgpu_bo_kmap(adev->vce.vcpu_bo, &cpu_addr); 30262306a36Sopenharmony_ci if (r) { 30362306a36Sopenharmony_ci amdgpu_bo_unreserve(adev->vce.vcpu_bo); 30462306a36Sopenharmony_ci dev_err(adev->dev, "(%d) VCE map failed\n", r); 30562306a36Sopenharmony_ci return r; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci hdr = (const struct common_firmware_header *)adev->vce.fw->data; 30962306a36Sopenharmony_ci offset = le32_to_cpu(hdr->ucode_array_offset_bytes); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (drm_dev_enter(adev_to_drm(adev), &idx)) { 31262306a36Sopenharmony_ci memcpy_toio(cpu_addr, adev->vce.fw->data + offset, 31362306a36Sopenharmony_ci adev->vce.fw->size - offset); 31462306a36Sopenharmony_ci drm_dev_exit(idx); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci amdgpu_bo_kunmap(adev->vce.vcpu_bo); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci amdgpu_bo_unreserve(adev->vce.vcpu_bo); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/** 32562306a36Sopenharmony_ci * amdgpu_vce_idle_work_handler - power off VCE 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci * @work: pointer to work structure 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * power of VCE when it's not used any more 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_cistatic void amdgpu_vce_idle_work_handler(struct work_struct *work) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct amdgpu_device *adev = 33462306a36Sopenharmony_ci container_of(work, struct amdgpu_device, vce.idle_work.work); 33562306a36Sopenharmony_ci unsigned int i, count = 0; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci for (i = 0; i < adev->vce.num_rings; i++) 33862306a36Sopenharmony_ci count += amdgpu_fence_count_emitted(&adev->vce.ring[i]); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (count == 0) { 34162306a36Sopenharmony_ci if (adev->pm.dpm_enabled) { 34262306a36Sopenharmony_ci amdgpu_dpm_enable_vce(adev, false); 34362306a36Sopenharmony_ci } else { 34462306a36Sopenharmony_ci amdgpu_asic_set_vce_clocks(adev, 0, 0); 34562306a36Sopenharmony_ci amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE, 34662306a36Sopenharmony_ci AMD_PG_STATE_GATE); 34762306a36Sopenharmony_ci amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE, 34862306a36Sopenharmony_ci AMD_CG_STATE_GATE); 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci } else { 35162306a36Sopenharmony_ci schedule_delayed_work(&adev->vce.idle_work, VCE_IDLE_TIMEOUT); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci/** 35662306a36Sopenharmony_ci * amdgpu_vce_ring_begin_use - power up VCE 35762306a36Sopenharmony_ci * 35862306a36Sopenharmony_ci * @ring: amdgpu ring 35962306a36Sopenharmony_ci * 36062306a36Sopenharmony_ci * Make sure VCE is powerd up when we want to use it 36162306a36Sopenharmony_ci */ 36262306a36Sopenharmony_civoid amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 36562306a36Sopenharmony_ci bool set_clocks; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 36862306a36Sopenharmony_ci return; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci mutex_lock(&adev->vce.idle_mutex); 37162306a36Sopenharmony_ci set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work); 37262306a36Sopenharmony_ci if (set_clocks) { 37362306a36Sopenharmony_ci if (adev->pm.dpm_enabled) { 37462306a36Sopenharmony_ci amdgpu_dpm_enable_vce(adev, true); 37562306a36Sopenharmony_ci } else { 37662306a36Sopenharmony_ci amdgpu_asic_set_vce_clocks(adev, 53300, 40000); 37762306a36Sopenharmony_ci amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE, 37862306a36Sopenharmony_ci AMD_CG_STATE_UNGATE); 37962306a36Sopenharmony_ci amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE, 38062306a36Sopenharmony_ci AMD_PG_STATE_UNGATE); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci mutex_unlock(&adev->vce.idle_mutex); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/** 38862306a36Sopenharmony_ci * amdgpu_vce_ring_end_use - power VCE down 38962306a36Sopenharmony_ci * 39062306a36Sopenharmony_ci * @ring: amdgpu ring 39162306a36Sopenharmony_ci * 39262306a36Sopenharmony_ci * Schedule work to power VCE down again 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_civoid amdgpu_vce_ring_end_use(struct amdgpu_ring *ring) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci if (!amdgpu_sriov_vf(ring->adev)) 39762306a36Sopenharmony_ci schedule_delayed_work(&ring->adev->vce.idle_work, VCE_IDLE_TIMEOUT); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/** 40162306a36Sopenharmony_ci * amdgpu_vce_free_handles - free still open VCE handles 40262306a36Sopenharmony_ci * 40362306a36Sopenharmony_ci * @adev: amdgpu_device pointer 40462306a36Sopenharmony_ci * @filp: drm file pointer 40562306a36Sopenharmony_ci * 40662306a36Sopenharmony_ci * Close all VCE handles still open by this file pointer 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_civoid amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct amdgpu_ring *ring = &adev->vce.ring[0]; 41162306a36Sopenharmony_ci int i, r; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { 41462306a36Sopenharmony_ci uint32_t handle = atomic_read(&adev->vce.handles[i]); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (!handle || adev->vce.filp[i] != filp) 41762306a36Sopenharmony_ci continue; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci r = amdgpu_vce_get_destroy_msg(ring, handle, false, NULL); 42062306a36Sopenharmony_ci if (r) 42162306a36Sopenharmony_ci DRM_ERROR("Error destroying VCE handle (%d)!\n", r); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci adev->vce.filp[i] = NULL; 42462306a36Sopenharmony_ci atomic_set(&adev->vce.handles[i], 0); 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci/** 42962306a36Sopenharmony_ci * amdgpu_vce_get_create_msg - generate a VCE create msg 43062306a36Sopenharmony_ci * 43162306a36Sopenharmony_ci * @ring: ring we should submit the msg to 43262306a36Sopenharmony_ci * @handle: VCE session handle to use 43362306a36Sopenharmony_ci * @fence: optional fence to return 43462306a36Sopenharmony_ci * 43562306a36Sopenharmony_ci * Open up a stream for HW test 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_cistatic int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, 43862306a36Sopenharmony_ci struct dma_fence **fence) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci const unsigned int ib_size_dw = 1024; 44162306a36Sopenharmony_ci struct amdgpu_job *job; 44262306a36Sopenharmony_ci struct amdgpu_ib *ib; 44362306a36Sopenharmony_ci struct amdgpu_ib ib_msg; 44462306a36Sopenharmony_ci struct dma_fence *f = NULL; 44562306a36Sopenharmony_ci uint64_t addr; 44662306a36Sopenharmony_ci int i, r; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity, 44962306a36Sopenharmony_ci AMDGPU_FENCE_OWNER_UNDEFINED, 45062306a36Sopenharmony_ci ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT, 45162306a36Sopenharmony_ci &job); 45262306a36Sopenharmony_ci if (r) 45362306a36Sopenharmony_ci return r; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci memset(&ib_msg, 0, sizeof(ib_msg)); 45662306a36Sopenharmony_ci /* only one gpu page is needed, alloc +1 page to make addr aligned. */ 45762306a36Sopenharmony_ci r = amdgpu_ib_get(ring->adev, NULL, AMDGPU_GPU_PAGE_SIZE * 2, 45862306a36Sopenharmony_ci AMDGPU_IB_POOL_DIRECT, 45962306a36Sopenharmony_ci &ib_msg); 46062306a36Sopenharmony_ci if (r) 46162306a36Sopenharmony_ci goto err; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci ib = &job->ibs[0]; 46462306a36Sopenharmony_ci /* let addr point to page boundary */ 46562306a36Sopenharmony_ci addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg.gpu_addr); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* stitch together an VCE create msg */ 46862306a36Sopenharmony_ci ib->length_dw = 0; 46962306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x0000000c; /* len */ 47062306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */ 47162306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = handle; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if ((ring->adev->vce.fw_version >> 24) >= 52) 47462306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000040; /* len */ 47562306a36Sopenharmony_ci else 47662306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000030; /* len */ 47762306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x01000001; /* create cmd */ 47862306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 47962306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000042; 48062306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x0000000a; 48162306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000001; 48262306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000080; 48362306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000060; 48462306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000100; 48562306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000100; 48662306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x0000000c; 48762306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 48862306a36Sopenharmony_ci if ((ring->adev->vce.fw_version >> 24) >= 52) { 48962306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 49062306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 49162306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 49262306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000014; /* len */ 49662306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */ 49762306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = upper_32_bits(addr); 49862306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = addr; 49962306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000001; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci for (i = ib->length_dw; i < ib_size_dw; ++i) 50262306a36Sopenharmony_ci ib->ptr[i] = 0x0; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci r = amdgpu_job_submit_direct(job, ring, &f); 50562306a36Sopenharmony_ci amdgpu_ib_free(ring->adev, &ib_msg, f); 50662306a36Sopenharmony_ci if (r) 50762306a36Sopenharmony_ci goto err; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (fence) 51062306a36Sopenharmony_ci *fence = dma_fence_get(f); 51162306a36Sopenharmony_ci dma_fence_put(f); 51262306a36Sopenharmony_ci return 0; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cierr: 51562306a36Sopenharmony_ci amdgpu_job_free(job); 51662306a36Sopenharmony_ci return r; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/** 52062306a36Sopenharmony_ci * amdgpu_vce_get_destroy_msg - generate a VCE destroy msg 52162306a36Sopenharmony_ci * 52262306a36Sopenharmony_ci * @ring: ring we should submit the msg to 52362306a36Sopenharmony_ci * @handle: VCE session handle to use 52462306a36Sopenharmony_ci * @direct: direct or delayed pool 52562306a36Sopenharmony_ci * @fence: optional fence to return 52662306a36Sopenharmony_ci * 52762306a36Sopenharmony_ci * Close up a stream for HW test or if userspace failed to do so 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_cistatic int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, 53062306a36Sopenharmony_ci bool direct, struct dma_fence **fence) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci const unsigned int ib_size_dw = 1024; 53362306a36Sopenharmony_ci struct amdgpu_job *job; 53462306a36Sopenharmony_ci struct amdgpu_ib *ib; 53562306a36Sopenharmony_ci struct dma_fence *f = NULL; 53662306a36Sopenharmony_ci int i, r; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity, 53962306a36Sopenharmony_ci AMDGPU_FENCE_OWNER_UNDEFINED, 54062306a36Sopenharmony_ci ib_size_dw * 4, 54162306a36Sopenharmony_ci direct ? AMDGPU_IB_POOL_DIRECT : 54262306a36Sopenharmony_ci AMDGPU_IB_POOL_DELAYED, &job); 54362306a36Sopenharmony_ci if (r) 54462306a36Sopenharmony_ci return r; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ib = &job->ibs[0]; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* stitch together an VCE destroy msg */ 54962306a36Sopenharmony_ci ib->length_dw = 0; 55062306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x0000000c; /* len */ 55162306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */ 55262306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = handle; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000020; /* len */ 55562306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000002; /* task info */ 55662306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0xffffffff; /* next task info, set to 0xffffffff if no */ 55762306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000001; /* destroy session */ 55862306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 55962306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 56062306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0xffffffff; /* feedback is not needed, set to 0xffffffff and firmware will not output feedback */ 56162306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000000; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x00000008; /* len */ 56462306a36Sopenharmony_ci ib->ptr[ib->length_dw++] = 0x02000001; /* destroy cmd */ 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci for (i = ib->length_dw; i < ib_size_dw; ++i) 56762306a36Sopenharmony_ci ib->ptr[i] = 0x0; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (direct) 57062306a36Sopenharmony_ci r = amdgpu_job_submit_direct(job, ring, &f); 57162306a36Sopenharmony_ci else 57262306a36Sopenharmony_ci f = amdgpu_job_submit(job); 57362306a36Sopenharmony_ci if (r) 57462306a36Sopenharmony_ci goto err; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (fence) 57762306a36Sopenharmony_ci *fence = dma_fence_get(f); 57862306a36Sopenharmony_ci dma_fence_put(f); 57962306a36Sopenharmony_ci return 0; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cierr: 58262306a36Sopenharmony_ci amdgpu_job_free(job); 58362306a36Sopenharmony_ci return r; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci/** 58762306a36Sopenharmony_ci * amdgpu_vce_validate_bo - make sure not to cross 4GB boundary 58862306a36Sopenharmony_ci * 58962306a36Sopenharmony_ci * @p: cs parser 59062306a36Sopenharmony_ci * @ib: indirect buffer to use 59162306a36Sopenharmony_ci * @lo: address of lower dword 59262306a36Sopenharmony_ci * @hi: address of higher dword 59362306a36Sopenharmony_ci * @size: minimum size 59462306a36Sopenharmony_ci * @index: bs/fb index 59562306a36Sopenharmony_ci * 59662306a36Sopenharmony_ci * Make sure that no BO cross a 4GB boundary. 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_cistatic int amdgpu_vce_validate_bo(struct amdgpu_cs_parser *p, 59962306a36Sopenharmony_ci struct amdgpu_ib *ib, int lo, int hi, 60062306a36Sopenharmony_ci unsigned int size, int32_t index) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci int64_t offset = ((uint64_t)size) * ((int64_t)index); 60362306a36Sopenharmony_ci struct ttm_operation_ctx ctx = { false, false }; 60462306a36Sopenharmony_ci struct amdgpu_bo_va_mapping *mapping; 60562306a36Sopenharmony_ci unsigned int i, fpfn, lpfn; 60662306a36Sopenharmony_ci struct amdgpu_bo *bo; 60762306a36Sopenharmony_ci uint64_t addr; 60862306a36Sopenharmony_ci int r; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci addr = ((uint64_t)amdgpu_ib_get_value(ib, lo)) | 61162306a36Sopenharmony_ci ((uint64_t)amdgpu_ib_get_value(ib, hi)) << 32; 61262306a36Sopenharmony_ci if (index >= 0) { 61362306a36Sopenharmony_ci addr += offset; 61462306a36Sopenharmony_ci fpfn = PAGE_ALIGN(offset) >> PAGE_SHIFT; 61562306a36Sopenharmony_ci lpfn = 0x100000000ULL >> PAGE_SHIFT; 61662306a36Sopenharmony_ci } else { 61762306a36Sopenharmony_ci fpfn = 0; 61862306a36Sopenharmony_ci lpfn = (0x100000000ULL - PAGE_ALIGN(offset)) >> PAGE_SHIFT; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci r = amdgpu_cs_find_mapping(p, addr, &bo, &mapping); 62262306a36Sopenharmony_ci if (r) { 62362306a36Sopenharmony_ci DRM_ERROR("Can't find BO for addr 0x%010llx %d %d %d %d\n", 62462306a36Sopenharmony_ci addr, lo, hi, size, index); 62562306a36Sopenharmony_ci return r; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci for (i = 0; i < bo->placement.num_placement; ++i) { 62962306a36Sopenharmony_ci bo->placements[i].fpfn = max(bo->placements[i].fpfn, fpfn); 63062306a36Sopenharmony_ci bo->placements[i].lpfn = bo->placements[i].lpfn ? 63162306a36Sopenharmony_ci min(bo->placements[i].lpfn, lpfn) : lpfn; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci return ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci/** 63862306a36Sopenharmony_ci * amdgpu_vce_cs_reloc - command submission relocation 63962306a36Sopenharmony_ci * 64062306a36Sopenharmony_ci * @p: parser context 64162306a36Sopenharmony_ci * @ib: indirect buffer to use 64262306a36Sopenharmony_ci * @lo: address of lower dword 64362306a36Sopenharmony_ci * @hi: address of higher dword 64462306a36Sopenharmony_ci * @size: minimum size 64562306a36Sopenharmony_ci * @index: bs/fb index 64662306a36Sopenharmony_ci * 64762306a36Sopenharmony_ci * Patch relocation inside command stream with real buffer address 64862306a36Sopenharmony_ci */ 64962306a36Sopenharmony_cistatic int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib, 65062306a36Sopenharmony_ci int lo, int hi, unsigned int size, uint32_t index) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct amdgpu_bo_va_mapping *mapping; 65362306a36Sopenharmony_ci struct amdgpu_bo *bo; 65462306a36Sopenharmony_ci uint64_t addr; 65562306a36Sopenharmony_ci int r; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (index == 0xffffffff) 65862306a36Sopenharmony_ci index = 0; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci addr = ((uint64_t)amdgpu_ib_get_value(ib, lo)) | 66162306a36Sopenharmony_ci ((uint64_t)amdgpu_ib_get_value(ib, hi)) << 32; 66262306a36Sopenharmony_ci addr += ((uint64_t)size) * ((uint64_t)index); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci r = amdgpu_cs_find_mapping(p, addr, &bo, &mapping); 66562306a36Sopenharmony_ci if (r) { 66662306a36Sopenharmony_ci DRM_ERROR("Can't find BO for addr 0x%010llx %d %d %d %d\n", 66762306a36Sopenharmony_ci addr, lo, hi, size, index); 66862306a36Sopenharmony_ci return r; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if ((addr + (uint64_t)size) > 67262306a36Sopenharmony_ci (mapping->last + 1) * AMDGPU_GPU_PAGE_SIZE) { 67362306a36Sopenharmony_ci DRM_ERROR("BO too small for addr 0x%010llx %d %d\n", 67462306a36Sopenharmony_ci addr, lo, hi); 67562306a36Sopenharmony_ci return -EINVAL; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci addr -= mapping->start * AMDGPU_GPU_PAGE_SIZE; 67962306a36Sopenharmony_ci addr += amdgpu_bo_gpu_offset(bo); 68062306a36Sopenharmony_ci addr -= ((uint64_t)size) * ((uint64_t)index); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci amdgpu_ib_set_value(ib, lo, lower_32_bits(addr)); 68362306a36Sopenharmony_ci amdgpu_ib_set_value(ib, hi, upper_32_bits(addr)); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci return 0; 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci/** 68962306a36Sopenharmony_ci * amdgpu_vce_validate_handle - validate stream handle 69062306a36Sopenharmony_ci * 69162306a36Sopenharmony_ci * @p: parser context 69262306a36Sopenharmony_ci * @handle: handle to validate 69362306a36Sopenharmony_ci * @allocated: allocated a new handle? 69462306a36Sopenharmony_ci * 69562306a36Sopenharmony_ci * Validates the handle and return the found session index or -EINVAL 69662306a36Sopenharmony_ci * we don't have another free session index. 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_cistatic int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p, 69962306a36Sopenharmony_ci uint32_t handle, uint32_t *allocated) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci unsigned int i; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* validate the handle */ 70462306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { 70562306a36Sopenharmony_ci if (atomic_read(&p->adev->vce.handles[i]) == handle) { 70662306a36Sopenharmony_ci if (p->adev->vce.filp[i] != p->filp) { 70762306a36Sopenharmony_ci DRM_ERROR("VCE handle collision detected!\n"); 70862306a36Sopenharmony_ci return -EINVAL; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci return i; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* handle not found try to alloc a new one */ 71562306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { 71662306a36Sopenharmony_ci if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) { 71762306a36Sopenharmony_ci p->adev->vce.filp[i] = p->filp; 71862306a36Sopenharmony_ci p->adev->vce.img_size[i] = 0; 71962306a36Sopenharmony_ci *allocated |= 1 << i; 72062306a36Sopenharmony_ci return i; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci DRM_ERROR("No more free VCE handles!\n"); 72562306a36Sopenharmony_ci return -EINVAL; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci/** 72962306a36Sopenharmony_ci * amdgpu_vce_ring_parse_cs - parse and validate the command stream 73062306a36Sopenharmony_ci * 73162306a36Sopenharmony_ci * @p: parser context 73262306a36Sopenharmony_ci * @job: the job to parse 73362306a36Sopenharmony_ci * @ib: the IB to patch 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_ciint amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, 73662306a36Sopenharmony_ci struct amdgpu_job *job, 73762306a36Sopenharmony_ci struct amdgpu_ib *ib) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci unsigned int fb_idx = 0, bs_idx = 0; 74062306a36Sopenharmony_ci int session_idx = -1; 74162306a36Sopenharmony_ci uint32_t destroyed = 0; 74262306a36Sopenharmony_ci uint32_t created = 0; 74362306a36Sopenharmony_ci uint32_t allocated = 0; 74462306a36Sopenharmony_ci uint32_t tmp, handle = 0; 74562306a36Sopenharmony_ci uint32_t *size = &tmp; 74662306a36Sopenharmony_ci unsigned int idx; 74762306a36Sopenharmony_ci int i, r = 0; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci job->vm = NULL; 75062306a36Sopenharmony_ci ib->gpu_addr = amdgpu_sa_bo_gpu_addr(ib->sa_bo); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci for (idx = 0; idx < ib->length_dw;) { 75362306a36Sopenharmony_ci uint32_t len = amdgpu_ib_get_value(ib, idx); 75462306a36Sopenharmony_ci uint32_t cmd = amdgpu_ib_get_value(ib, idx + 1); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if ((len < 8) || (len & 3)) { 75762306a36Sopenharmony_ci DRM_ERROR("invalid VCE command length (%d)!\n", len); 75862306a36Sopenharmony_ci r = -EINVAL; 75962306a36Sopenharmony_ci goto out; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci switch (cmd) { 76362306a36Sopenharmony_ci case 0x00000002: /* task info */ 76462306a36Sopenharmony_ci fb_idx = amdgpu_ib_get_value(ib, idx + 6); 76562306a36Sopenharmony_ci bs_idx = amdgpu_ib_get_value(ib, idx + 7); 76662306a36Sopenharmony_ci break; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci case 0x03000001: /* encode */ 76962306a36Sopenharmony_ci r = amdgpu_vce_validate_bo(p, ib, idx + 10, idx + 9, 77062306a36Sopenharmony_ci 0, 0); 77162306a36Sopenharmony_ci if (r) 77262306a36Sopenharmony_ci goto out; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci r = amdgpu_vce_validate_bo(p, ib, idx + 12, idx + 11, 77562306a36Sopenharmony_ci 0, 0); 77662306a36Sopenharmony_ci if (r) 77762306a36Sopenharmony_ci goto out; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci case 0x05000001: /* context buffer */ 78162306a36Sopenharmony_ci r = amdgpu_vce_validate_bo(p, ib, idx + 3, idx + 2, 78262306a36Sopenharmony_ci 0, 0); 78362306a36Sopenharmony_ci if (r) 78462306a36Sopenharmony_ci goto out; 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci case 0x05000004: /* video bitstream buffer */ 78862306a36Sopenharmony_ci tmp = amdgpu_ib_get_value(ib, idx + 4); 78962306a36Sopenharmony_ci r = amdgpu_vce_validate_bo(p, ib, idx + 3, idx + 2, 79062306a36Sopenharmony_ci tmp, bs_idx); 79162306a36Sopenharmony_ci if (r) 79262306a36Sopenharmony_ci goto out; 79362306a36Sopenharmony_ci break; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci case 0x05000005: /* feedback buffer */ 79662306a36Sopenharmony_ci r = amdgpu_vce_validate_bo(p, ib, idx + 3, idx + 2, 79762306a36Sopenharmony_ci 4096, fb_idx); 79862306a36Sopenharmony_ci if (r) 79962306a36Sopenharmony_ci goto out; 80062306a36Sopenharmony_ci break; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci case 0x0500000d: /* MV buffer */ 80362306a36Sopenharmony_ci r = amdgpu_vce_validate_bo(p, ib, idx + 3, idx + 2, 80462306a36Sopenharmony_ci 0, 0); 80562306a36Sopenharmony_ci if (r) 80662306a36Sopenharmony_ci goto out; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci r = amdgpu_vce_validate_bo(p, ib, idx + 8, idx + 7, 80962306a36Sopenharmony_ci 0, 0); 81062306a36Sopenharmony_ci if (r) 81162306a36Sopenharmony_ci goto out; 81262306a36Sopenharmony_ci break; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci idx += len / 4; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci for (idx = 0; idx < ib->length_dw;) { 81962306a36Sopenharmony_ci uint32_t len = amdgpu_ib_get_value(ib, idx); 82062306a36Sopenharmony_ci uint32_t cmd = amdgpu_ib_get_value(ib, idx + 1); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci switch (cmd) { 82362306a36Sopenharmony_ci case 0x00000001: /* session */ 82462306a36Sopenharmony_ci handle = amdgpu_ib_get_value(ib, idx + 2); 82562306a36Sopenharmony_ci session_idx = amdgpu_vce_validate_handle(p, handle, 82662306a36Sopenharmony_ci &allocated); 82762306a36Sopenharmony_ci if (session_idx < 0) { 82862306a36Sopenharmony_ci r = session_idx; 82962306a36Sopenharmony_ci goto out; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci size = &p->adev->vce.img_size[session_idx]; 83262306a36Sopenharmony_ci break; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci case 0x00000002: /* task info */ 83562306a36Sopenharmony_ci fb_idx = amdgpu_ib_get_value(ib, idx + 6); 83662306a36Sopenharmony_ci bs_idx = amdgpu_ib_get_value(ib, idx + 7); 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci case 0x01000001: /* create */ 84062306a36Sopenharmony_ci created |= 1 << session_idx; 84162306a36Sopenharmony_ci if (destroyed & (1 << session_idx)) { 84262306a36Sopenharmony_ci destroyed &= ~(1 << session_idx); 84362306a36Sopenharmony_ci allocated |= 1 << session_idx; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci } else if (!(allocated & (1 << session_idx))) { 84662306a36Sopenharmony_ci DRM_ERROR("Handle already in use!\n"); 84762306a36Sopenharmony_ci r = -EINVAL; 84862306a36Sopenharmony_ci goto out; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci *size = amdgpu_ib_get_value(ib, idx + 8) * 85262306a36Sopenharmony_ci amdgpu_ib_get_value(ib, idx + 10) * 85362306a36Sopenharmony_ci 8 * 3 / 2; 85462306a36Sopenharmony_ci break; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci case 0x04000001: /* config extension */ 85762306a36Sopenharmony_ci case 0x04000002: /* pic control */ 85862306a36Sopenharmony_ci case 0x04000005: /* rate control */ 85962306a36Sopenharmony_ci case 0x04000007: /* motion estimation */ 86062306a36Sopenharmony_ci case 0x04000008: /* rdo */ 86162306a36Sopenharmony_ci case 0x04000009: /* vui */ 86262306a36Sopenharmony_ci case 0x05000002: /* auxiliary buffer */ 86362306a36Sopenharmony_ci case 0x05000009: /* clock table */ 86462306a36Sopenharmony_ci break; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci case 0x0500000c: /* hw config */ 86762306a36Sopenharmony_ci switch (p->adev->asic_type) { 86862306a36Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_CIK 86962306a36Sopenharmony_ci case CHIP_KAVERI: 87062306a36Sopenharmony_ci case CHIP_MULLINS: 87162306a36Sopenharmony_ci#endif 87262306a36Sopenharmony_ci case CHIP_CARRIZO: 87362306a36Sopenharmony_ci break; 87462306a36Sopenharmony_ci default: 87562306a36Sopenharmony_ci r = -EINVAL; 87662306a36Sopenharmony_ci goto out; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci break; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci case 0x03000001: /* encode */ 88162306a36Sopenharmony_ci r = amdgpu_vce_cs_reloc(p, ib, idx + 10, idx + 9, 88262306a36Sopenharmony_ci *size, 0); 88362306a36Sopenharmony_ci if (r) 88462306a36Sopenharmony_ci goto out; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci r = amdgpu_vce_cs_reloc(p, ib, idx + 12, idx + 11, 88762306a36Sopenharmony_ci *size / 3, 0); 88862306a36Sopenharmony_ci if (r) 88962306a36Sopenharmony_ci goto out; 89062306a36Sopenharmony_ci break; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci case 0x02000001: /* destroy */ 89362306a36Sopenharmony_ci destroyed |= 1 << session_idx; 89462306a36Sopenharmony_ci break; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci case 0x05000001: /* context buffer */ 89762306a36Sopenharmony_ci r = amdgpu_vce_cs_reloc(p, ib, idx + 3, idx + 2, 89862306a36Sopenharmony_ci *size * 2, 0); 89962306a36Sopenharmony_ci if (r) 90062306a36Sopenharmony_ci goto out; 90162306a36Sopenharmony_ci break; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci case 0x05000004: /* video bitstream buffer */ 90462306a36Sopenharmony_ci tmp = amdgpu_ib_get_value(ib, idx + 4); 90562306a36Sopenharmony_ci r = amdgpu_vce_cs_reloc(p, ib, idx + 3, idx + 2, 90662306a36Sopenharmony_ci tmp, bs_idx); 90762306a36Sopenharmony_ci if (r) 90862306a36Sopenharmony_ci goto out; 90962306a36Sopenharmony_ci break; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci case 0x05000005: /* feedback buffer */ 91262306a36Sopenharmony_ci r = amdgpu_vce_cs_reloc(p, ib, idx + 3, idx + 2, 91362306a36Sopenharmony_ci 4096, fb_idx); 91462306a36Sopenharmony_ci if (r) 91562306a36Sopenharmony_ci goto out; 91662306a36Sopenharmony_ci break; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci case 0x0500000d: /* MV buffer */ 91962306a36Sopenharmony_ci r = amdgpu_vce_cs_reloc(p, ib, idx + 3, 92062306a36Sopenharmony_ci idx + 2, *size, 0); 92162306a36Sopenharmony_ci if (r) 92262306a36Sopenharmony_ci goto out; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci r = amdgpu_vce_cs_reloc(p, ib, idx + 8, 92562306a36Sopenharmony_ci idx + 7, *size / 12, 0); 92662306a36Sopenharmony_ci if (r) 92762306a36Sopenharmony_ci goto out; 92862306a36Sopenharmony_ci break; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci default: 93162306a36Sopenharmony_ci DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); 93262306a36Sopenharmony_ci r = -EINVAL; 93362306a36Sopenharmony_ci goto out; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (session_idx == -1) { 93762306a36Sopenharmony_ci DRM_ERROR("no session command at start of IB\n"); 93862306a36Sopenharmony_ci r = -EINVAL; 93962306a36Sopenharmony_ci goto out; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci idx += len / 4; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (allocated & ~created) { 94662306a36Sopenharmony_ci DRM_ERROR("New session without create command!\n"); 94762306a36Sopenharmony_ci r = -ENOENT; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ciout: 95162306a36Sopenharmony_ci if (!r) { 95262306a36Sopenharmony_ci /* No error, free all destroyed handle slots */ 95362306a36Sopenharmony_ci tmp = destroyed; 95462306a36Sopenharmony_ci } else { 95562306a36Sopenharmony_ci /* Error during parsing, free all allocated handle slots */ 95662306a36Sopenharmony_ci tmp = allocated; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) 96062306a36Sopenharmony_ci if (tmp & (1 << i)) 96162306a36Sopenharmony_ci atomic_set(&p->adev->vce.handles[i], 0); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci return r; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci/** 96762306a36Sopenharmony_ci * amdgpu_vce_ring_parse_cs_vm - parse the command stream in VM mode 96862306a36Sopenharmony_ci * 96962306a36Sopenharmony_ci * @p: parser context 97062306a36Sopenharmony_ci * @job: the job to parse 97162306a36Sopenharmony_ci * @ib: the IB to patch 97262306a36Sopenharmony_ci */ 97362306a36Sopenharmony_ciint amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, 97462306a36Sopenharmony_ci struct amdgpu_job *job, 97562306a36Sopenharmony_ci struct amdgpu_ib *ib) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci int session_idx = -1; 97862306a36Sopenharmony_ci uint32_t destroyed = 0; 97962306a36Sopenharmony_ci uint32_t created = 0; 98062306a36Sopenharmony_ci uint32_t allocated = 0; 98162306a36Sopenharmony_ci uint32_t tmp, handle = 0; 98262306a36Sopenharmony_ci int i, r = 0, idx = 0; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci while (idx < ib->length_dw) { 98562306a36Sopenharmony_ci uint32_t len = amdgpu_ib_get_value(ib, idx); 98662306a36Sopenharmony_ci uint32_t cmd = amdgpu_ib_get_value(ib, idx + 1); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if ((len < 8) || (len & 3)) { 98962306a36Sopenharmony_ci DRM_ERROR("invalid VCE command length (%d)!\n", len); 99062306a36Sopenharmony_ci r = -EINVAL; 99162306a36Sopenharmony_ci goto out; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci switch (cmd) { 99562306a36Sopenharmony_ci case 0x00000001: /* session */ 99662306a36Sopenharmony_ci handle = amdgpu_ib_get_value(ib, idx + 2); 99762306a36Sopenharmony_ci session_idx = amdgpu_vce_validate_handle(p, handle, 99862306a36Sopenharmony_ci &allocated); 99962306a36Sopenharmony_ci if (session_idx < 0) { 100062306a36Sopenharmony_ci r = session_idx; 100162306a36Sopenharmony_ci goto out; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci break; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci case 0x01000001: /* create */ 100662306a36Sopenharmony_ci created |= 1 << session_idx; 100762306a36Sopenharmony_ci if (destroyed & (1 << session_idx)) { 100862306a36Sopenharmony_ci destroyed &= ~(1 << session_idx); 100962306a36Sopenharmony_ci allocated |= 1 << session_idx; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci } else if (!(allocated & (1 << session_idx))) { 101262306a36Sopenharmony_ci DRM_ERROR("Handle already in use!\n"); 101362306a36Sopenharmony_ci r = -EINVAL; 101462306a36Sopenharmony_ci goto out; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci break; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci case 0x02000001: /* destroy */ 102062306a36Sopenharmony_ci destroyed |= 1 << session_idx; 102162306a36Sopenharmony_ci break; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci default: 102462306a36Sopenharmony_ci break; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (session_idx == -1) { 102862306a36Sopenharmony_ci DRM_ERROR("no session command at start of IB\n"); 102962306a36Sopenharmony_ci r = -EINVAL; 103062306a36Sopenharmony_ci goto out; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci idx += len / 4; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci if (allocated & ~created) { 103762306a36Sopenharmony_ci DRM_ERROR("New session without create command!\n"); 103862306a36Sopenharmony_ci r = -ENOENT; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ciout: 104262306a36Sopenharmony_ci if (!r) { 104362306a36Sopenharmony_ci /* No error, free all destroyed handle slots */ 104462306a36Sopenharmony_ci tmp = destroyed; 104562306a36Sopenharmony_ci amdgpu_ib_free(p->adev, ib, NULL); 104662306a36Sopenharmony_ci } else { 104762306a36Sopenharmony_ci /* Error during parsing, free all allocated handle slots */ 104862306a36Sopenharmony_ci tmp = allocated; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) 105262306a36Sopenharmony_ci if (tmp & (1 << i)) 105362306a36Sopenharmony_ci atomic_set(&p->adev->vce.handles[i], 0); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci return r; 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci/** 105962306a36Sopenharmony_ci * amdgpu_vce_ring_emit_ib - execute indirect buffer 106062306a36Sopenharmony_ci * 106162306a36Sopenharmony_ci * @ring: engine to use 106262306a36Sopenharmony_ci * @job: job to retrieve vmid from 106362306a36Sopenharmony_ci * @ib: the IB to execute 106462306a36Sopenharmony_ci * @flags: unused 106562306a36Sopenharmony_ci * 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_civoid amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, 106862306a36Sopenharmony_ci struct amdgpu_job *job, 106962306a36Sopenharmony_ci struct amdgpu_ib *ib, 107062306a36Sopenharmony_ci uint32_t flags) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci amdgpu_ring_write(ring, VCE_CMD_IB); 107362306a36Sopenharmony_ci amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); 107462306a36Sopenharmony_ci amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); 107562306a36Sopenharmony_ci amdgpu_ring_write(ring, ib->length_dw); 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci/** 107962306a36Sopenharmony_ci * amdgpu_vce_ring_emit_fence - add a fence command to the ring 108062306a36Sopenharmony_ci * 108162306a36Sopenharmony_ci * @ring: engine to use 108262306a36Sopenharmony_ci * @addr: address 108362306a36Sopenharmony_ci * @seq: sequence number 108462306a36Sopenharmony_ci * @flags: fence related flags 108562306a36Sopenharmony_ci * 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_civoid amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, 108862306a36Sopenharmony_ci unsigned int flags) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci amdgpu_ring_write(ring, VCE_CMD_FENCE); 109362306a36Sopenharmony_ci amdgpu_ring_write(ring, addr); 109462306a36Sopenharmony_ci amdgpu_ring_write(ring, upper_32_bits(addr)); 109562306a36Sopenharmony_ci amdgpu_ring_write(ring, seq); 109662306a36Sopenharmony_ci amdgpu_ring_write(ring, VCE_CMD_TRAP); 109762306a36Sopenharmony_ci amdgpu_ring_write(ring, VCE_CMD_END); 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci/** 110162306a36Sopenharmony_ci * amdgpu_vce_ring_test_ring - test if VCE ring is working 110262306a36Sopenharmony_ci * 110362306a36Sopenharmony_ci * @ring: the engine to test on 110462306a36Sopenharmony_ci * 110562306a36Sopenharmony_ci */ 110662306a36Sopenharmony_ciint amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 110962306a36Sopenharmony_ci uint32_t rptr; 111062306a36Sopenharmony_ci unsigned int i; 111162306a36Sopenharmony_ci int r, timeout = adev->usec_timeout; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* skip ring test for sriov*/ 111462306a36Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 111562306a36Sopenharmony_ci return 0; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci r = amdgpu_ring_alloc(ring, 16); 111862306a36Sopenharmony_ci if (r) 111962306a36Sopenharmony_ci return r; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci rptr = amdgpu_ring_get_rptr(ring); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci amdgpu_ring_write(ring, VCE_CMD_END); 112462306a36Sopenharmony_ci amdgpu_ring_commit(ring); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci for (i = 0; i < timeout; i++) { 112762306a36Sopenharmony_ci if (amdgpu_ring_get_rptr(ring) != rptr) 112862306a36Sopenharmony_ci break; 112962306a36Sopenharmony_ci udelay(1); 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (i >= timeout) 113362306a36Sopenharmony_ci r = -ETIMEDOUT; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci return r; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci/** 113962306a36Sopenharmony_ci * amdgpu_vce_ring_test_ib - test if VCE IBs are working 114062306a36Sopenharmony_ci * 114162306a36Sopenharmony_ci * @ring: the engine to test on 114262306a36Sopenharmony_ci * @timeout: timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT 114362306a36Sopenharmony_ci * 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_ciint amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci struct dma_fence *fence = NULL; 114862306a36Sopenharmony_ci long r; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* skip vce ring1/2 ib test for now, since it's not reliable */ 115162306a36Sopenharmony_ci if (ring != &ring->adev->vce.ring[0]) 115262306a36Sopenharmony_ci return 0; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci r = amdgpu_vce_get_create_msg(ring, 1, NULL); 115562306a36Sopenharmony_ci if (r) 115662306a36Sopenharmony_ci goto error; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci r = amdgpu_vce_get_destroy_msg(ring, 1, true, &fence); 115962306a36Sopenharmony_ci if (r) 116062306a36Sopenharmony_ci goto error; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci r = dma_fence_wait_timeout(fence, false, timeout); 116362306a36Sopenharmony_ci if (r == 0) 116462306a36Sopenharmony_ci r = -ETIMEDOUT; 116562306a36Sopenharmony_ci else if (r > 0) 116662306a36Sopenharmony_ci r = 0; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_cierror: 116962306a36Sopenharmony_ci dma_fence_put(fence); 117062306a36Sopenharmony_ci return r; 117162306a36Sopenharmony_ci} 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_cienum amdgpu_ring_priority_level amdgpu_vce_get_ring_prio(int ring) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci switch (ring) { 117662306a36Sopenharmony_ci case 0: 117762306a36Sopenharmony_ci return AMDGPU_RING_PRIO_0; 117862306a36Sopenharmony_ci case 1: 117962306a36Sopenharmony_ci return AMDGPU_RING_PRIO_1; 118062306a36Sopenharmony_ci case 2: 118162306a36Sopenharmony_ci return AMDGPU_RING_PRIO_2; 118262306a36Sopenharmony_ci default: 118362306a36Sopenharmony_ci return AMDGPU_RING_PRIO_0; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci} 1186