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