1 1.5 riastrad /* $NetBSD: radeon_vce.c,v 1.5 2021/12/18 23:45:43 riastradh Exp $ */ 2 1.3 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2013 Advanced Micro Devices, Inc. 5 1.1 riastrad * All Rights Reserved. 6 1.1 riastrad * 7 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 8 1.1 riastrad * copy of this software and associated documentation files (the 9 1.1 riastrad * "Software"), to deal in the Software without restriction, including 10 1.1 riastrad * without limitation the rights to use, copy, modify, merge, publish, 11 1.1 riastrad * distribute, sub license, and/or sell copies of the Software, and to 12 1.1 riastrad * permit persons to whom the Software is furnished to do so, subject to 13 1.1 riastrad * the following conditions: 14 1.1 riastrad * 15 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 1.1 riastrad * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 1.1 riastrad * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 1.1 riastrad * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 1.1 riastrad * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 1.1 riastrad * 23 1.1 riastrad * The above copyright notice and this permission notice (including the 24 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 25 1.1 riastrad * of the Software. 26 1.1 riastrad * 27 1.1 riastrad * Authors: Christian Knig <christian.koenig (at) amd.com> 28 1.1 riastrad */ 29 1.1 riastrad 30 1.3 riastrad #include <sys/cdefs.h> 31 1.5 riastrad __KERNEL_RCSID(0, "$NetBSD: radeon_vce.c,v 1.5 2021/12/18 23:45:43 riastradh Exp $"); 32 1.3 riastrad 33 1.1 riastrad #include <linux/firmware.h> 34 1.1 riastrad #include <linux/module.h> 35 1.5 riastrad 36 1.1 riastrad #include <drm/drm.h> 37 1.1 riastrad 38 1.1 riastrad #include "radeon.h" 39 1.1 riastrad #include "radeon_asic.h" 40 1.1 riastrad #include "sid.h" 41 1.1 riastrad 42 1.1 riastrad /* 1 second timeout */ 43 1.1 riastrad #define VCE_IDLE_TIMEOUT_MS 1000 44 1.1 riastrad 45 1.1 riastrad /* Firmware Names */ 46 1.3 riastrad #define FIRMWARE_TAHITI "radeon/TAHITI_vce.bin" 47 1.1 riastrad #define FIRMWARE_BONAIRE "radeon/BONAIRE_vce.bin" 48 1.1 riastrad 49 1.3 riastrad MODULE_FIRMWARE(FIRMWARE_TAHITI); 50 1.1 riastrad MODULE_FIRMWARE(FIRMWARE_BONAIRE); 51 1.1 riastrad 52 1.1 riastrad static void radeon_vce_idle_work_handler(struct work_struct *work); 53 1.1 riastrad 54 1.2 riastrad #ifdef __NetBSD__ /* XXX Ugh! */ 55 1.2 riastrad static bool 56 1.4 jmcneill scan_2dec_uint(const char **sp, char delim, unsigned int *uintp) 57 1.2 riastrad { 58 1.4 jmcneill u_int val = 0, n; 59 1.4 jmcneill char c; 60 1.2 riastrad 61 1.4 jmcneill for (n = 0; n < 2; n++) { 62 1.4 jmcneill c = *(*sp)++; 63 1.4 jmcneill if (!isdigit((unsigned char)c)) 64 1.4 jmcneill return false; 65 1.4 jmcneill if (n != 0) 66 1.4 jmcneill val *= 10; 67 1.4 jmcneill val += (c - '0'); 68 1.4 jmcneill if (*(*sp) == delim) 69 1.4 jmcneill break; 70 1.4 jmcneill } 71 1.4 jmcneill if (*(*sp) != delim) 72 1.2 riastrad return false; 73 1.2 riastrad 74 1.4 jmcneill (*sp)++; 75 1.4 jmcneill *uintp = val; 76 1.2 riastrad return true; 77 1.2 riastrad } 78 1.2 riastrad 79 1.2 riastrad static bool 80 1.4 jmcneill scan_2dec_u8(const char **sp, char delim, uint8_t *u8p) 81 1.2 riastrad { 82 1.4 jmcneill unsigned int val; 83 1.2 riastrad 84 1.4 jmcneill if (!scan_2dec_uint(sp, delim, &val)) 85 1.2 riastrad return false; 86 1.2 riastrad 87 1.4 jmcneill *u8p = (uint8_t)val; 88 1.2 riastrad return true; 89 1.2 riastrad } 90 1.2 riastrad #endif 91 1.2 riastrad 92 1.1 riastrad /** 93 1.1 riastrad * radeon_vce_init - allocate memory, load vce firmware 94 1.1 riastrad * 95 1.1 riastrad * @rdev: radeon_device pointer 96 1.1 riastrad * 97 1.1 riastrad * First step to get VCE online, allocate memory and load the firmware 98 1.1 riastrad */ 99 1.1 riastrad int radeon_vce_init(struct radeon_device *rdev) 100 1.1 riastrad { 101 1.1 riastrad static const char *fw_version = "[ATI LIB=VCEFW,"; 102 1.1 riastrad static const char *fb_version = "[ATI LIB=VCEFWSTATS,"; 103 1.1 riastrad unsigned long size; 104 1.1 riastrad const char *fw_name, *c; 105 1.1 riastrad uint8_t start, mid, end; 106 1.1 riastrad int i, r; 107 1.1 riastrad 108 1.1 riastrad INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler); 109 1.1 riastrad 110 1.1 riastrad switch (rdev->family) { 111 1.3 riastrad case CHIP_TAHITI: 112 1.3 riastrad case CHIP_PITCAIRN: 113 1.3 riastrad case CHIP_VERDE: 114 1.3 riastrad case CHIP_OLAND: 115 1.3 riastrad case CHIP_ARUBA: 116 1.3 riastrad fw_name = FIRMWARE_TAHITI; 117 1.3 riastrad break; 118 1.3 riastrad 119 1.1 riastrad case CHIP_BONAIRE: 120 1.1 riastrad case CHIP_KAVERI: 121 1.1 riastrad case CHIP_KABINI: 122 1.3 riastrad case CHIP_HAWAII: 123 1.1 riastrad case CHIP_MULLINS: 124 1.1 riastrad fw_name = FIRMWARE_BONAIRE; 125 1.1 riastrad break; 126 1.1 riastrad 127 1.1 riastrad default: 128 1.1 riastrad return -EINVAL; 129 1.1 riastrad } 130 1.1 riastrad 131 1.1 riastrad r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev); 132 1.1 riastrad if (r) { 133 1.1 riastrad dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n", 134 1.1 riastrad fw_name); 135 1.1 riastrad return r; 136 1.1 riastrad } 137 1.1 riastrad 138 1.1 riastrad /* search for firmware version */ 139 1.1 riastrad 140 1.1 riastrad size = rdev->vce_fw->size - strlen(fw_version) - 9; 141 1.1 riastrad c = rdev->vce_fw->data; 142 1.1 riastrad for (;size > 0; --size, ++c) 143 1.1 riastrad if (strncmp(c, fw_version, strlen(fw_version)) == 0) 144 1.1 riastrad break; 145 1.1 riastrad 146 1.1 riastrad if (size == 0) 147 1.1 riastrad return -EINVAL; 148 1.1 riastrad 149 1.1 riastrad c += strlen(fw_version); 150 1.2 riastrad #ifdef __NetBSD__ 151 1.2 riastrad if (!scan_2dec_u8(&c, '.', &start)) 152 1.2 riastrad return -EINVAL; 153 1.2 riastrad if (!scan_2dec_u8(&c, '.', &mid)) 154 1.2 riastrad return -EINVAL; 155 1.2 riastrad if (!scan_2dec_u8(&c, ']', &end)) 156 1.2 riastrad return -EINVAL; 157 1.2 riastrad #else 158 1.1 riastrad if (sscanf(c, "%2hhd.%2hhd.%2hhd]", &start, &mid, &end) != 3) 159 1.1 riastrad return -EINVAL; 160 1.2 riastrad #endif 161 1.1 riastrad 162 1.1 riastrad /* search for feedback version */ 163 1.1 riastrad 164 1.1 riastrad size = rdev->vce_fw->size - strlen(fb_version) - 3; 165 1.1 riastrad c = rdev->vce_fw->data; 166 1.1 riastrad for (;size > 0; --size, ++c) 167 1.1 riastrad if (strncmp(c, fb_version, strlen(fb_version)) == 0) 168 1.1 riastrad break; 169 1.1 riastrad 170 1.1 riastrad if (size == 0) 171 1.1 riastrad return -EINVAL; 172 1.1 riastrad 173 1.1 riastrad c += strlen(fb_version); 174 1.2 riastrad #ifdef __NetBSD__ 175 1.2 riastrad if (!scan_2dec_uint(&c, ']', &rdev->vce.fb_version)) 176 1.2 riastrad return -EINVAL; 177 1.2 riastrad #else 178 1.1 riastrad if (sscanf(c, "%2u]", &rdev->vce.fb_version) != 1) 179 1.1 riastrad return -EINVAL; 180 1.2 riastrad #endif 181 1.1 riastrad 182 1.1 riastrad DRM_INFO("Found VCE firmware/feedback version %hhd.%hhd.%hhd / %d!\n", 183 1.1 riastrad start, mid, end, rdev->vce.fb_version); 184 1.1 riastrad 185 1.1 riastrad rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8); 186 1.1 riastrad 187 1.1 riastrad /* we can only work with this fw version for now */ 188 1.3 riastrad if ((rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) && 189 1.3 riastrad (rdev->vce.fw_version != ((50 << 24) | (0 << 16) | (1 << 8))) && 190 1.3 riastrad (rdev->vce.fw_version != ((50 << 24) | (1 << 16) | (2 << 8)))) 191 1.1 riastrad return -EINVAL; 192 1.1 riastrad 193 1.1 riastrad /* allocate firmware, stack and heap BO */ 194 1.1 riastrad 195 1.3 riastrad if (rdev->family < CHIP_BONAIRE) 196 1.3 riastrad size = vce_v1_0_bo_size(rdev); 197 1.3 riastrad else 198 1.3 riastrad size = vce_v2_0_bo_size(rdev); 199 1.1 riastrad r = radeon_bo_create(rdev, size, PAGE_SIZE, true, 200 1.3 riastrad RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL, 201 1.3 riastrad &rdev->vce.vcpu_bo); 202 1.1 riastrad if (r) { 203 1.1 riastrad dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r); 204 1.1 riastrad return r; 205 1.1 riastrad } 206 1.1 riastrad 207 1.1 riastrad r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); 208 1.1 riastrad if (r) { 209 1.1 riastrad radeon_bo_unref(&rdev->vce.vcpu_bo); 210 1.1 riastrad dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); 211 1.1 riastrad return r; 212 1.1 riastrad } 213 1.1 riastrad 214 1.1 riastrad r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, 215 1.1 riastrad &rdev->vce.gpu_addr); 216 1.1 riastrad radeon_bo_unreserve(rdev->vce.vcpu_bo); 217 1.1 riastrad if (r) { 218 1.1 riastrad radeon_bo_unref(&rdev->vce.vcpu_bo); 219 1.1 riastrad dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r); 220 1.1 riastrad return r; 221 1.1 riastrad } 222 1.1 riastrad 223 1.1 riastrad for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 224 1.1 riastrad atomic_set(&rdev->vce.handles[i], 0); 225 1.1 riastrad rdev->vce.filp[i] = NULL; 226 1.5 riastrad } 227 1.1 riastrad 228 1.1 riastrad return 0; 229 1.1 riastrad } 230 1.1 riastrad 231 1.1 riastrad /** 232 1.1 riastrad * radeon_vce_fini - free memory 233 1.1 riastrad * 234 1.1 riastrad * @rdev: radeon_device pointer 235 1.1 riastrad * 236 1.1 riastrad * Last step on VCE teardown, free firmware memory 237 1.1 riastrad */ 238 1.1 riastrad void radeon_vce_fini(struct radeon_device *rdev) 239 1.1 riastrad { 240 1.1 riastrad if (rdev->vce.vcpu_bo == NULL) 241 1.1 riastrad return; 242 1.1 riastrad 243 1.1 riastrad radeon_bo_unref(&rdev->vce.vcpu_bo); 244 1.1 riastrad 245 1.1 riastrad release_firmware(rdev->vce_fw); 246 1.1 riastrad } 247 1.1 riastrad 248 1.1 riastrad /** 249 1.1 riastrad * radeon_vce_suspend - unpin VCE fw memory 250 1.1 riastrad * 251 1.1 riastrad * @rdev: radeon_device pointer 252 1.1 riastrad * 253 1.1 riastrad */ 254 1.1 riastrad int radeon_vce_suspend(struct radeon_device *rdev) 255 1.1 riastrad { 256 1.1 riastrad int i; 257 1.1 riastrad 258 1.1 riastrad if (rdev->vce.vcpu_bo == NULL) 259 1.1 riastrad return 0; 260 1.1 riastrad 261 1.1 riastrad for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) 262 1.1 riastrad if (atomic_read(&rdev->vce.handles[i])) 263 1.1 riastrad break; 264 1.1 riastrad 265 1.1 riastrad if (i == RADEON_MAX_VCE_HANDLES) 266 1.1 riastrad return 0; 267 1.1 riastrad 268 1.1 riastrad /* TODO: suspending running encoding sessions isn't supported */ 269 1.1 riastrad return -EINVAL; 270 1.1 riastrad } 271 1.1 riastrad 272 1.1 riastrad /** 273 1.1 riastrad * radeon_vce_resume - pin VCE fw memory 274 1.1 riastrad * 275 1.1 riastrad * @rdev: radeon_device pointer 276 1.1 riastrad * 277 1.1 riastrad */ 278 1.1 riastrad int radeon_vce_resume(struct radeon_device *rdev) 279 1.1 riastrad { 280 1.1 riastrad void *cpu_addr; 281 1.1 riastrad int r; 282 1.1 riastrad 283 1.1 riastrad if (rdev->vce.vcpu_bo == NULL) 284 1.1 riastrad return -EINVAL; 285 1.1 riastrad 286 1.1 riastrad r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); 287 1.1 riastrad if (r) { 288 1.1 riastrad dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); 289 1.1 riastrad return r; 290 1.1 riastrad } 291 1.1 riastrad 292 1.1 riastrad r = radeon_bo_kmap(rdev->vce.vcpu_bo, &cpu_addr); 293 1.1 riastrad if (r) { 294 1.1 riastrad radeon_bo_unreserve(rdev->vce.vcpu_bo); 295 1.1 riastrad dev_err(rdev->dev, "(%d) VCE map failed\n", r); 296 1.1 riastrad return r; 297 1.1 riastrad } 298 1.1 riastrad 299 1.3 riastrad memset(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo)); 300 1.3 riastrad if (rdev->family < CHIP_BONAIRE) 301 1.3 riastrad r = vce_v1_0_load_fw(rdev, cpu_addr); 302 1.3 riastrad else 303 1.3 riastrad memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size); 304 1.1 riastrad 305 1.1 riastrad radeon_bo_kunmap(rdev->vce.vcpu_bo); 306 1.1 riastrad 307 1.1 riastrad radeon_bo_unreserve(rdev->vce.vcpu_bo); 308 1.1 riastrad 309 1.3 riastrad return r; 310 1.1 riastrad } 311 1.1 riastrad 312 1.1 riastrad /** 313 1.1 riastrad * radeon_vce_idle_work_handler - power off VCE 314 1.1 riastrad * 315 1.1 riastrad * @work: pointer to work structure 316 1.1 riastrad * 317 1.1 riastrad * power of VCE when it's not used any more 318 1.1 riastrad */ 319 1.1 riastrad static void radeon_vce_idle_work_handler(struct work_struct *work) 320 1.1 riastrad { 321 1.1 riastrad struct radeon_device *rdev = 322 1.1 riastrad container_of(work, struct radeon_device, vce.idle_work.work); 323 1.1 riastrad 324 1.1 riastrad if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX) == 0) && 325 1.1 riastrad (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX) == 0)) { 326 1.1 riastrad if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 327 1.1 riastrad radeon_dpm_enable_vce(rdev, false); 328 1.1 riastrad } else { 329 1.1 riastrad radeon_set_vce_clocks(rdev, 0, 0); 330 1.1 riastrad } 331 1.1 riastrad } else { 332 1.1 riastrad schedule_delayed_work(&rdev->vce.idle_work, 333 1.1 riastrad msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); 334 1.1 riastrad } 335 1.1 riastrad } 336 1.1 riastrad 337 1.1 riastrad /** 338 1.1 riastrad * radeon_vce_note_usage - power up VCE 339 1.1 riastrad * 340 1.1 riastrad * @rdev: radeon_device pointer 341 1.1 riastrad * 342 1.1 riastrad * Make sure VCE is powerd up when we want to use it 343 1.1 riastrad */ 344 1.1 riastrad void radeon_vce_note_usage(struct radeon_device *rdev) 345 1.1 riastrad { 346 1.1 riastrad bool streams_changed = false; 347 1.1 riastrad bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work); 348 1.1 riastrad set_clocks &= schedule_delayed_work(&rdev->vce.idle_work, 349 1.1 riastrad msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)); 350 1.1 riastrad 351 1.1 riastrad if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 352 1.1 riastrad /* XXX figure out if the streams changed */ 353 1.1 riastrad streams_changed = false; 354 1.1 riastrad } 355 1.1 riastrad 356 1.1 riastrad if (set_clocks || streams_changed) { 357 1.1 riastrad if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 358 1.1 riastrad radeon_dpm_enable_vce(rdev, true); 359 1.1 riastrad } else { 360 1.1 riastrad radeon_set_vce_clocks(rdev, 53300, 40000); 361 1.1 riastrad } 362 1.1 riastrad } 363 1.1 riastrad } 364 1.1 riastrad 365 1.1 riastrad /** 366 1.1 riastrad * radeon_vce_free_handles - free still open VCE handles 367 1.1 riastrad * 368 1.1 riastrad * @rdev: radeon_device pointer 369 1.1 riastrad * @filp: drm file pointer 370 1.1 riastrad * 371 1.1 riastrad * Close all VCE handles still open by this file pointer 372 1.1 riastrad */ 373 1.1 riastrad void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) 374 1.1 riastrad { 375 1.1 riastrad int i, r; 376 1.1 riastrad for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 377 1.1 riastrad uint32_t handle = atomic_read(&rdev->vce.handles[i]); 378 1.1 riastrad if (!handle || rdev->vce.filp[i] != filp) 379 1.1 riastrad continue; 380 1.1 riastrad 381 1.1 riastrad radeon_vce_note_usage(rdev); 382 1.1 riastrad 383 1.1 riastrad r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, 384 1.1 riastrad handle, NULL); 385 1.1 riastrad if (r) 386 1.1 riastrad DRM_ERROR("Error destroying VCE handle (%d)!\n", r); 387 1.1 riastrad 388 1.1 riastrad rdev->vce.filp[i] = NULL; 389 1.1 riastrad atomic_set(&rdev->vce.handles[i], 0); 390 1.1 riastrad } 391 1.1 riastrad } 392 1.1 riastrad 393 1.1 riastrad /** 394 1.1 riastrad * radeon_vce_get_create_msg - generate a VCE create msg 395 1.1 riastrad * 396 1.1 riastrad * @rdev: radeon_device pointer 397 1.1 riastrad * @ring: ring we should submit the msg to 398 1.1 riastrad * @handle: VCE session handle to use 399 1.1 riastrad * @fence: optional fence to return 400 1.1 riastrad * 401 1.1 riastrad * Open up a stream for HW test 402 1.1 riastrad */ 403 1.1 riastrad int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, 404 1.1 riastrad uint32_t handle, struct radeon_fence **fence) 405 1.1 riastrad { 406 1.1 riastrad const unsigned ib_size_dw = 1024; 407 1.1 riastrad struct radeon_ib ib; 408 1.1 riastrad uint64_t dummy; 409 1.1 riastrad int i, r; 410 1.1 riastrad 411 1.1 riastrad r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); 412 1.1 riastrad if (r) { 413 1.1 riastrad DRM_ERROR("radeon: failed to get ib (%d).\n", r); 414 1.1 riastrad return r; 415 1.1 riastrad } 416 1.1 riastrad 417 1.1 riastrad dummy = ib.gpu_addr + 1024; 418 1.1 riastrad 419 1.1 riastrad /* stitch together an VCE create msg */ 420 1.1 riastrad ib.length_dw = 0; 421 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ 422 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ 423 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(handle); 424 1.3 riastrad 425 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000030); /* len */ 426 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x01000001); /* create cmd */ 427 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000); 428 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000042); 429 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000a); 430 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); 431 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000080); 432 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000060); 433 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100); 434 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100); 435 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); 436 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000); 437 1.3 riastrad 438 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ 439 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ 440 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); 441 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); 442 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); 443 1.1 riastrad 444 1.1 riastrad for (i = ib.length_dw; i < ib_size_dw; ++i) 445 1.3 riastrad ib.ptr[i] = cpu_to_le32(0x0); 446 1.1 riastrad 447 1.3 riastrad r = radeon_ib_schedule(rdev, &ib, NULL, false); 448 1.5 riastrad if (r) 449 1.5 riastrad DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 450 1.5 riastrad 451 1.1 riastrad 452 1.1 riastrad if (fence) 453 1.1 riastrad *fence = radeon_fence_ref(ib.fence); 454 1.1 riastrad 455 1.1 riastrad radeon_ib_free(rdev, &ib); 456 1.1 riastrad 457 1.1 riastrad return r; 458 1.1 riastrad } 459 1.1 riastrad 460 1.1 riastrad /** 461 1.1 riastrad * radeon_vce_get_destroy_msg - generate a VCE destroy msg 462 1.1 riastrad * 463 1.1 riastrad * @rdev: radeon_device pointer 464 1.1 riastrad * @ring: ring we should submit the msg to 465 1.1 riastrad * @handle: VCE session handle to use 466 1.1 riastrad * @fence: optional fence to return 467 1.1 riastrad * 468 1.1 riastrad * Close up a stream for HW test or if userspace failed to do so 469 1.1 riastrad */ 470 1.1 riastrad int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, 471 1.1 riastrad uint32_t handle, struct radeon_fence **fence) 472 1.1 riastrad { 473 1.1 riastrad const unsigned ib_size_dw = 1024; 474 1.1 riastrad struct radeon_ib ib; 475 1.1 riastrad uint64_t dummy; 476 1.1 riastrad int i, r; 477 1.1 riastrad 478 1.1 riastrad r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); 479 1.1 riastrad if (r) { 480 1.1 riastrad DRM_ERROR("radeon: failed to get ib (%d).\n", r); 481 1.1 riastrad return r; 482 1.1 riastrad } 483 1.1 riastrad 484 1.1 riastrad dummy = ib.gpu_addr + 1024; 485 1.1 riastrad 486 1.1 riastrad /* stitch together an VCE destroy msg */ 487 1.1 riastrad ib.length_dw = 0; 488 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */ 489 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */ 490 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(handle); 491 1.3 riastrad 492 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */ 493 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */ 494 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy)); 495 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(dummy); 496 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); 497 1.1 riastrad 498 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008); /* len */ 499 1.3 riastrad ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001); /* destroy cmd */ 500 1.1 riastrad 501 1.1 riastrad for (i = ib.length_dw; i < ib_size_dw; ++i) 502 1.3 riastrad ib.ptr[i] = cpu_to_le32(0x0); 503 1.1 riastrad 504 1.3 riastrad r = radeon_ib_schedule(rdev, &ib, NULL, false); 505 1.1 riastrad if (r) { 506 1.5 riastrad DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); 507 1.1 riastrad } 508 1.1 riastrad 509 1.1 riastrad if (fence) 510 1.1 riastrad *fence = radeon_fence_ref(ib.fence); 511 1.1 riastrad 512 1.1 riastrad radeon_ib_free(rdev, &ib); 513 1.1 riastrad 514 1.1 riastrad return r; 515 1.1 riastrad } 516 1.1 riastrad 517 1.1 riastrad /** 518 1.1 riastrad * radeon_vce_cs_reloc - command submission relocation 519 1.1 riastrad * 520 1.1 riastrad * @p: parser context 521 1.1 riastrad * @lo: address of lower dword 522 1.1 riastrad * @hi: address of higher dword 523 1.1 riastrad * @size: size of checker for relocation buffer 524 1.1 riastrad * 525 1.1 riastrad * Patch relocation inside command stream with real buffer address 526 1.1 riastrad */ 527 1.1 riastrad int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi, 528 1.1 riastrad unsigned size) 529 1.1 riastrad { 530 1.1 riastrad struct radeon_cs_chunk *relocs_chunk; 531 1.3 riastrad struct radeon_bo_list *reloc; 532 1.1 riastrad uint64_t start, end, offset; 533 1.1 riastrad unsigned idx; 534 1.1 riastrad 535 1.3 riastrad relocs_chunk = p->chunk_relocs; 536 1.1 riastrad offset = radeon_get_ib_value(p, lo); 537 1.1 riastrad idx = radeon_get_ib_value(p, hi); 538 1.1 riastrad 539 1.1 riastrad if (idx >= relocs_chunk->length_dw) { 540 1.1 riastrad DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", 541 1.1 riastrad idx, relocs_chunk->length_dw); 542 1.1 riastrad return -EINVAL; 543 1.1 riastrad } 544 1.1 riastrad 545 1.3 riastrad reloc = &p->relocs[(idx / 4)]; 546 1.1 riastrad start = reloc->gpu_offset; 547 1.1 riastrad end = start + radeon_bo_size(reloc->robj); 548 1.1 riastrad start += offset; 549 1.1 riastrad 550 1.1 riastrad p->ib.ptr[lo] = start & 0xFFFFFFFF; 551 1.1 riastrad p->ib.ptr[hi] = start >> 32; 552 1.1 riastrad 553 1.1 riastrad if (end <= start) { 554 1.2 riastrad DRM_ERROR("invalid reloc offset %"PRIX64"!\n", offset); 555 1.1 riastrad return -EINVAL; 556 1.1 riastrad } 557 1.1 riastrad if ((end - start) < size) { 558 1.1 riastrad DRM_ERROR("buffer to small (%d / %d)!\n", 559 1.1 riastrad (unsigned)(end - start), size); 560 1.1 riastrad return -EINVAL; 561 1.1 riastrad } 562 1.1 riastrad 563 1.1 riastrad return 0; 564 1.1 riastrad } 565 1.1 riastrad 566 1.1 riastrad /** 567 1.1 riastrad * radeon_vce_validate_handle - validate stream handle 568 1.1 riastrad * 569 1.1 riastrad * @p: parser context 570 1.1 riastrad * @handle: handle to validate 571 1.3 riastrad * @allocated: allocated a new handle? 572 1.1 riastrad * 573 1.1 riastrad * Validates the handle and return the found session index or -EINVAL 574 1.1 riastrad * we we don't have another free session index. 575 1.1 riastrad */ 576 1.3 riastrad static int radeon_vce_validate_handle(struct radeon_cs_parser *p, 577 1.3 riastrad uint32_t handle, bool *allocated) 578 1.1 riastrad { 579 1.1 riastrad unsigned i; 580 1.1 riastrad 581 1.3 riastrad *allocated = false; 582 1.3 riastrad 583 1.1 riastrad /* validate the handle */ 584 1.1 riastrad for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 585 1.3 riastrad if (atomic_read(&p->rdev->vce.handles[i]) == handle) { 586 1.3 riastrad if (p->rdev->vce.filp[i] != p->filp) { 587 1.3 riastrad DRM_ERROR("VCE handle collision detected!\n"); 588 1.3 riastrad return -EINVAL; 589 1.3 riastrad } 590 1.1 riastrad return i; 591 1.3 riastrad } 592 1.1 riastrad } 593 1.1 riastrad 594 1.1 riastrad /* handle not found try to alloc a new one */ 595 1.1 riastrad for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { 596 1.1 riastrad if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { 597 1.1 riastrad p->rdev->vce.filp[i] = p->filp; 598 1.1 riastrad p->rdev->vce.img_size[i] = 0; 599 1.3 riastrad *allocated = true; 600 1.1 riastrad return i; 601 1.1 riastrad } 602 1.1 riastrad } 603 1.1 riastrad 604 1.1 riastrad DRM_ERROR("No more free VCE handles!\n"); 605 1.1 riastrad return -EINVAL; 606 1.1 riastrad } 607 1.1 riastrad 608 1.1 riastrad /** 609 1.1 riastrad * radeon_vce_cs_parse - parse and validate the command stream 610 1.1 riastrad * 611 1.1 riastrad * @p: parser context 612 1.1 riastrad * 613 1.1 riastrad */ 614 1.1 riastrad int radeon_vce_cs_parse(struct radeon_cs_parser *p) 615 1.1 riastrad { 616 1.1 riastrad int session_idx = -1; 617 1.3 riastrad bool destroyed = false, created = false, allocated = false; 618 1.1 riastrad uint32_t tmp, handle = 0; 619 1.1 riastrad uint32_t *size = &tmp; 620 1.3 riastrad int i, r = 0; 621 1.1 riastrad 622 1.3 riastrad while (p->idx < p->chunk_ib->length_dw) { 623 1.1 riastrad uint32_t len = radeon_get_ib_value(p, p->idx); 624 1.1 riastrad uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); 625 1.1 riastrad 626 1.1 riastrad if ((len < 8) || (len & 3)) { 627 1.1 riastrad DRM_ERROR("invalid VCE command length (%d)!\n", len); 628 1.3 riastrad r = -EINVAL; 629 1.3 riastrad goto out; 630 1.1 riastrad } 631 1.1 riastrad 632 1.1 riastrad if (destroyed) { 633 1.1 riastrad DRM_ERROR("No other command allowed after destroy!\n"); 634 1.3 riastrad r = -EINVAL; 635 1.3 riastrad goto out; 636 1.1 riastrad } 637 1.1 riastrad 638 1.1 riastrad switch (cmd) { 639 1.1 riastrad case 0x00000001: // session 640 1.1 riastrad handle = radeon_get_ib_value(p, p->idx + 2); 641 1.3 riastrad session_idx = radeon_vce_validate_handle(p, handle, 642 1.3 riastrad &allocated); 643 1.1 riastrad if (session_idx < 0) 644 1.1 riastrad return session_idx; 645 1.1 riastrad size = &p->rdev->vce.img_size[session_idx]; 646 1.1 riastrad break; 647 1.1 riastrad 648 1.1 riastrad case 0x00000002: // task info 649 1.1 riastrad break; 650 1.1 riastrad 651 1.1 riastrad case 0x01000001: // create 652 1.3 riastrad created = true; 653 1.3 riastrad if (!allocated) { 654 1.3 riastrad DRM_ERROR("Handle already in use!\n"); 655 1.3 riastrad r = -EINVAL; 656 1.3 riastrad goto out; 657 1.3 riastrad } 658 1.3 riastrad 659 1.1 riastrad *size = radeon_get_ib_value(p, p->idx + 8) * 660 1.1 riastrad radeon_get_ib_value(p, p->idx + 10) * 661 1.1 riastrad 8 * 3 / 2; 662 1.1 riastrad break; 663 1.1 riastrad 664 1.1 riastrad case 0x04000001: // config extension 665 1.1 riastrad case 0x04000002: // pic control 666 1.1 riastrad case 0x04000005: // rate control 667 1.1 riastrad case 0x04000007: // motion estimation 668 1.1 riastrad case 0x04000008: // rdo 669 1.3 riastrad case 0x04000009: // vui 670 1.1 riastrad break; 671 1.1 riastrad 672 1.1 riastrad case 0x03000001: // encode 673 1.1 riastrad r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9, 674 1.1 riastrad *size); 675 1.1 riastrad if (r) 676 1.3 riastrad goto out; 677 1.1 riastrad 678 1.1 riastrad r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11, 679 1.1 riastrad *size / 3); 680 1.1 riastrad if (r) 681 1.3 riastrad goto out; 682 1.1 riastrad break; 683 1.1 riastrad 684 1.1 riastrad case 0x02000001: // destroy 685 1.1 riastrad destroyed = true; 686 1.1 riastrad break; 687 1.1 riastrad 688 1.1 riastrad case 0x05000001: // context buffer 689 1.1 riastrad r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 690 1.1 riastrad *size * 2); 691 1.1 riastrad if (r) 692 1.3 riastrad goto out; 693 1.1 riastrad break; 694 1.1 riastrad 695 1.1 riastrad case 0x05000004: // video bitstream buffer 696 1.1 riastrad tmp = radeon_get_ib_value(p, p->idx + 4); 697 1.1 riastrad r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 698 1.1 riastrad tmp); 699 1.1 riastrad if (r) 700 1.3 riastrad goto out; 701 1.1 riastrad break; 702 1.1 riastrad 703 1.1 riastrad case 0x05000005: // feedback buffer 704 1.1 riastrad r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, 705 1.1 riastrad 4096); 706 1.1 riastrad if (r) 707 1.3 riastrad goto out; 708 1.1 riastrad break; 709 1.1 riastrad 710 1.1 riastrad default: 711 1.1 riastrad DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); 712 1.3 riastrad r = -EINVAL; 713 1.3 riastrad goto out; 714 1.1 riastrad } 715 1.1 riastrad 716 1.1 riastrad if (session_idx == -1) { 717 1.1 riastrad DRM_ERROR("no session command at start of IB\n"); 718 1.3 riastrad r = -EINVAL; 719 1.3 riastrad goto out; 720 1.1 riastrad } 721 1.1 riastrad 722 1.1 riastrad p->idx += len / 4; 723 1.1 riastrad } 724 1.1 riastrad 725 1.3 riastrad if (allocated && !created) { 726 1.3 riastrad DRM_ERROR("New session without create command!\n"); 727 1.3 riastrad r = -ENOENT; 728 1.3 riastrad } 729 1.3 riastrad 730 1.3 riastrad out: 731 1.3 riastrad if ((!r && destroyed) || (r && allocated)) { 732 1.3 riastrad /* 733 1.3 riastrad * IB contains a destroy msg or we have allocated an 734 1.3 riastrad * handle and got an error, anyway free the handle 735 1.3 riastrad */ 736 1.1 riastrad for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) 737 1.1 riastrad atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0); 738 1.1 riastrad } 739 1.1 riastrad 740 1.3 riastrad return r; 741 1.1 riastrad } 742 1.1 riastrad 743 1.1 riastrad /** 744 1.1 riastrad * radeon_vce_semaphore_emit - emit a semaphore command 745 1.1 riastrad * 746 1.1 riastrad * @rdev: radeon_device pointer 747 1.1 riastrad * @ring: engine to use 748 1.1 riastrad * @semaphore: address of semaphore 749 1.1 riastrad * @emit_wait: true=emit wait, false=emit signal 750 1.1 riastrad * 751 1.1 riastrad */ 752 1.1 riastrad bool radeon_vce_semaphore_emit(struct radeon_device *rdev, 753 1.1 riastrad struct radeon_ring *ring, 754 1.1 riastrad struct radeon_semaphore *semaphore, 755 1.1 riastrad bool emit_wait) 756 1.1 riastrad { 757 1.1 riastrad uint64_t addr = semaphore->gpu_addr; 758 1.1 riastrad 759 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(VCE_CMD_SEMAPHORE)); 760 1.3 riastrad radeon_ring_write(ring, cpu_to_le32((addr >> 3) & 0x000FFFFF)); 761 1.3 riastrad radeon_ring_write(ring, cpu_to_le32((addr >> 23) & 0x000FFFFF)); 762 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(0x01003000 | (emit_wait ? 1 : 0))); 763 1.1 riastrad if (!emit_wait) 764 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); 765 1.1 riastrad 766 1.1 riastrad return true; 767 1.1 riastrad } 768 1.1 riastrad 769 1.1 riastrad /** 770 1.1 riastrad * radeon_vce_ib_execute - execute indirect buffer 771 1.1 riastrad * 772 1.1 riastrad * @rdev: radeon_device pointer 773 1.1 riastrad * @ib: the IB to execute 774 1.1 riastrad * 775 1.1 riastrad */ 776 1.1 riastrad void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) 777 1.1 riastrad { 778 1.1 riastrad struct radeon_ring *ring = &rdev->ring[ib->ring]; 779 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(VCE_CMD_IB)); 780 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(ib->gpu_addr)); 781 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(upper_32_bits(ib->gpu_addr))); 782 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(ib->length_dw)); 783 1.1 riastrad } 784 1.1 riastrad 785 1.1 riastrad /** 786 1.1 riastrad * radeon_vce_fence_emit - add a fence command to the ring 787 1.1 riastrad * 788 1.1 riastrad * @rdev: radeon_device pointer 789 1.1 riastrad * @fence: the fence 790 1.1 riastrad * 791 1.1 riastrad */ 792 1.1 riastrad void radeon_vce_fence_emit(struct radeon_device *rdev, 793 1.1 riastrad struct radeon_fence *fence) 794 1.1 riastrad { 795 1.1 riastrad struct radeon_ring *ring = &rdev->ring[fence->ring]; 796 1.1 riastrad uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; 797 1.1 riastrad 798 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(VCE_CMD_FENCE)); 799 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(addr)); 800 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(upper_32_bits(addr))); 801 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(fence->seq)); 802 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(VCE_CMD_TRAP)); 803 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); 804 1.1 riastrad } 805 1.1 riastrad 806 1.1 riastrad /** 807 1.1 riastrad * radeon_vce_ring_test - test if VCE ring is working 808 1.1 riastrad * 809 1.1 riastrad * @rdev: radeon_device pointer 810 1.1 riastrad * @ring: the engine to test on 811 1.1 riastrad * 812 1.1 riastrad */ 813 1.1 riastrad int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) 814 1.1 riastrad { 815 1.1 riastrad uint32_t rptr = vce_v1_0_get_rptr(rdev, ring); 816 1.1 riastrad unsigned i; 817 1.1 riastrad int r; 818 1.1 riastrad 819 1.1 riastrad r = radeon_ring_lock(rdev, ring, 16); 820 1.1 riastrad if (r) { 821 1.1 riastrad DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n", 822 1.1 riastrad ring->idx, r); 823 1.1 riastrad return r; 824 1.1 riastrad } 825 1.3 riastrad radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)); 826 1.3 riastrad radeon_ring_unlock_commit(rdev, ring, false); 827 1.1 riastrad 828 1.1 riastrad for (i = 0; i < rdev->usec_timeout; i++) { 829 1.5 riastrad if (vce_v1_0_get_rptr(rdev, ring) != rptr) 830 1.5 riastrad break; 831 1.5 riastrad udelay(1); 832 1.1 riastrad } 833 1.1 riastrad 834 1.1 riastrad if (i < rdev->usec_timeout) { 835 1.5 riastrad DRM_INFO("ring test on %d succeeded in %d usecs\n", 836 1.5 riastrad ring->idx, i); 837 1.1 riastrad } else { 838 1.5 riastrad DRM_ERROR("radeon: ring %d test failed\n", 839 1.5 riastrad ring->idx); 840 1.5 riastrad r = -ETIMEDOUT; 841 1.1 riastrad } 842 1.1 riastrad 843 1.1 riastrad return r; 844 1.1 riastrad } 845 1.1 riastrad 846 1.1 riastrad /** 847 1.1 riastrad * radeon_vce_ib_test - test if VCE IBs are working 848 1.1 riastrad * 849 1.1 riastrad * @rdev: radeon_device pointer 850 1.1 riastrad * @ring: the engine to test on 851 1.1 riastrad * 852 1.1 riastrad */ 853 1.1 riastrad int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) 854 1.1 riastrad { 855 1.1 riastrad struct radeon_fence *fence = NULL; 856 1.1 riastrad int r; 857 1.1 riastrad 858 1.1 riastrad r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL); 859 1.1 riastrad if (r) { 860 1.1 riastrad DRM_ERROR("radeon: failed to get create msg (%d).\n", r); 861 1.1 riastrad goto error; 862 1.1 riastrad } 863 1.1 riastrad 864 1.1 riastrad r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence); 865 1.1 riastrad if (r) { 866 1.1 riastrad DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); 867 1.1 riastrad goto error; 868 1.1 riastrad } 869 1.1 riastrad 870 1.5 riastrad r = radeon_fence_wait_timeout(fence, false, usecs_to_jiffies( 871 1.5 riastrad RADEON_USEC_IB_TEST_TIMEOUT)); 872 1.5 riastrad if (r < 0) { 873 1.1 riastrad DRM_ERROR("radeon: fence wait failed (%d).\n", r); 874 1.5 riastrad } else if (r == 0) { 875 1.5 riastrad DRM_ERROR("radeon: fence wait timed out.\n"); 876 1.5 riastrad r = -ETIMEDOUT; 877 1.1 riastrad } else { 878 1.5 riastrad DRM_INFO("ib test on ring %d succeeded\n", ring->idx); 879 1.5 riastrad r = 0; 880 1.1 riastrad } 881 1.1 riastrad error: 882 1.1 riastrad radeon_fence_unref(&fence); 883 1.1 riastrad return r; 884 1.1 riastrad } 885