18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2013 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * All Rights Reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the 78c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 88c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 98c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 108c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 118c2ecf20Sopenharmony_ci * the following conditions: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 148c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 158c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 168c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 178c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 188c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 198c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the 228c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 238c2ecf20Sopenharmony_ci * of the Software. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Authors: Christian König <christian.koenig@amd.com> 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/firmware.h> 298c2ecf20Sopenharmony_ci#include <linux/module.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <drm/drm.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "radeon.h" 348c2ecf20Sopenharmony_ci#include "radeon_asic.h" 358c2ecf20Sopenharmony_ci#include "sid.h" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* 1 second timeout */ 388c2ecf20Sopenharmony_ci#define VCE_IDLE_TIMEOUT_MS 1000 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* Firmware Names */ 418c2ecf20Sopenharmony_ci#define FIRMWARE_TAHITI "radeon/TAHITI_vce.bin" 428c2ecf20Sopenharmony_ci#define FIRMWARE_BONAIRE "radeon/BONAIRE_vce.bin" 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_TAHITI); 458c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FIRMWARE_BONAIRE); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void radeon_vce_idle_work_handler(struct work_struct *work); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/** 508c2ecf20Sopenharmony_ci * radeon_vce_init - allocate memory, load vce firmware 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * First step to get VCE online, allocate memory and load the firmware 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_ciint radeon_vce_init(struct radeon_device *rdev) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci static const char *fw_version = "[ATI LIB=VCEFW,"; 598c2ecf20Sopenharmony_ci static const char *fb_version = "[ATI LIB=VCEFWSTATS,"; 608c2ecf20Sopenharmony_ci unsigned long size; 618c2ecf20Sopenharmony_ci const char *fw_name, *c; 628c2ecf20Sopenharmony_ci uint8_t start, mid, end; 638c2ecf20Sopenharmony_ci int i, r; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci switch (rdev->family) { 688c2ecf20Sopenharmony_ci case CHIP_TAHITI: 698c2ecf20Sopenharmony_ci case CHIP_PITCAIRN: 708c2ecf20Sopenharmony_ci case CHIP_VERDE: 718c2ecf20Sopenharmony_ci case CHIP_ARUBA: 728c2ecf20Sopenharmony_ci fw_name = FIRMWARE_TAHITI; 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci case CHIP_BONAIRE: 768c2ecf20Sopenharmony_ci case CHIP_KAVERI: 778c2ecf20Sopenharmony_ci case CHIP_KABINI: 788c2ecf20Sopenharmony_ci case CHIP_HAWAII: 798c2ecf20Sopenharmony_ci case CHIP_MULLINS: 808c2ecf20Sopenharmony_ci fw_name = FIRMWARE_BONAIRE; 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci default: 848c2ecf20Sopenharmony_ci return -EINVAL; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev); 888c2ecf20Sopenharmony_ci if (r) { 898c2ecf20Sopenharmony_ci dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n", 908c2ecf20Sopenharmony_ci fw_name); 918c2ecf20Sopenharmony_ci return r; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* search for firmware version */ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci size = rdev->vce_fw->size - strlen(fw_version) - 9; 978c2ecf20Sopenharmony_ci c = rdev->vce_fw->data; 988c2ecf20Sopenharmony_ci for (;size > 0; --size, ++c) 998c2ecf20Sopenharmony_ci if (strncmp(c, fw_version, strlen(fw_version)) == 0) 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (size == 0) 1038c2ecf20Sopenharmony_ci return -EINVAL; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci c += strlen(fw_version); 1068c2ecf20Sopenharmony_ci if (sscanf(c, "%2hhd.%2hhd.%2hhd]", &start, &mid, &end) != 3) 1078c2ecf20Sopenharmony_ci return -EINVAL; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* search for feedback version */ 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci size = rdev->vce_fw->size - strlen(fb_version) - 3; 1128c2ecf20Sopenharmony_ci c = rdev->vce_fw->data; 1138c2ecf20Sopenharmony_ci for (;size > 0; --size, ++c) 1148c2ecf20Sopenharmony_ci if (strncmp(c, fb_version, strlen(fb_version)) == 0) 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (size == 0) 1188c2ecf20Sopenharmony_ci return -EINVAL; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci c += strlen(fb_version); 1218c2ecf20Sopenharmony_ci if (sscanf(c, "%2u]", &rdev->vce.fb_version) != 1) 1228c2ecf20Sopenharmony_ci return -EINVAL; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci DRM_INFO("Found VCE firmware/feedback version %hhd.%hhd.%hhd / %d!\n", 1258c2ecf20Sopenharmony_ci start, mid, end, rdev->vce.fb_version); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* we can only work with this fw version for now */ 1308c2ecf20Sopenharmony_ci if ((rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) && 1318c2ecf20Sopenharmony_ci (rdev->vce.fw_version != ((50 << 24) | (0 << 16) | (1 << 8))) && 1328c2ecf20Sopenharmony_ci (rdev->vce.fw_version != ((50 << 24) | (1 << 16) | (2 << 8)))) 1338c2ecf20Sopenharmony_ci return -EINVAL; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* allocate firmware, stack and heap BO */ 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (rdev->family < CHIP_BONAIRE) 1388c2ecf20Sopenharmony_ci size = vce_v1_0_bo_size(rdev); 1398c2ecf20Sopenharmony_ci else 1408c2ecf20Sopenharmony_ci size = vce_v2_0_bo_size(rdev); 1418c2ecf20Sopenharmony_ci r = radeon_bo_create(rdev, size, PAGE_SIZE, true, 1428c2ecf20Sopenharmony_ci RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL, 1438c2ecf20Sopenharmony_ci &rdev->vce.vcpu_bo); 1448c2ecf20Sopenharmony_ci if (r) { 1458c2ecf20Sopenharmony_ci dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r); 1468c2ecf20Sopenharmony_ci return r; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); 1508c2ecf20Sopenharmony_ci if (r) { 1518c2ecf20Sopenharmony_ci radeon_bo_unref(&rdev->vce.vcpu_bo); 1528c2ecf20Sopenharmony_ci dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); 1538c2ecf20Sopenharmony_ci return r; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, 1578c2ecf20Sopenharmony_ci &rdev->vce.gpu_addr); 1588c2ecf20Sopenharmony_ci radeon_bo_unreserve(rdev->vce.vcpu_bo); 1598c2ecf20Sopenharmony_ci if (r) { 1608c2ecf20Sopenharmony_ci radeon_bo_unref(&rdev->vce.vcpu_bo); 1618c2ecf20Sopenharmony_ci dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r); 1628c2ecf20Sopenharmony_ci return r; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 1668c2ecf20Sopenharmony_ci atomic_set(&rdev->vce.handles[i], 0); 1678c2ecf20Sopenharmony_ci rdev->vce.filp[i] = NULL; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * radeon_vce_fini - free memory 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 1778c2ecf20Sopenharmony_ci * 1788c2ecf20Sopenharmony_ci * Last step on VCE teardown, free firmware memory 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_civoid radeon_vce_fini(struct radeon_device *rdev) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci if (rdev->vce.vcpu_bo == NULL) 1838c2ecf20Sopenharmony_ci return; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci radeon_bo_unref(&rdev->vce.vcpu_bo); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci release_firmware(rdev->vce_fw); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/** 1918c2ecf20Sopenharmony_ci * radeon_vce_suspend - unpin VCE fw memory 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ciint radeon_vce_suspend(struct radeon_device *rdev) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci int i; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (rdev->vce.vcpu_bo == NULL) 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) 2048c2ecf20Sopenharmony_ci if (atomic_read(&rdev->vce.handles[i])) 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (i == RADEON_MAX_VCE_HANDLES) 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* TODO: suspending running encoding sessions isn't supported */ 2118c2ecf20Sopenharmony_ci return -EINVAL; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/** 2158c2ecf20Sopenharmony_ci * radeon_vce_resume - pin VCE fw memory 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 2188c2ecf20Sopenharmony_ci * 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ciint radeon_vce_resume(struct radeon_device *rdev) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci void *cpu_addr; 2238c2ecf20Sopenharmony_ci int r; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (rdev->vce.vcpu_bo == NULL) 2268c2ecf20Sopenharmony_ci return -EINVAL; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); 2298c2ecf20Sopenharmony_ci if (r) { 2308c2ecf20Sopenharmony_ci dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); 2318c2ecf20Sopenharmony_ci return r; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci r = radeon_bo_kmap(rdev->vce.vcpu_bo, &cpu_addr); 2358c2ecf20Sopenharmony_ci if (r) { 2368c2ecf20Sopenharmony_ci radeon_bo_unreserve(rdev->vce.vcpu_bo); 2378c2ecf20Sopenharmony_ci dev_err(rdev->dev, "(%d) VCE map failed\n", r); 2388c2ecf20Sopenharmony_ci return r; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci memset(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo)); 2428c2ecf20Sopenharmony_ci if (rdev->family < CHIP_BONAIRE) 2438c2ecf20Sopenharmony_ci r = vce_v1_0_load_fw(rdev, cpu_addr); 2448c2ecf20Sopenharmony_ci else 2458c2ecf20Sopenharmony_ci memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci radeon_bo_kunmap(rdev->vce.vcpu_bo); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci radeon_bo_unreserve(rdev->vce.vcpu_bo); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return r; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/** 2558c2ecf20Sopenharmony_ci * radeon_vce_idle_work_handler - power off VCE 2568c2ecf20Sopenharmony_ci * 2578c2ecf20Sopenharmony_ci * @work: pointer to work structure 2588c2ecf20Sopenharmony_ci * 2598c2ecf20Sopenharmony_ci * power of VCE when it's not used any more 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_cistatic void radeon_vce_idle_work_handler(struct work_struct *work) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct radeon_device *rdev = 2648c2ecf20Sopenharmony_ci container_of(work, struct radeon_device, vce.idle_work.work); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX) == 0) && 2678c2ecf20Sopenharmony_ci (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX) == 0)) { 2688c2ecf20Sopenharmony_ci if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 2698c2ecf20Sopenharmony_ci radeon_dpm_enable_vce(rdev, false); 2708c2ecf20Sopenharmony_ci } else { 2718c2ecf20Sopenharmony_ci radeon_set_vce_clocks(rdev, 0, 0); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci } else { 2748c2ecf20Sopenharmony_ci schedule_delayed_work(&rdev->vce.idle_work, 2758c2ecf20Sopenharmony_ci msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/** 2808c2ecf20Sopenharmony_ci * radeon_vce_note_usage - power up VCE 2818c2ecf20Sopenharmony_ci * 2828c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 2838c2ecf20Sopenharmony_ci * 2848c2ecf20Sopenharmony_ci * Make sure VCE is powerd up when we want to use it 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_civoid radeon_vce_note_usage(struct radeon_device *rdev) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci bool streams_changed = false; 2898c2ecf20Sopenharmony_ci bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work); 2908c2ecf20Sopenharmony_ci set_clocks &= schedule_delayed_work(&rdev->vce.idle_work, 2918c2ecf20Sopenharmony_ci msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 2948c2ecf20Sopenharmony_ci /* XXX figure out if the streams changed */ 2958c2ecf20Sopenharmony_ci streams_changed = false; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (set_clocks || streams_changed) { 2998c2ecf20Sopenharmony_ci if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 3008c2ecf20Sopenharmony_ci radeon_dpm_enable_vce(rdev, true); 3018c2ecf20Sopenharmony_ci } else { 3028c2ecf20Sopenharmony_ci radeon_set_vce_clocks(rdev, 53300, 40000); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/** 3088c2ecf20Sopenharmony_ci * radeon_vce_free_handles - free still open VCE handles 3098c2ecf20Sopenharmony_ci * 3108c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 3118c2ecf20Sopenharmony_ci * @filp: drm file pointer 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * Close all VCE handles still open by this file pointer 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_civoid radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci int i, r; 3188c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 3198c2ecf20Sopenharmony_ci uint32_t handle = atomic_read(&rdev->vce.handles[i]); 3208c2ecf20Sopenharmony_ci if (!handle || rdev->vce.filp[i] != filp) 3218c2ecf20Sopenharmony_ci continue; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci radeon_vce_note_usage(rdev); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, 3268c2ecf20Sopenharmony_ci handle, NULL); 3278c2ecf20Sopenharmony_ci if (r) 3288c2ecf20Sopenharmony_ci DRM_ERROR("Error destroying VCE handle (%d)!\n", r); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci rdev->vce.filp[i] = NULL; 3318c2ecf20Sopenharmony_ci atomic_set(&rdev->vce.handles[i], 0); 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci/** 3368c2ecf20Sopenharmony_ci * radeon_vce_get_create_msg - generate a VCE create msg 3378c2ecf20Sopenharmony_ci * 3388c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 3398c2ecf20Sopenharmony_ci * @ring: ring we should submit the msg to 3408c2ecf20Sopenharmony_ci * @handle: VCE session handle to use 3418c2ecf20Sopenharmony_ci * @fence: optional fence to return 3428c2ecf20Sopenharmony_ci * 3438c2ecf20Sopenharmony_ci * Open up a stream for HW test 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ciint radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, 3468c2ecf20Sopenharmony_ci uint32_t handle, struct radeon_fence **fence) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci const unsigned ib_size_dw = 1024; 3498c2ecf20Sopenharmony_ci struct radeon_ib ib; 3508c2ecf20Sopenharmony_ci uint64_t dummy; 3518c2ecf20Sopenharmony_ci int i, r; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); 3548c2ecf20Sopenharmony_ci if (r) { 3558c2ecf20Sopenharmony_ci DRM_ERROR("radeon: failed to get ib (%d).\n", r); 3568c2ecf20Sopenharmony_ci return r; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci dummy = ib.gpu_addr + 1024; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* stitch together an VCE create msg */ 3628c2ecf20Sopenharmony_ci ib.length_dw = 0; 3638c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ 3648c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ 3658c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(handle); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000030); /* len */ 3688c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x01000001); /* create cmd */ 3698c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000); 3708c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000042); 3718c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000a); 3728c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); 3738c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000080); 3748c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000060); 3758c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100); 3768c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100); 3778c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); 3788c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ 3818c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ 3828c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); 3838c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); 3848c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci for (i = ib.length_dw; i < ib_size_dw; ++i) 3878c2ecf20Sopenharmony_ci ib.ptr[i] = cpu_to_le32(0x0); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci r = radeon_ib_schedule(rdev, &ib, NULL, false); 3908c2ecf20Sopenharmony_ci if (r) 3918c2ecf20Sopenharmony_ci DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (fence) 3958c2ecf20Sopenharmony_ci *fence = radeon_fence_ref(ib.fence); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci radeon_ib_free(rdev, &ib); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return r; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci/** 4038c2ecf20Sopenharmony_ci * radeon_vce_get_destroy_msg - generate a VCE destroy msg 4048c2ecf20Sopenharmony_ci * 4058c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 4068c2ecf20Sopenharmony_ci * @ring: ring we should submit the msg to 4078c2ecf20Sopenharmony_ci * @handle: VCE session handle to use 4088c2ecf20Sopenharmony_ci * @fence: optional fence to return 4098c2ecf20Sopenharmony_ci * 4108c2ecf20Sopenharmony_ci * Close up a stream for HW test or if userspace failed to do so 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ciint radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, 4138c2ecf20Sopenharmony_ci uint32_t handle, struct radeon_fence **fence) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci const unsigned ib_size_dw = 1024; 4168c2ecf20Sopenharmony_ci struct radeon_ib ib; 4178c2ecf20Sopenharmony_ci uint64_t dummy; 4188c2ecf20Sopenharmony_ci int i, r; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); 4218c2ecf20Sopenharmony_ci if (r) { 4228c2ecf20Sopenharmony_ci DRM_ERROR("radeon: failed to get ib (%d).\n", r); 4238c2ecf20Sopenharmony_ci return r; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci dummy = ib.gpu_addr + 1024; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* stitch together an VCE destroy msg */ 4298c2ecf20Sopenharmony_ci ib.length_dw = 0; 4308c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ 4318c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ 4328c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(handle); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ 4358c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ 4368c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); 4378c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); 4388c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008); /* len */ 4418c2ecf20Sopenharmony_ci ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001); /* destroy cmd */ 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci for (i = ib.length_dw; i < ib_size_dw; ++i) 4448c2ecf20Sopenharmony_ci ib.ptr[i] = cpu_to_le32(0x0); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci r = radeon_ib_schedule(rdev, &ib, NULL, false); 4478c2ecf20Sopenharmony_ci if (r) { 4488c2ecf20Sopenharmony_ci DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (fence) 4528c2ecf20Sopenharmony_ci *fence = radeon_fence_ref(ib.fence); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci radeon_ib_free(rdev, &ib); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return r; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci/** 4608c2ecf20Sopenharmony_ci * radeon_vce_cs_reloc - command submission relocation 4618c2ecf20Sopenharmony_ci * 4628c2ecf20Sopenharmony_ci * @p: parser context 4638c2ecf20Sopenharmony_ci * @lo: address of lower dword 4648c2ecf20Sopenharmony_ci * @hi: address of higher dword 4658c2ecf20Sopenharmony_ci * @size: size of checker for relocation buffer 4668c2ecf20Sopenharmony_ci * 4678c2ecf20Sopenharmony_ci * Patch relocation inside command stream with real buffer address 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_ciint radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi, 4708c2ecf20Sopenharmony_ci unsigned size) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct radeon_cs_chunk *relocs_chunk; 4738c2ecf20Sopenharmony_ci struct radeon_bo_list *reloc; 4748c2ecf20Sopenharmony_ci uint64_t start, end, offset; 4758c2ecf20Sopenharmony_ci unsigned idx; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci relocs_chunk = p->chunk_relocs; 4788c2ecf20Sopenharmony_ci offset = radeon_get_ib_value(p, lo); 4798c2ecf20Sopenharmony_ci idx = radeon_get_ib_value(p, hi); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (idx >= relocs_chunk->length_dw) { 4828c2ecf20Sopenharmony_ci DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", 4838c2ecf20Sopenharmony_ci idx, relocs_chunk->length_dw); 4848c2ecf20Sopenharmony_ci return -EINVAL; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci reloc = &p->relocs[(idx / 4)]; 4888c2ecf20Sopenharmony_ci start = reloc->gpu_offset; 4898c2ecf20Sopenharmony_ci end = start + radeon_bo_size(reloc->robj); 4908c2ecf20Sopenharmony_ci start += offset; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci p->ib.ptr[lo] = start & 0xFFFFFFFF; 4938c2ecf20Sopenharmony_ci p->ib.ptr[hi] = start >> 32; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (end <= start) { 4968c2ecf20Sopenharmony_ci DRM_ERROR("invalid reloc offset %llX!\n", offset); 4978c2ecf20Sopenharmony_ci return -EINVAL; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci if ((end - start) < size) { 5008c2ecf20Sopenharmony_ci DRM_ERROR("buffer to small (%d / %d)!\n", 5018c2ecf20Sopenharmony_ci (unsigned)(end - start), size); 5028c2ecf20Sopenharmony_ci return -EINVAL; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci/** 5098c2ecf20Sopenharmony_ci * radeon_vce_validate_handle - validate stream handle 5108c2ecf20Sopenharmony_ci * 5118c2ecf20Sopenharmony_ci * @p: parser context 5128c2ecf20Sopenharmony_ci * @handle: handle to validate 5138c2ecf20Sopenharmony_ci * @allocated: allocated a new handle? 5148c2ecf20Sopenharmony_ci * 5158c2ecf20Sopenharmony_ci * Validates the handle and return the found session index or -EINVAL 5168c2ecf20Sopenharmony_ci * we we don't have another free session index. 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_cistatic int radeon_vce_validate_handle(struct radeon_cs_parser *p, 5198c2ecf20Sopenharmony_ci uint32_t handle, bool *allocated) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci unsigned i; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci *allocated = false; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* validate the handle */ 5268c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 5278c2ecf20Sopenharmony_ci if (atomic_read(&p->rdev->vce.handles[i]) == handle) { 5288c2ecf20Sopenharmony_ci if (p->rdev->vce.filp[i] != p->filp) { 5298c2ecf20Sopenharmony_ci DRM_ERROR("VCE handle collision detected!\n"); 5308c2ecf20Sopenharmony_ci return -EINVAL; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci return i; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci /* handle not found try to alloc a new one */ 5378c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 5388c2ecf20Sopenharmony_ci if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { 5398c2ecf20Sopenharmony_ci p->rdev->vce.filp[i] = p->filp; 5408c2ecf20Sopenharmony_ci p->rdev->vce.img_size[i] = 0; 5418c2ecf20Sopenharmony_ci *allocated = true; 5428c2ecf20Sopenharmony_ci return i; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci DRM_ERROR("No more free VCE handles!\n"); 5478c2ecf20Sopenharmony_ci return -EINVAL; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci/** 5518c2ecf20Sopenharmony_ci * radeon_vce_cs_parse - parse and validate the command stream 5528c2ecf20Sopenharmony_ci * 5538c2ecf20Sopenharmony_ci * @p: parser context 5548c2ecf20Sopenharmony_ci * 5558c2ecf20Sopenharmony_ci */ 5568c2ecf20Sopenharmony_ciint radeon_vce_cs_parse(struct radeon_cs_parser *p) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci int session_idx = -1; 5598c2ecf20Sopenharmony_ci bool destroyed = false, created = false, allocated = false; 5608c2ecf20Sopenharmony_ci uint32_t tmp, handle = 0; 5618c2ecf20Sopenharmony_ci uint32_t *size = &tmp; 5628c2ecf20Sopenharmony_ci int i, r = 0; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci while (p->idx < p->chunk_ib->length_dw) { 5658c2ecf20Sopenharmony_ci uint32_t len = radeon_get_ib_value(p, p->idx); 5668c2ecf20Sopenharmony_ci uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if ((len < 8) || (len & 3)) { 5698c2ecf20Sopenharmony_ci DRM_ERROR("invalid VCE command length (%d)!\n", len); 5708c2ecf20Sopenharmony_ci r = -EINVAL; 5718c2ecf20Sopenharmony_ci goto out; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (destroyed) { 5758c2ecf20Sopenharmony_ci DRM_ERROR("No other command allowed after destroy!\n"); 5768c2ecf20Sopenharmony_ci r = -EINVAL; 5778c2ecf20Sopenharmony_ci goto out; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci switch (cmd) { 5818c2ecf20Sopenharmony_ci case 0x00000001: // session 5828c2ecf20Sopenharmony_ci handle = radeon_get_ib_value(p, p->idx + 2); 5838c2ecf20Sopenharmony_ci session_idx = radeon_vce_validate_handle(p, handle, 5848c2ecf20Sopenharmony_ci &allocated); 5858c2ecf20Sopenharmony_ci if (session_idx < 0) 5868c2ecf20Sopenharmony_ci return session_idx; 5878c2ecf20Sopenharmony_ci size = &p->rdev->vce.img_size[session_idx]; 5888c2ecf20Sopenharmony_ci break; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci case 0x00000002: // task info 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci case 0x01000001: // create 5948c2ecf20Sopenharmony_ci created = true; 5958c2ecf20Sopenharmony_ci if (!allocated) { 5968c2ecf20Sopenharmony_ci DRM_ERROR("Handle already in use!\n"); 5978c2ecf20Sopenharmony_ci r = -EINVAL; 5988c2ecf20Sopenharmony_ci goto out; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci *size = radeon_get_ib_value(p, p->idx + 8) * 6028c2ecf20Sopenharmony_ci radeon_get_ib_value(p, p->idx + 10) * 6038c2ecf20Sopenharmony_ci 8 * 3 / 2; 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci case 0x04000001: // config extension 6078c2ecf20Sopenharmony_ci case 0x04000002: // pic control 6088c2ecf20Sopenharmony_ci case 0x04000005: // rate control 6098c2ecf20Sopenharmony_ci case 0x04000007: // motion estimation 6108c2ecf20Sopenharmony_ci case 0x04000008: // rdo 6118c2ecf20Sopenharmony_ci case 0x04000009: // vui 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci case 0x03000001: // encode 6158c2ecf20Sopenharmony_ci r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9, 6168c2ecf20Sopenharmony_ci *size); 6178c2ecf20Sopenharmony_ci if (r) 6188c2ecf20Sopenharmony_ci goto out; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11, 6218c2ecf20Sopenharmony_ci *size / 3); 6228c2ecf20Sopenharmony_ci if (r) 6238c2ecf20Sopenharmony_ci goto out; 6248c2ecf20Sopenharmony_ci break; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci case 0x02000001: // destroy 6278c2ecf20Sopenharmony_ci destroyed = true; 6288c2ecf20Sopenharmony_ci break; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci case 0x05000001: // context buffer 6318c2ecf20Sopenharmony_ci r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 6328c2ecf20Sopenharmony_ci *size * 2); 6338c2ecf20Sopenharmony_ci if (r) 6348c2ecf20Sopenharmony_ci goto out; 6358c2ecf20Sopenharmony_ci break; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci case 0x05000004: // video bitstream buffer 6388c2ecf20Sopenharmony_ci tmp = radeon_get_ib_value(p, p->idx + 4); 6398c2ecf20Sopenharmony_ci r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 6408c2ecf20Sopenharmony_ci tmp); 6418c2ecf20Sopenharmony_ci if (r) 6428c2ecf20Sopenharmony_ci goto out; 6438c2ecf20Sopenharmony_ci break; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci case 0x05000005: // feedback buffer 6468c2ecf20Sopenharmony_ci r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 6478c2ecf20Sopenharmony_ci 4096); 6488c2ecf20Sopenharmony_ci if (r) 6498c2ecf20Sopenharmony_ci goto out; 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci default: 6538c2ecf20Sopenharmony_ci DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); 6548c2ecf20Sopenharmony_ci r = -EINVAL; 6558c2ecf20Sopenharmony_ci goto out; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (session_idx == -1) { 6598c2ecf20Sopenharmony_ci DRM_ERROR("no session command at start of IB\n"); 6608c2ecf20Sopenharmony_ci r = -EINVAL; 6618c2ecf20Sopenharmony_ci goto out; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci p->idx += len / 4; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (allocated && !created) { 6688c2ecf20Sopenharmony_ci DRM_ERROR("New session without create command!\n"); 6698c2ecf20Sopenharmony_ci r = -ENOENT; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ciout: 6738c2ecf20Sopenharmony_ci if ((!r && destroyed) || (r && allocated)) { 6748c2ecf20Sopenharmony_ci /* 6758c2ecf20Sopenharmony_ci * IB contains a destroy msg or we have allocated an 6768c2ecf20Sopenharmony_ci * handle and got an error, anyway free the handle 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) 6798c2ecf20Sopenharmony_ci atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0); 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci return r; 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci/** 6868c2ecf20Sopenharmony_ci * radeon_vce_semaphore_emit - emit a semaphore command 6878c2ecf20Sopenharmony_ci * 6888c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 6898c2ecf20Sopenharmony_ci * @ring: engine to use 6908c2ecf20Sopenharmony_ci * @semaphore: address of semaphore 6918c2ecf20Sopenharmony_ci * @emit_wait: true=emit wait, false=emit signal 6928c2ecf20Sopenharmony_ci * 6938c2ecf20Sopenharmony_ci */ 6948c2ecf20Sopenharmony_cibool radeon_vce_semaphore_emit(struct radeon_device *rdev, 6958c2ecf20Sopenharmony_ci struct radeon_ring *ring, 6968c2ecf20Sopenharmony_ci struct radeon_semaphore *semaphore, 6978c2ecf20Sopenharmony_ci bool emit_wait) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci uint64_t addr = semaphore->gpu_addr; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(VCE_CMD_SEMAPHORE)); 7028c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32((addr >> 3) & 0x000FFFFF)); 7038c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32((addr >> 23) & 0x000FFFFF)); 7048c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(0x01003000 | (emit_wait ? 1 : 0))); 7058c2ecf20Sopenharmony_ci if (!emit_wait) 7068c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci return true; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci/** 7128c2ecf20Sopenharmony_ci * radeon_vce_ib_execute - execute indirect buffer 7138c2ecf20Sopenharmony_ci * 7148c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 7158c2ecf20Sopenharmony_ci * @ib: the IB to execute 7168c2ecf20Sopenharmony_ci * 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_civoid radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[ib->ring]; 7218c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(VCE_CMD_IB)); 7228c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(ib->gpu_addr)); 7238c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(upper_32_bits(ib->gpu_addr))); 7248c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(ib->length_dw)); 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci/** 7288c2ecf20Sopenharmony_ci * radeon_vce_fence_emit - add a fence command to the ring 7298c2ecf20Sopenharmony_ci * 7308c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 7318c2ecf20Sopenharmony_ci * @fence: the fence 7328c2ecf20Sopenharmony_ci * 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_civoid radeon_vce_fence_emit(struct radeon_device *rdev, 7358c2ecf20Sopenharmony_ci struct radeon_fence *fence) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[fence->ring]; 7388c2ecf20Sopenharmony_ci uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(VCE_CMD_FENCE)); 7418c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(addr)); 7428c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(upper_32_bits(addr))); 7438c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(fence->seq)); 7448c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(VCE_CMD_TRAP)); 7458c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci/** 7498c2ecf20Sopenharmony_ci * radeon_vce_ring_test - test if VCE ring is working 7508c2ecf20Sopenharmony_ci * 7518c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 7528c2ecf20Sopenharmony_ci * @ring: the engine to test on 7538c2ecf20Sopenharmony_ci * 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ciint radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci uint32_t rptr = vce_v1_0_get_rptr(rdev, ring); 7588c2ecf20Sopenharmony_ci unsigned i; 7598c2ecf20Sopenharmony_ci int r; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci r = radeon_ring_lock(rdev, ring, 16); 7628c2ecf20Sopenharmony_ci if (r) { 7638c2ecf20Sopenharmony_ci DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n", 7648c2ecf20Sopenharmony_ci ring->idx, r); 7658c2ecf20Sopenharmony_ci return r; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); 7688c2ecf20Sopenharmony_ci radeon_ring_unlock_commit(rdev, ring, false); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci for (i = 0; i < rdev->usec_timeout; i++) { 7718c2ecf20Sopenharmony_ci if (vce_v1_0_get_rptr(rdev, ring) != rptr) 7728c2ecf20Sopenharmony_ci break; 7738c2ecf20Sopenharmony_ci udelay(1); 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (i < rdev->usec_timeout) { 7778c2ecf20Sopenharmony_ci DRM_INFO("ring test on %d succeeded in %d usecs\n", 7788c2ecf20Sopenharmony_ci ring->idx, i); 7798c2ecf20Sopenharmony_ci } else { 7808c2ecf20Sopenharmony_ci DRM_ERROR("radeon: ring %d test failed\n", 7818c2ecf20Sopenharmony_ci ring->idx); 7828c2ecf20Sopenharmony_ci r = -ETIMEDOUT; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci return r; 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci/** 7898c2ecf20Sopenharmony_ci * radeon_vce_ib_test - test if VCE IBs are working 7908c2ecf20Sopenharmony_ci * 7918c2ecf20Sopenharmony_ci * @rdev: radeon_device pointer 7928c2ecf20Sopenharmony_ci * @ring: the engine to test on 7938c2ecf20Sopenharmony_ci * 7948c2ecf20Sopenharmony_ci */ 7958c2ecf20Sopenharmony_ciint radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci struct radeon_fence *fence = NULL; 7988c2ecf20Sopenharmony_ci int r; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL); 8018c2ecf20Sopenharmony_ci if (r) { 8028c2ecf20Sopenharmony_ci DRM_ERROR("radeon: failed to get create msg (%d).\n", r); 8038c2ecf20Sopenharmony_ci goto error; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence); 8078c2ecf20Sopenharmony_ci if (r) { 8088c2ecf20Sopenharmony_ci DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); 8098c2ecf20Sopenharmony_ci goto error; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci r = radeon_fence_wait_timeout(fence, false, usecs_to_jiffies( 8138c2ecf20Sopenharmony_ci RADEON_USEC_IB_TEST_TIMEOUT)); 8148c2ecf20Sopenharmony_ci if (r < 0) { 8158c2ecf20Sopenharmony_ci DRM_ERROR("radeon: fence wait failed (%d).\n", r); 8168c2ecf20Sopenharmony_ci } else if (r == 0) { 8178c2ecf20Sopenharmony_ci DRM_ERROR("radeon: fence wait timed out.\n"); 8188c2ecf20Sopenharmony_ci r = -ETIMEDOUT; 8198c2ecf20Sopenharmony_ci } else { 8208c2ecf20Sopenharmony_ci DRM_INFO("ib test on ring %d succeeded\n", ring->idx); 8218c2ecf20Sopenharmony_ci r = 0; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_cierror: 8248c2ecf20Sopenharmony_ci radeon_fence_unref(&fence); 8258c2ecf20Sopenharmony_ci return r; 8268c2ecf20Sopenharmony_ci} 827