1d93f7937SChristian König /* 2d93f7937SChristian König * Copyright 2013 Advanced Micro Devices, Inc. 3d93f7937SChristian König * All Rights Reserved. 4d93f7937SChristian König * 5d93f7937SChristian König * Permission is hereby granted, free of charge, to any person obtaining a 6d93f7937SChristian König * copy of this software and associated documentation files (the 7d93f7937SChristian König * "Software"), to deal in the Software without restriction, including 8d93f7937SChristian König * without limitation the rights to use, copy, modify, merge, publish, 9d93f7937SChristian König * distribute, sub license, and/or sell copies of the Software, and to 10d93f7937SChristian König * permit persons to whom the Software is furnished to do so, subject to 11d93f7937SChristian König * the following conditions: 12d93f7937SChristian König * 13d93f7937SChristian König * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14d93f7937SChristian König * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15d93f7937SChristian König * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16d93f7937SChristian König * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17d93f7937SChristian König * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18d93f7937SChristian König * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19d93f7937SChristian König * USE OR OTHER DEALINGS IN THE SOFTWARE. 20d93f7937SChristian König * 21d93f7937SChristian König * The above copyright notice and this permission notice (including the 22d93f7937SChristian König * next paragraph) shall be included in all copies or substantial portions 23d93f7937SChristian König * of the Software. 24d93f7937SChristian König * 25d93f7937SChristian König * Authors: Christian König <christian.koenig@amd.com> 26d93f7937SChristian König */ 27d93f7937SChristian König 28d93f7937SChristian König #include <linux/firmware.h> 29d93f7937SChristian König #include <linux/module.h> 30d93f7937SChristian König #include <drm/drmP.h> 31d93f7937SChristian König #include <drm/drm.h> 32d93f7937SChristian König 33d93f7937SChristian König #include "radeon.h" 34d93f7937SChristian König #include "radeon_asic.h" 35d93f7937SChristian König #include "sid.h" 36d93f7937SChristian König 3703afe6f6SAlex Deucher /* 1 second timeout */ 3803afe6f6SAlex Deucher #define VCE_IDLE_TIMEOUT_MS 1000 3903afe6f6SAlex Deucher 40d93f7937SChristian König /* Firmware Names */ 41a918efabSChristian König #define FIRMWARE_TAHITI "radeon/TAHITI_vce.bin" 42d93f7937SChristian König #define FIRMWARE_BONAIRE "radeon/BONAIRE_vce.bin" 43d93f7937SChristian König 44a918efabSChristian König MODULE_FIRMWARE(FIRMWARE_TAHITI); 45d93f7937SChristian König MODULE_FIRMWARE(FIRMWARE_BONAIRE); 46d93f7937SChristian König 4703afe6f6SAlex Deucher static void radeon_vce_idle_work_handler(struct work_struct *work); 4803afe6f6SAlex Deucher 49d93f7937SChristian König /** 50d93f7937SChristian König * radeon_vce_init - allocate memory, load vce firmware 51d93f7937SChristian König * 52d93f7937SChristian König * @rdev: radeon_device pointer 53d93f7937SChristian König * 54d93f7937SChristian König * First step to get VCE online, allocate memory and load the firmware 55d93f7937SChristian König */ 56d93f7937SChristian König int radeon_vce_init(struct radeon_device *rdev) 57d93f7937SChristian König { 5898ccc291SChristian König static const char *fw_version = "[ATI LIB=VCEFW,"; 5998ccc291SChristian König static const char *fb_version = "[ATI LIB=VCEFWSTATS,"; 6098ccc291SChristian König unsigned long size; 6198ccc291SChristian König const char *fw_name, *c; 6298ccc291SChristian König uint8_t start, mid, end; 63d93f7937SChristian König int i, r; 64d93f7937SChristian König 6503afe6f6SAlex Deucher INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler); 6603afe6f6SAlex Deucher 67d93f7937SChristian König switch (rdev->family) { 68a918efabSChristian König case CHIP_TAHITI: 69a918efabSChristian König case CHIP_PITCAIRN: 70a918efabSChristian König case CHIP_VERDE: 71a918efabSChristian König case CHIP_OLAND: 72a918efabSChristian König case CHIP_ARUBA: 73a918efabSChristian König fw_name = FIRMWARE_TAHITI; 74a918efabSChristian König break; 75a918efabSChristian König 76d93f7937SChristian König case CHIP_BONAIRE: 77d93f7937SChristian König case CHIP_KAVERI: 78d93f7937SChristian König case CHIP_KABINI: 79d71c48f6SAlex Deucher case CHIP_HAWAII: 80428bedddSLeo Liu case CHIP_MULLINS: 81d93f7937SChristian König fw_name = FIRMWARE_BONAIRE; 82d93f7937SChristian König break; 83d93f7937SChristian König 84d93f7937SChristian König default: 85d93f7937SChristian König return -EINVAL; 86d93f7937SChristian König } 87d93f7937SChristian König 88d93f7937SChristian König r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev); 89d93f7937SChristian König if (r) { 90d93f7937SChristian König dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n", 91d93f7937SChristian König fw_name); 92d93f7937SChristian König return r; 93d93f7937SChristian König } 94d93f7937SChristian König 9598ccc291SChristian König /* search for firmware version */ 9698ccc291SChristian König 9798ccc291SChristian König size = rdev->vce_fw->size - strlen(fw_version) - 9; 9898ccc291SChristian König c = rdev->vce_fw->data; 9998ccc291SChristian König for (;size > 0; --size, ++c) 10098ccc291SChristian König if (strncmp(c, fw_version, strlen(fw_version)) == 0) 10198ccc291SChristian König break; 10298ccc291SChristian König 10398ccc291SChristian König if (size == 0) 10498ccc291SChristian König return -EINVAL; 10598ccc291SChristian König 10698ccc291SChristian König c += strlen(fw_version); 10798ccc291SChristian König if (sscanf(c, "%2hhd.%2hhd.%2hhd]", &start, &mid, &end) != 3) 10898ccc291SChristian König return -EINVAL; 10998ccc291SChristian König 11098ccc291SChristian König /* search for feedback version */ 11198ccc291SChristian König 11298ccc291SChristian König size = rdev->vce_fw->size - strlen(fb_version) - 3; 11398ccc291SChristian König c = rdev->vce_fw->data; 11498ccc291SChristian König for (;size > 0; --size, ++c) 11598ccc291SChristian König if (strncmp(c, fb_version, strlen(fb_version)) == 0) 11698ccc291SChristian König break; 11798ccc291SChristian König 11898ccc291SChristian König if (size == 0) 11998ccc291SChristian König return -EINVAL; 12098ccc291SChristian König 12198ccc291SChristian König c += strlen(fb_version); 12298ccc291SChristian König if (sscanf(c, "%2u]", &rdev->vce.fb_version) != 1) 12398ccc291SChristian König return -EINVAL; 12498ccc291SChristian König 12598ccc291SChristian König DRM_INFO("Found VCE firmware/feedback version %hhd.%hhd.%hhd / %d!\n", 12698ccc291SChristian König start, mid, end, rdev->vce.fb_version); 12798ccc291SChristian König 12898ccc291SChristian König rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8); 12998ccc291SChristian König 13098ccc291SChristian König /* we can only work with this fw version for now */ 131c11d75c8SChristian König if ((rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) && 132c11d75c8SChristian König (rdev->vce.fw_version != ((50 << 24) | (0 << 16) | (1 << 8))) && 133c11d75c8SChristian König (rdev->vce.fw_version != ((50 << 24) | (1 << 16) | (2 << 8)))) 13498ccc291SChristian König return -EINVAL; 13598ccc291SChristian König 136b03b4e4bSChristian König /* allocate firmware, stack and heap BO */ 13798ccc291SChristian König 138a918efabSChristian König if (rdev->family < CHIP_BONAIRE) 139a918efabSChristian König size = vce_v1_0_bo_size(rdev); 140a918efabSChristian König else 141fa0cf2f2SChristian König size = vce_v2_0_bo_size(rdev); 14298ccc291SChristian König r = radeon_bo_create(rdev, size, PAGE_SIZE, true, 143831b6966SMaarten Lankhorst RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL, 144831b6966SMaarten Lankhorst &rdev->vce.vcpu_bo); 145d93f7937SChristian König if (r) { 146d93f7937SChristian König dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r); 147d93f7937SChristian König return r; 148d93f7937SChristian König } 149d93f7937SChristian König 150b03b4e4bSChristian König r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); 151b03b4e4bSChristian König if (r) { 152b03b4e4bSChristian König radeon_bo_unref(&rdev->vce.vcpu_bo); 153b03b4e4bSChristian König dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); 154d93f7937SChristian König return r; 155b03b4e4bSChristian König } 156d93f7937SChristian König 157b03b4e4bSChristian König r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, 158b03b4e4bSChristian König &rdev->vce.gpu_addr); 159b03b4e4bSChristian König radeon_bo_unreserve(rdev->vce.vcpu_bo); 160b03b4e4bSChristian König if (r) { 161b03b4e4bSChristian König radeon_bo_unref(&rdev->vce.vcpu_bo); 162b03b4e4bSChristian König dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r); 163d93f7937SChristian König return r; 164b03b4e4bSChristian König } 165d93f7937SChristian König 166d93f7937SChristian König for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 167d93f7937SChristian König atomic_set(&rdev->vce.handles[i], 0); 168d93f7937SChristian König rdev->vce.filp[i] = NULL; 169d93f7937SChristian König } 170d93f7937SChristian König 171d93f7937SChristian König return 0; 172d93f7937SChristian König } 173d93f7937SChristian König 174d93f7937SChristian König /** 175d93f7937SChristian König * radeon_vce_fini - free memory 176d93f7937SChristian König * 177d93f7937SChristian König * @rdev: radeon_device pointer 178d93f7937SChristian König * 179d93f7937SChristian König * Last step on VCE teardown, free firmware memory 180d93f7937SChristian König */ 181d93f7937SChristian König void radeon_vce_fini(struct radeon_device *rdev) 182d93f7937SChristian König { 183b03b4e4bSChristian König if (rdev->vce.vcpu_bo == NULL) 184b03b4e4bSChristian König return; 185b03b4e4bSChristian König 186d93f7937SChristian König radeon_bo_unref(&rdev->vce.vcpu_bo); 187b03b4e4bSChristian König 188b03b4e4bSChristian König release_firmware(rdev->vce_fw); 189d93f7937SChristian König } 190d93f7937SChristian König 191d93f7937SChristian König /** 192d93f7937SChristian König * radeon_vce_suspend - unpin VCE fw memory 193d93f7937SChristian König * 194d93f7937SChristian König * @rdev: radeon_device pointer 195d93f7937SChristian König * 196d93f7937SChristian König */ 197d93f7937SChristian König int radeon_vce_suspend(struct radeon_device *rdev) 198d93f7937SChristian König { 199b03b4e4bSChristian König int i; 200d93f7937SChristian König 201d93f7937SChristian König if (rdev->vce.vcpu_bo == NULL) 202d93f7937SChristian König return 0; 203d93f7937SChristian König 204b03b4e4bSChristian König for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) 205b03b4e4bSChristian König if (atomic_read(&rdev->vce.handles[i])) 206b03b4e4bSChristian König break; 207b03b4e4bSChristian König 208b03b4e4bSChristian König if (i == RADEON_MAX_VCE_HANDLES) 209b03b4e4bSChristian König return 0; 210b03b4e4bSChristian König 211b03b4e4bSChristian König /* TODO: suspending running encoding sessions isn't supported */ 212b03b4e4bSChristian König return -EINVAL; 213d93f7937SChristian König } 214d93f7937SChristian König 215d93f7937SChristian König /** 216d93f7937SChristian König * radeon_vce_resume - pin VCE fw memory 217d93f7937SChristian König * 218d93f7937SChristian König * @rdev: radeon_device pointer 219d93f7937SChristian König * 220d93f7937SChristian König */ 221d93f7937SChristian König int radeon_vce_resume(struct radeon_device *rdev) 222d93f7937SChristian König { 223b03b4e4bSChristian König void *cpu_addr; 224d93f7937SChristian König int r; 225d93f7937SChristian König 226d93f7937SChristian König if (rdev->vce.vcpu_bo == NULL) 227d93f7937SChristian König return -EINVAL; 228d93f7937SChristian König 229d93f7937SChristian König r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); 230d93f7937SChristian König if (r) { 231d93f7937SChristian König dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); 232d93f7937SChristian König return r; 233d93f7937SChristian König } 234d93f7937SChristian König 235b03b4e4bSChristian König r = radeon_bo_kmap(rdev->vce.vcpu_bo, &cpu_addr); 236d93f7937SChristian König if (r) { 237d93f7937SChristian König radeon_bo_unreserve(rdev->vce.vcpu_bo); 238d93f7937SChristian König dev_err(rdev->dev, "(%d) VCE map failed\n", r); 239d93f7937SChristian König return r; 240d93f7937SChristian König } 241d93f7937SChristian König 242a918efabSChristian König memset(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo)); 243a918efabSChristian König if (rdev->family < CHIP_BONAIRE) 244a918efabSChristian König r = vce_v1_0_load_fw(rdev, cpu_addr); 245a918efabSChristian König else 246b03b4e4bSChristian König memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size); 247b03b4e4bSChristian König 248b03b4e4bSChristian König radeon_bo_kunmap(rdev->vce.vcpu_bo); 249b03b4e4bSChristian König 250d93f7937SChristian König radeon_bo_unreserve(rdev->vce.vcpu_bo); 251d93f7937SChristian König 252a918efabSChristian König return r; 253d93f7937SChristian König } 254d93f7937SChristian König 255d93f7937SChristian König /** 25603afe6f6SAlex Deucher * radeon_vce_idle_work_handler - power off VCE 25703afe6f6SAlex Deucher * 25803afe6f6SAlex Deucher * @work: pointer to work structure 25903afe6f6SAlex Deucher * 26003afe6f6SAlex Deucher * power of VCE when it's not used any more 26103afe6f6SAlex Deucher */ 26203afe6f6SAlex Deucher static void radeon_vce_idle_work_handler(struct work_struct *work) 26303afe6f6SAlex Deucher { 26403afe6f6SAlex Deucher struct radeon_device *rdev = 26503afe6f6SAlex Deucher container_of(work, struct radeon_device, vce.idle_work.work); 26603afe6f6SAlex Deucher 26703afe6f6SAlex Deucher if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX) == 0) && 26803afe6f6SAlex Deucher (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX) == 0)) { 26903afe6f6SAlex Deucher if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 27003afe6f6SAlex Deucher radeon_dpm_enable_vce(rdev, false); 27103afe6f6SAlex Deucher } else { 27203afe6f6SAlex Deucher radeon_set_vce_clocks(rdev, 0, 0); 27303afe6f6SAlex Deucher } 27403afe6f6SAlex Deucher } else { 27503afe6f6SAlex Deucher schedule_delayed_work(&rdev->vce.idle_work, 27603afe6f6SAlex Deucher msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); 27703afe6f6SAlex Deucher } 27803afe6f6SAlex Deucher } 27903afe6f6SAlex Deucher 28003afe6f6SAlex Deucher /** 28103afe6f6SAlex Deucher * radeon_vce_note_usage - power up VCE 28203afe6f6SAlex Deucher * 28303afe6f6SAlex Deucher * @rdev: radeon_device pointer 28403afe6f6SAlex Deucher * 28503afe6f6SAlex Deucher * Make sure VCE is powerd up when we want to use it 28603afe6f6SAlex Deucher */ 28703afe6f6SAlex Deucher void radeon_vce_note_usage(struct radeon_device *rdev) 28803afe6f6SAlex Deucher { 28903afe6f6SAlex Deucher bool streams_changed = false; 29003afe6f6SAlex Deucher bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work); 29103afe6f6SAlex Deucher set_clocks &= schedule_delayed_work(&rdev->vce.idle_work, 29203afe6f6SAlex Deucher msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); 29303afe6f6SAlex Deucher 29403afe6f6SAlex Deucher if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 29503afe6f6SAlex Deucher /* XXX figure out if the streams changed */ 29603afe6f6SAlex Deucher streams_changed = false; 29703afe6f6SAlex Deucher } 29803afe6f6SAlex Deucher 29903afe6f6SAlex Deucher if (set_clocks || streams_changed) { 30003afe6f6SAlex Deucher if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 30103afe6f6SAlex Deucher radeon_dpm_enable_vce(rdev, true); 30203afe6f6SAlex Deucher } else { 30303afe6f6SAlex Deucher radeon_set_vce_clocks(rdev, 53300, 40000); 30403afe6f6SAlex Deucher } 30503afe6f6SAlex Deucher } 30603afe6f6SAlex Deucher } 30703afe6f6SAlex Deucher 30803afe6f6SAlex Deucher /** 309d93f7937SChristian König * radeon_vce_free_handles - free still open VCE handles 310d93f7937SChristian König * 311d93f7937SChristian König * @rdev: radeon_device pointer 312d93f7937SChristian König * @filp: drm file pointer 313d93f7937SChristian König * 314d93f7937SChristian König * Close all VCE handles still open by this file pointer 315d93f7937SChristian König */ 316d93f7937SChristian König void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) 317d93f7937SChristian König { 318d93f7937SChristian König int i, r; 319d93f7937SChristian König for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 320d93f7937SChristian König uint32_t handle = atomic_read(&rdev->vce.handles[i]); 321d93f7937SChristian König if (!handle || rdev->vce.filp[i] != filp) 322d93f7937SChristian König continue; 323d93f7937SChristian König 32403afe6f6SAlex Deucher radeon_vce_note_usage(rdev); 32503afe6f6SAlex Deucher 326d93f7937SChristian König r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, 327d93f7937SChristian König handle, NULL); 328d93f7937SChristian König if (r) 329d93f7937SChristian König DRM_ERROR("Error destroying VCE handle (%d)!\n", r); 330d93f7937SChristian König 331d93f7937SChristian König rdev->vce.filp[i] = NULL; 332d93f7937SChristian König atomic_set(&rdev->vce.handles[i], 0); 333d93f7937SChristian König } 334d93f7937SChristian König } 335d93f7937SChristian König 336d93f7937SChristian König /** 337d93f7937SChristian König * radeon_vce_get_create_msg - generate a VCE create msg 338d93f7937SChristian König * 339d93f7937SChristian König * @rdev: radeon_device pointer 340d93f7937SChristian König * @ring: ring we should submit the msg to 341d93f7937SChristian König * @handle: VCE session handle to use 342d93f7937SChristian König * @fence: optional fence to return 343d93f7937SChristian König * 344d93f7937SChristian König * Open up a stream for HW test 345d93f7937SChristian König */ 346d93f7937SChristian König int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, 347d93f7937SChristian König uint32_t handle, struct radeon_fence **fence) 348d93f7937SChristian König { 349d93f7937SChristian König const unsigned ib_size_dw = 1024; 350d93f7937SChristian König struct radeon_ib ib; 351d93f7937SChristian König uint64_t dummy; 352d93f7937SChristian König int i, r; 353d93f7937SChristian König 354d93f7937SChristian König r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); 355d93f7937SChristian König if (r) { 356d93f7937SChristian König DRM_ERROR("radeon: failed to get ib (%d).\n", r); 357d93f7937SChristian König return r; 358d93f7937SChristian König } 359d93f7937SChristian König 360d93f7937SChristian König dummy = ib.gpu_addr + 1024; 361d93f7937SChristian König 362d93f7937SChristian König /* stitch together an VCE create msg */ 363d93f7937SChristian König ib.length_dw = 0; 364361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ 365361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ 366361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(handle); 367d93f7937SChristian König 368361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000030); /* len */ 369361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x01000001); /* create cmd */ 370361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000); 371361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000042); 372361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000a); 373361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); 374361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000080); 375361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000060); 376361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100); 377361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100); 378361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); 379361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000); 380d93f7937SChristian König 381361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ 382361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ 383361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); 384361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); 385361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); 386d93f7937SChristian König 387d93f7937SChristian König for (i = ib.length_dw; i < ib_size_dw; ++i) 388361c32d3SOded Gabbay ib.ptr[i] = cpu_to_le32(0x0); 389d93f7937SChristian König 3901538a9e0SMichel Dänzer r = radeon_ib_schedule(rdev, &ib, NULL, false); 391d93f7937SChristian König if (r) { 392d93f7937SChristian König DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 393d93f7937SChristian König } 394d93f7937SChristian König 395d93f7937SChristian König if (fence) 396d93f7937SChristian König *fence = radeon_fence_ref(ib.fence); 397d93f7937SChristian König 398d93f7937SChristian König radeon_ib_free(rdev, &ib); 399d93f7937SChristian König 400d93f7937SChristian König return r; 401d93f7937SChristian König } 402d93f7937SChristian König 403d93f7937SChristian König /** 404d93f7937SChristian König * radeon_vce_get_destroy_msg - generate a VCE destroy msg 405d93f7937SChristian König * 406d93f7937SChristian König * @rdev: radeon_device pointer 407d93f7937SChristian König * @ring: ring we should submit the msg to 408d93f7937SChristian König * @handle: VCE session handle to use 409d93f7937SChristian König * @fence: optional fence to return 410d93f7937SChristian König * 411d93f7937SChristian König * Close up a stream for HW test or if userspace failed to do so 412d93f7937SChristian König */ 413d93f7937SChristian König int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, 414d93f7937SChristian König uint32_t handle, struct radeon_fence **fence) 415d93f7937SChristian König { 416d93f7937SChristian König const unsigned ib_size_dw = 1024; 417d93f7937SChristian König struct radeon_ib ib; 418d93f7937SChristian König uint64_t dummy; 419d93f7937SChristian König int i, r; 420d93f7937SChristian König 421d93f7937SChristian König r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); 422d93f7937SChristian König if (r) { 423d93f7937SChristian König DRM_ERROR("radeon: failed to get ib (%d).\n", r); 424d93f7937SChristian König return r; 425d93f7937SChristian König } 426d93f7937SChristian König 427d93f7937SChristian König dummy = ib.gpu_addr + 1024; 428d93f7937SChristian König 429d93f7937SChristian König /* stitch together an VCE destroy msg */ 430d93f7937SChristian König ib.length_dw = 0; 431361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ 432361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ 433361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(handle); 434d93f7937SChristian König 435361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ 436361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ 437361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); 438361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); 439361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); 440d93f7937SChristian König 441361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008); /* len */ 442361c32d3SOded Gabbay ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001); /* destroy cmd */ 443d93f7937SChristian König 444d93f7937SChristian König for (i = ib.length_dw; i < ib_size_dw; ++i) 445361c32d3SOded Gabbay ib.ptr[i] = cpu_to_le32(0x0); 446d93f7937SChristian König 4471538a9e0SMichel Dänzer r = radeon_ib_schedule(rdev, &ib, NULL, false); 448d93f7937SChristian König if (r) { 449d93f7937SChristian König DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 450d93f7937SChristian König } 451d93f7937SChristian König 452d93f7937SChristian König if (fence) 453d93f7937SChristian König *fence = radeon_fence_ref(ib.fence); 454d93f7937SChristian König 455d93f7937SChristian König radeon_ib_free(rdev, &ib); 456d93f7937SChristian König 457d93f7937SChristian König return r; 458d93f7937SChristian König } 459d93f7937SChristian König 460d93f7937SChristian König /** 461d93f7937SChristian König * radeon_vce_cs_reloc - command submission relocation 462d93f7937SChristian König * 463d93f7937SChristian König * @p: parser context 464d93f7937SChristian König * @lo: address of lower dword 465d93f7937SChristian König * @hi: address of higher dword 4662fc5703aSLeo Liu * @size: size of checker for relocation buffer 467d93f7937SChristian König * 468d93f7937SChristian König * Patch relocation inside command stream with real buffer address 469d93f7937SChristian König */ 4702fc5703aSLeo Liu int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi, 4712fc5703aSLeo Liu unsigned size) 472d93f7937SChristian König { 473d93f7937SChristian König struct radeon_cs_chunk *relocs_chunk; 4741d0c0942SChristian König struct radeon_bo_list *reloc; 4752fc5703aSLeo Liu uint64_t start, end, offset; 476d93f7937SChristian König unsigned idx; 477d93f7937SChristian König 4786d2d13ddSChristian König relocs_chunk = p->chunk_relocs; 479d93f7937SChristian König offset = radeon_get_ib_value(p, lo); 480d93f7937SChristian König idx = radeon_get_ib_value(p, hi); 481d93f7937SChristian König 482d93f7937SChristian König if (idx >= relocs_chunk->length_dw) { 483d93f7937SChristian König DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", 484d93f7937SChristian König idx, relocs_chunk->length_dw); 485d93f7937SChristian König return -EINVAL; 486d93f7937SChristian König } 487d93f7937SChristian König 488466be338SChristian König reloc = &p->relocs[(idx / 4)]; 4892fc5703aSLeo Liu start = reloc->gpu_offset; 4902fc5703aSLeo Liu end = start + radeon_bo_size(reloc->robj); 4912fc5703aSLeo Liu start += offset; 492d93f7937SChristian König 4932fc5703aSLeo Liu p->ib.ptr[lo] = start & 0xFFFFFFFF; 4942fc5703aSLeo Liu p->ib.ptr[hi] = start >> 32; 4952fc5703aSLeo Liu 4962fc5703aSLeo Liu if (end <= start) { 4972fc5703aSLeo Liu DRM_ERROR("invalid reloc offset %llX!\n", offset); 4982fc5703aSLeo Liu return -EINVAL; 4992fc5703aSLeo Liu } 5002fc5703aSLeo Liu if ((end - start) < size) { 5012fc5703aSLeo Liu DRM_ERROR("buffer to small (%d / %d)!\n", 5022fc5703aSLeo Liu (unsigned)(end - start), size); 5032fc5703aSLeo Liu return -EINVAL; 5042fc5703aSLeo Liu } 505d93f7937SChristian König 506d93f7937SChristian König return 0; 507d93f7937SChristian König } 508d93f7937SChristian König 509d93f7937SChristian König /** 5102fc5703aSLeo Liu * radeon_vce_validate_handle - validate stream handle 5112fc5703aSLeo Liu * 5122fc5703aSLeo Liu * @p: parser context 5132fc5703aSLeo Liu * @handle: handle to validate 51429c63fe2SChristian König * @allocated: allocated a new handle? 5152fc5703aSLeo Liu * 5162fc5703aSLeo Liu * Validates the handle and return the found session index or -EINVAL 5172fc5703aSLeo Liu * we we don't have another free session index. 5182fc5703aSLeo Liu */ 51929c63fe2SChristian König static int radeon_vce_validate_handle(struct radeon_cs_parser *p, 52029c63fe2SChristian König uint32_t handle, bool *allocated) 5212fc5703aSLeo Liu { 5222fc5703aSLeo Liu unsigned i; 5232fc5703aSLeo Liu 52429c63fe2SChristian König *allocated = false; 52529c63fe2SChristian König 5262fc5703aSLeo Liu /* validate the handle */ 5272fc5703aSLeo Liu for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 52829c63fe2SChristian König if (atomic_read(&p->rdev->vce.handles[i]) == handle) { 52929c63fe2SChristian König if (p->rdev->vce.filp[i] != p->filp) { 53029c63fe2SChristian König DRM_ERROR("VCE handle collision detected!\n"); 53129c63fe2SChristian König return -EINVAL; 53229c63fe2SChristian König } 5332fc5703aSLeo Liu return i; 5342fc5703aSLeo Liu } 53529c63fe2SChristian König } 5362fc5703aSLeo Liu 5372fc5703aSLeo Liu /* handle not found try to alloc a new one */ 5382fc5703aSLeo Liu for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 5392fc5703aSLeo Liu if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { 5402fc5703aSLeo Liu p->rdev->vce.filp[i] = p->filp; 5412fc5703aSLeo Liu p->rdev->vce.img_size[i] = 0; 54229c63fe2SChristian König *allocated = true; 5432fc5703aSLeo Liu return i; 5442fc5703aSLeo Liu } 5452fc5703aSLeo Liu } 5462fc5703aSLeo Liu 5472fc5703aSLeo Liu DRM_ERROR("No more free VCE handles!\n"); 5482fc5703aSLeo Liu return -EINVAL; 5492fc5703aSLeo Liu } 5502fc5703aSLeo Liu 5512fc5703aSLeo Liu /** 552d93f7937SChristian König * radeon_vce_cs_parse - parse and validate the command stream 553d93f7937SChristian König * 554d93f7937SChristian König * @p: parser context 555d93f7937SChristian König * 556d93f7937SChristian König */ 557d93f7937SChristian König int radeon_vce_cs_parse(struct radeon_cs_parser *p) 558d93f7937SChristian König { 5592fc5703aSLeo Liu int session_idx = -1; 56029c63fe2SChristian König bool destroyed = false, created = false, allocated = false; 5612fc5703aSLeo Liu uint32_t tmp, handle = 0; 5622fc5703aSLeo Liu uint32_t *size = &tmp; 56329c63fe2SChristian König int i, r = 0; 564d93f7937SChristian König 5656d2d13ddSChristian König while (p->idx < p->chunk_ib->length_dw) { 566d93f7937SChristian König uint32_t len = radeon_get_ib_value(p, p->idx); 567d93f7937SChristian König uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); 568d93f7937SChristian König 569d93f7937SChristian König if ((len < 8) || (len & 3)) { 570d93f7937SChristian König DRM_ERROR("invalid VCE command length (%d)!\n", len); 57129c63fe2SChristian König r = -EINVAL; 57229c63fe2SChristian König goto out; 573d93f7937SChristian König } 574d93f7937SChristian König 5752fc5703aSLeo Liu if (destroyed) { 5762fc5703aSLeo Liu DRM_ERROR("No other command allowed after destroy!\n"); 57729c63fe2SChristian König r = -EINVAL; 57829c63fe2SChristian König goto out; 5792fc5703aSLeo Liu } 5802fc5703aSLeo Liu 581d93f7937SChristian König switch (cmd) { 582d93f7937SChristian König case 0x00000001: // session 583d93f7937SChristian König handle = radeon_get_ib_value(p, p->idx + 2); 58429c63fe2SChristian König session_idx = radeon_vce_validate_handle(p, handle, 58529c63fe2SChristian König &allocated); 5862fc5703aSLeo Liu if (session_idx < 0) 5872fc5703aSLeo Liu return session_idx; 5882fc5703aSLeo Liu size = &p->rdev->vce.img_size[session_idx]; 589d93f7937SChristian König break; 590d93f7937SChristian König 591d93f7937SChristian König case 0x00000002: // task info 5922fc5703aSLeo Liu break; 5932fc5703aSLeo Liu 594d93f7937SChristian König case 0x01000001: // create 59529c63fe2SChristian König created = true; 59629c63fe2SChristian König if (!allocated) { 59729c63fe2SChristian König DRM_ERROR("Handle already in use!\n"); 59829c63fe2SChristian König r = -EINVAL; 59929c63fe2SChristian König goto out; 60029c63fe2SChristian König } 60129c63fe2SChristian König 6022fc5703aSLeo Liu *size = radeon_get_ib_value(p, p->idx + 8) * 6032fc5703aSLeo Liu radeon_get_ib_value(p, p->idx + 10) * 6042fc5703aSLeo Liu 8 * 3 / 2; 6052fc5703aSLeo Liu break; 6062fc5703aSLeo Liu 607d93f7937SChristian König case 0x04000001: // config extension 608d93f7937SChristian König case 0x04000002: // pic control 609d93f7937SChristian König case 0x04000005: // rate control 610d93f7937SChristian König case 0x04000007: // motion estimation 611d93f7937SChristian König case 0x04000008: // rdo 6121957d6beSLeo Liu case 0x04000009: // vui 613d93f7937SChristian König break; 614d93f7937SChristian König 615d93f7937SChristian König case 0x03000001: // encode 6162fc5703aSLeo Liu r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9, 6172fc5703aSLeo Liu *size); 618d93f7937SChristian König if (r) 61929c63fe2SChristian König goto out; 620d93f7937SChristian König 6212fc5703aSLeo Liu r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11, 6222fc5703aSLeo Liu *size / 3); 623d93f7937SChristian König if (r) 62429c63fe2SChristian König goto out; 625d93f7937SChristian König break; 626d93f7937SChristian König 627d93f7937SChristian König case 0x02000001: // destroy 6282fc5703aSLeo Liu destroyed = true; 629d93f7937SChristian König break; 630d93f7937SChristian König 631d93f7937SChristian König case 0x05000001: // context buffer 6322fc5703aSLeo Liu r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 6332fc5703aSLeo Liu *size * 2); 6342fc5703aSLeo Liu if (r) 63529c63fe2SChristian König goto out; 6362fc5703aSLeo Liu break; 6372fc5703aSLeo Liu 638d93f7937SChristian König case 0x05000004: // video bitstream buffer 6392fc5703aSLeo Liu tmp = radeon_get_ib_value(p, p->idx + 4); 6402fc5703aSLeo Liu r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 6412fc5703aSLeo Liu tmp); 6422fc5703aSLeo Liu if (r) 64329c63fe2SChristian König goto out; 6442fc5703aSLeo Liu break; 6452fc5703aSLeo Liu 646d93f7937SChristian König case 0x05000005: // feedback buffer 6472fc5703aSLeo Liu r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 6482fc5703aSLeo Liu 4096); 649d93f7937SChristian König if (r) 65029c63fe2SChristian König goto out; 651d93f7937SChristian König break; 652d93f7937SChristian König 653d93f7937SChristian König default: 654d93f7937SChristian König DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); 65529c63fe2SChristian König r = -EINVAL; 65629c63fe2SChristian König goto out; 657d93f7937SChristian König } 658d93f7937SChristian König 6592fc5703aSLeo Liu if (session_idx == -1) { 6602fc5703aSLeo Liu DRM_ERROR("no session command at start of IB\n"); 66129c63fe2SChristian König r = -EINVAL; 66229c63fe2SChristian König goto out; 6632fc5703aSLeo Liu } 6642fc5703aSLeo Liu 665d93f7937SChristian König p->idx += len / 4; 666d93f7937SChristian König } 667d93f7937SChristian König 66829c63fe2SChristian König if (allocated && !created) { 66929c63fe2SChristian König DRM_ERROR("New session without create command!\n"); 67029c63fe2SChristian König r = -ENOENT; 67129c63fe2SChristian König } 67229c63fe2SChristian König 67329c63fe2SChristian König out: 67429c63fe2SChristian König if ((!r && destroyed) || (r && allocated)) { 67529c63fe2SChristian König /* 67629c63fe2SChristian König * IB contains a destroy msg or we have allocated an 67729c63fe2SChristian König * handle and got an error, anyway free the handle 67829c63fe2SChristian König */ 679d93f7937SChristian König for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) 680d93f7937SChristian König atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0); 6812fc5703aSLeo Liu } 682d93f7937SChristian König 68329c63fe2SChristian König return r; 684d93f7937SChristian König } 685d93f7937SChristian König 686d93f7937SChristian König /** 687d93f7937SChristian König * radeon_vce_semaphore_emit - emit a semaphore command 688d93f7937SChristian König * 689d93f7937SChristian König * @rdev: radeon_device pointer 690d93f7937SChristian König * @ring: engine to use 691d93f7937SChristian König * @semaphore: address of semaphore 692d93f7937SChristian König * @emit_wait: true=emit wait, false=emit signal 693d93f7937SChristian König * 694d93f7937SChristian König */ 695d93f7937SChristian König bool radeon_vce_semaphore_emit(struct radeon_device *rdev, 696d93f7937SChristian König struct radeon_ring *ring, 697d93f7937SChristian König struct radeon_semaphore *semaphore, 698d93f7937SChristian König bool emit_wait) 699d93f7937SChristian König { 700d93f7937SChristian König uint64_t addr = semaphore->gpu_addr; 701d93f7937SChristian König 702687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(VCE_CMD_SEMAPHORE)); 703687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32((addr >> 3) & 0x000FFFFF)); 704687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32((addr >> 23) & 0x000FFFFF)); 705687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(0x01003000 | (emit_wait ? 1 : 0))); 706d93f7937SChristian König if (!emit_wait) 707687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); 708d93f7937SChristian König 709d93f7937SChristian König return true; 710d93f7937SChristian König } 711d93f7937SChristian König 712d93f7937SChristian König /** 713d93f7937SChristian König * radeon_vce_ib_execute - execute indirect buffer 714d93f7937SChristian König * 715d93f7937SChristian König * @rdev: radeon_device pointer 716d93f7937SChristian König * @ib: the IB to execute 717d93f7937SChristian König * 718d93f7937SChristian König */ 719d93f7937SChristian König void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) 720d93f7937SChristian König { 721d93f7937SChristian König struct radeon_ring *ring = &rdev->ring[ib->ring]; 722687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(VCE_CMD_IB)); 723687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(ib->gpu_addr)); 724687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(upper_32_bits(ib->gpu_addr))); 725687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(ib->length_dw)); 726d93f7937SChristian König } 727d93f7937SChristian König 728d93f7937SChristian König /** 729d93f7937SChristian König * radeon_vce_fence_emit - add a fence command to the ring 730d93f7937SChristian König * 731d93f7937SChristian König * @rdev: radeon_device pointer 732d93f7937SChristian König * @fence: the fence 733d93f7937SChristian König * 734d93f7937SChristian König */ 735d93f7937SChristian König void radeon_vce_fence_emit(struct radeon_device *rdev, 736d93f7937SChristian König struct radeon_fence *fence) 737d93f7937SChristian König { 738d93f7937SChristian König struct radeon_ring *ring = &rdev->ring[fence->ring]; 739681941c1SChristoph Jaeger uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; 740d93f7937SChristian König 741687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(VCE_CMD_FENCE)); 742687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(addr)); 743687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(upper_32_bits(addr))); 744687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(fence->seq)); 745687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(VCE_CMD_TRAP)); 746687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); 747d93f7937SChristian König } 748d93f7937SChristian König 749d93f7937SChristian König /** 750d93f7937SChristian König * radeon_vce_ring_test - test if VCE ring is working 751d93f7937SChristian König * 752d93f7937SChristian König * @rdev: radeon_device pointer 753d93f7937SChristian König * @ring: the engine to test on 754d93f7937SChristian König * 755d93f7937SChristian König */ 756d93f7937SChristian König int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) 757d93f7937SChristian König { 758d93f7937SChristian König uint32_t rptr = vce_v1_0_get_rptr(rdev, ring); 759d93f7937SChristian König unsigned i; 760d93f7937SChristian König int r; 761d93f7937SChristian König 762d93f7937SChristian König r = radeon_ring_lock(rdev, ring, 16); 763d93f7937SChristian König if (r) { 764d93f7937SChristian König DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n", 765d93f7937SChristian König ring->idx, r); 766d93f7937SChristian König return r; 767d93f7937SChristian König } 768687f4b98SOded Gabbay radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); 7691538a9e0SMichel Dänzer radeon_ring_unlock_commit(rdev, ring, false); 770d93f7937SChristian König 771d93f7937SChristian König for (i = 0; i < rdev->usec_timeout; i++) { 772d93f7937SChristian König if (vce_v1_0_get_rptr(rdev, ring) != rptr) 773d93f7937SChristian König break; 774*0e1a351dSSam Ravnborg udelay(1); 775d93f7937SChristian König } 776d93f7937SChristian König 777d93f7937SChristian König if (i < rdev->usec_timeout) { 778d93f7937SChristian König DRM_INFO("ring test on %d succeeded in %d usecs\n", 779d93f7937SChristian König ring->idx, i); 780d93f7937SChristian König } else { 781d93f7937SChristian König DRM_ERROR("radeon: ring %d test failed\n", 782d93f7937SChristian König ring->idx); 783d93f7937SChristian König r = -ETIMEDOUT; 784d93f7937SChristian König } 785d93f7937SChristian König 786d93f7937SChristian König return r; 787d93f7937SChristian König } 788d93f7937SChristian König 789d93f7937SChristian König /** 790d93f7937SChristian König * radeon_vce_ib_test - test if VCE IBs are working 791d93f7937SChristian König * 792d93f7937SChristian König * @rdev: radeon_device pointer 793d93f7937SChristian König * @ring: the engine to test on 794d93f7937SChristian König * 795d93f7937SChristian König */ 796d93f7937SChristian König int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) 797d93f7937SChristian König { 798d93f7937SChristian König struct radeon_fence *fence = NULL; 799d93f7937SChristian König int r; 800d93f7937SChristian König 801d93f7937SChristian König r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL); 802d93f7937SChristian König if (r) { 803d93f7937SChristian König DRM_ERROR("radeon: failed to get create msg (%d).\n", r); 804d93f7937SChristian König goto error; 805d93f7937SChristian König } 806d93f7937SChristian König 807d93f7937SChristian König r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence); 808d93f7937SChristian König if (r) { 809d93f7937SChristian König DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); 810d93f7937SChristian König goto error; 811d93f7937SChristian König } 812d93f7937SChristian König 81304db4cafSMatthew Dawson r = radeon_fence_wait_timeout(fence, false, usecs_to_jiffies( 81404db4cafSMatthew Dawson RADEON_USEC_IB_TEST_TIMEOUT)); 81504db4cafSMatthew Dawson if (r < 0) { 816d93f7937SChristian König DRM_ERROR("radeon: fence wait failed (%d).\n", r); 81704db4cafSMatthew Dawson } else if (r == 0) { 81804db4cafSMatthew Dawson DRM_ERROR("radeon: fence wait timed out.\n"); 81904db4cafSMatthew Dawson r = -ETIMEDOUT; 820d93f7937SChristian König } else { 821d93f7937SChristian König DRM_INFO("ib test on ring %d succeeded\n", ring->idx); 82204db4cafSMatthew Dawson r = 0; 823d93f7937SChristian König } 824d93f7937SChristian König error: 825d93f7937SChristian König radeon_fence_unref(&fence); 826d93f7937SChristian König return r; 827d93f7937SChristian König } 828