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