xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_vce.c (revision 2b73d18af7a98bc9907041875c671f63165f1d3e)
1*2b73d18aSriastradh /*	$NetBSD: amdgpu_vce.c,v 1.7 2021/12/19 12:21:29 riastradh Exp $	*/
2efa246c0Sriastradh 
3efa246c0Sriastradh /*
4efa246c0Sriastradh  * Copyright 2013 Advanced Micro Devices, Inc.
5efa246c0Sriastradh  * All Rights Reserved.
6efa246c0Sriastradh  *
7efa246c0Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
8efa246c0Sriastradh  * copy of this software and associated documentation files (the
9efa246c0Sriastradh  * "Software"), to deal in the Software without restriction, including
10efa246c0Sriastradh  * without limitation the rights to use, copy, modify, merge, publish,
11efa246c0Sriastradh  * distribute, sub license, and/or sell copies of the Software, and to
12efa246c0Sriastradh  * permit persons to whom the Software is furnished to do so, subject to
13efa246c0Sriastradh  * the following conditions:
14efa246c0Sriastradh  *
15efa246c0Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16efa246c0Sriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17efa246c0Sriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18efa246c0Sriastradh  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
19efa246c0Sriastradh  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20efa246c0Sriastradh  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21efa246c0Sriastradh  * USE OR OTHER DEALINGS IN THE SOFTWARE.
22efa246c0Sriastradh  *
23efa246c0Sriastradh  * The above copyright notice and this permission notice (including the
24efa246c0Sriastradh  * next paragraph) shall be included in all copies or substantial portions
25efa246c0Sriastradh  * of the Software.
26efa246c0Sriastradh  *
27efa246c0Sriastradh  * Authors: Christian König <christian.koenig@amd.com>
28efa246c0Sriastradh  */
29efa246c0Sriastradh 
30efa246c0Sriastradh #include <sys/cdefs.h>
31*2b73d18aSriastradh __KERNEL_RCSID(0, "$NetBSD: amdgpu_vce.c,v 1.7 2021/12/19 12:21:29 riastradh Exp $");
32efa246c0Sriastradh 
33efa246c0Sriastradh #include <linux/firmware.h>
34efa246c0Sriastradh #include <linux/module.h>
3541ec0267Sriastradh 
36efa246c0Sriastradh #include <drm/drm.h>
37efa246c0Sriastradh 
38efa246c0Sriastradh #include "amdgpu.h"
39efa246c0Sriastradh #include "amdgpu_pm.h"
40efa246c0Sriastradh #include "amdgpu_vce.h"
41efa246c0Sriastradh #include "cikd.h"
42efa246c0Sriastradh 
43*2b73d18aSriastradh #include <linux/nbsd-namespace.h>
44*2b73d18aSriastradh 
45efa246c0Sriastradh /* 1 second timeout */
4641ec0267Sriastradh #define VCE_IDLE_TIMEOUT	msecs_to_jiffies(1000)
47efa246c0Sriastradh 
48efa246c0Sriastradh /* Firmware Names */
49efa246c0Sriastradh #ifdef CONFIG_DRM_AMDGPU_CIK
5041ec0267Sriastradh #define FIRMWARE_BONAIRE	"amdgpu/bonaire_vce.bin"
5141ec0267Sriastradh #define FIRMWARE_KABINI	"amdgpu/kabini_vce.bin"
5241ec0267Sriastradh #define FIRMWARE_KAVERI	"amdgpu/kaveri_vce.bin"
5341ec0267Sriastradh #define FIRMWARE_HAWAII	"amdgpu/hawaii_vce.bin"
5441ec0267Sriastradh #define FIRMWARE_MULLINS	"amdgpu/mullins_vce.bin"
55efa246c0Sriastradh #endif
56efa246c0Sriastradh #define FIRMWARE_TONGA		"amdgpu/tonga_vce.bin"
57efa246c0Sriastradh #define FIRMWARE_CARRIZO	"amdgpu/carrizo_vce.bin"
58efa246c0Sriastradh #define FIRMWARE_FIJI		"amdgpu/fiji_vce.bin"
59efa246c0Sriastradh #define FIRMWARE_STONEY		"amdgpu/stoney_vce.bin"
6041ec0267Sriastradh #define FIRMWARE_POLARIS10	"amdgpu/polaris10_vce.bin"
6141ec0267Sriastradh #define FIRMWARE_POLARIS11	"amdgpu/polaris11_vce.bin"
6241ec0267Sriastradh #define FIRMWARE_POLARIS12	"amdgpu/polaris12_vce.bin"
6341ec0267Sriastradh #define FIRMWARE_VEGAM		"amdgpu/vegam_vce.bin"
6441ec0267Sriastradh 
6541ec0267Sriastradh #define FIRMWARE_VEGA10		"amdgpu/vega10_vce.bin"
6641ec0267Sriastradh #define FIRMWARE_VEGA12		"amdgpu/vega12_vce.bin"
6741ec0267Sriastradh #define FIRMWARE_VEGA20		"amdgpu/vega20_vce.bin"
68efa246c0Sriastradh 
69efa246c0Sriastradh #ifdef CONFIG_DRM_AMDGPU_CIK
70efa246c0Sriastradh MODULE_FIRMWARE(FIRMWARE_BONAIRE);
71efa246c0Sriastradh MODULE_FIRMWARE(FIRMWARE_KABINI);
72efa246c0Sriastradh MODULE_FIRMWARE(FIRMWARE_KAVERI);
73efa246c0Sriastradh MODULE_FIRMWARE(FIRMWARE_HAWAII);
74efa246c0Sriastradh MODULE_FIRMWARE(FIRMWARE_MULLINS);
75efa246c0Sriastradh #endif
76efa246c0Sriastradh MODULE_FIRMWARE(FIRMWARE_TONGA);
77efa246c0Sriastradh MODULE_FIRMWARE(FIRMWARE_CARRIZO);
78efa246c0Sriastradh MODULE_FIRMWARE(FIRMWARE_FIJI);
79efa246c0Sriastradh MODULE_FIRMWARE(FIRMWARE_STONEY);
8041ec0267Sriastradh MODULE_FIRMWARE(FIRMWARE_POLARIS10);
8141ec0267Sriastradh MODULE_FIRMWARE(FIRMWARE_POLARIS11);
8241ec0267Sriastradh MODULE_FIRMWARE(FIRMWARE_POLARIS12);
8341ec0267Sriastradh MODULE_FIRMWARE(FIRMWARE_VEGAM);
8441ec0267Sriastradh 
8541ec0267Sriastradh MODULE_FIRMWARE(FIRMWARE_VEGA10);
8641ec0267Sriastradh MODULE_FIRMWARE(FIRMWARE_VEGA12);
8741ec0267Sriastradh MODULE_FIRMWARE(FIRMWARE_VEGA20);
88efa246c0Sriastradh 
89efa246c0Sriastradh static void amdgpu_vce_idle_work_handler(struct work_struct *work);
9041ec0267Sriastradh static int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
9141ec0267Sriastradh 				     struct amdgpu_bo *bo,
9241ec0267Sriastradh 				     struct dma_fence **fence);
9341ec0267Sriastradh static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
9441ec0267Sriastradh 				      bool direct, struct dma_fence **fence);
95efa246c0Sriastradh 
96efa246c0Sriastradh /**
97efa246c0Sriastradh  * amdgpu_vce_init - allocate memory, load vce firmware
98efa246c0Sriastradh  *
99efa246c0Sriastradh  * @adev: amdgpu_device pointer
100efa246c0Sriastradh  *
101efa246c0Sriastradh  * First step to get VCE online, allocate memory and load the firmware
102efa246c0Sriastradh  */
amdgpu_vce_sw_init(struct amdgpu_device * adev,unsigned long size)103efa246c0Sriastradh int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
104efa246c0Sriastradh {
105efa246c0Sriastradh 	const char *fw_name;
106efa246c0Sriastradh 	const struct common_firmware_header *hdr;
107efa246c0Sriastradh 	unsigned ucode_version, version_major, version_minor, binary_id;
108efa246c0Sriastradh 	int i, r;
109efa246c0Sriastradh 
110efa246c0Sriastradh 	switch (adev->asic_type) {
111efa246c0Sriastradh #ifdef CONFIG_DRM_AMDGPU_CIK
112efa246c0Sriastradh 	case CHIP_BONAIRE:
113efa246c0Sriastradh 		fw_name = FIRMWARE_BONAIRE;
114efa246c0Sriastradh 		break;
115efa246c0Sriastradh 	case CHIP_KAVERI:
116efa246c0Sriastradh 		fw_name = FIRMWARE_KAVERI;
117efa246c0Sriastradh 		break;
118efa246c0Sriastradh 	case CHIP_KABINI:
119efa246c0Sriastradh 		fw_name = FIRMWARE_KABINI;
120efa246c0Sriastradh 		break;
121efa246c0Sriastradh 	case CHIP_HAWAII:
122efa246c0Sriastradh 		fw_name = FIRMWARE_HAWAII;
123efa246c0Sriastradh 		break;
124efa246c0Sriastradh 	case CHIP_MULLINS:
125efa246c0Sriastradh 		fw_name = FIRMWARE_MULLINS;
126efa246c0Sriastradh 		break;
127efa246c0Sriastradh #endif
128efa246c0Sriastradh 	case CHIP_TONGA:
129efa246c0Sriastradh 		fw_name = FIRMWARE_TONGA;
130efa246c0Sriastradh 		break;
131efa246c0Sriastradh 	case CHIP_CARRIZO:
132efa246c0Sriastradh 		fw_name = FIRMWARE_CARRIZO;
133efa246c0Sriastradh 		break;
134efa246c0Sriastradh 	case CHIP_FIJI:
135efa246c0Sriastradh 		fw_name = FIRMWARE_FIJI;
136efa246c0Sriastradh 		break;
137efa246c0Sriastradh 	case CHIP_STONEY:
138efa246c0Sriastradh 		fw_name = FIRMWARE_STONEY;
139efa246c0Sriastradh 		break;
14041ec0267Sriastradh 	case CHIP_POLARIS10:
14141ec0267Sriastradh 		fw_name = FIRMWARE_POLARIS10;
14241ec0267Sriastradh 		break;
14341ec0267Sriastradh 	case CHIP_POLARIS11:
14441ec0267Sriastradh 		fw_name = FIRMWARE_POLARIS11;
14541ec0267Sriastradh 		break;
14641ec0267Sriastradh 	case CHIP_POLARIS12:
14741ec0267Sriastradh 		fw_name = FIRMWARE_POLARIS12;
14841ec0267Sriastradh 		break;
14941ec0267Sriastradh 	case CHIP_VEGAM:
15041ec0267Sriastradh 		fw_name = FIRMWARE_VEGAM;
15141ec0267Sriastradh 		break;
15241ec0267Sriastradh 	case CHIP_VEGA10:
15341ec0267Sriastradh 		fw_name = FIRMWARE_VEGA10;
15441ec0267Sriastradh 		break;
15541ec0267Sriastradh 	case CHIP_VEGA12:
15641ec0267Sriastradh 		fw_name = FIRMWARE_VEGA12;
15741ec0267Sriastradh 		break;
15841ec0267Sriastradh 	case CHIP_VEGA20:
15941ec0267Sriastradh 		fw_name = FIRMWARE_VEGA20;
16041ec0267Sriastradh 		break;
161efa246c0Sriastradh 
162efa246c0Sriastradh 	default:
163efa246c0Sriastradh 		return -EINVAL;
164efa246c0Sriastradh 	}
165efa246c0Sriastradh 
166efa246c0Sriastradh 	r = request_firmware(&adev->vce.fw, fw_name, adev->dev);
167efa246c0Sriastradh 	if (r) {
168efa246c0Sriastradh 		dev_err(adev->dev, "amdgpu_vce: Can't load firmware \"%s\"\n",
169efa246c0Sriastradh 			fw_name);
170efa246c0Sriastradh 		return r;
171efa246c0Sriastradh 	}
172efa246c0Sriastradh 
173efa246c0Sriastradh 	r = amdgpu_ucode_validate(adev->vce.fw);
174efa246c0Sriastradh 	if (r) {
175efa246c0Sriastradh 		dev_err(adev->dev, "amdgpu_vce: Can't validate firmware \"%s\"\n",
176efa246c0Sriastradh 			fw_name);
177efa246c0Sriastradh 		release_firmware(adev->vce.fw);
178efa246c0Sriastradh 		adev->vce.fw = NULL;
179efa246c0Sriastradh 		return r;
180efa246c0Sriastradh 	}
181efa246c0Sriastradh 
182efa246c0Sriastradh 	hdr = (const struct common_firmware_header *)adev->vce.fw->data;
183efa246c0Sriastradh 
184efa246c0Sriastradh 	ucode_version = le32_to_cpu(hdr->ucode_version);
185efa246c0Sriastradh 	version_major = (ucode_version >> 20) & 0xfff;
186efa246c0Sriastradh 	version_minor = (ucode_version >> 8) & 0xfff;
187efa246c0Sriastradh 	binary_id = ucode_version & 0xff;
1889d096b74Smaya 	DRM_INFO("Found VCE firmware Version: %x.%x Binary ID: %x\n",
189efa246c0Sriastradh 		version_major, version_minor, binary_id);
190efa246c0Sriastradh 	adev->vce.fw_version = ((version_major << 24) | (version_minor << 16) |
191efa246c0Sriastradh 				(binary_id << 8));
192efa246c0Sriastradh 
19341ec0267Sriastradh 	r = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE,
19441ec0267Sriastradh 				    AMDGPU_GEM_DOMAIN_VRAM, &adev->vce.vcpu_bo,
19541ec0267Sriastradh 				    &adev->vce.gpu_addr, &adev->vce.cpu_addr);
196efa246c0Sriastradh 	if (r) {
197efa246c0Sriastradh 		dev_err(adev->dev, "(%d) failed to allocate VCE bo\n", r);
198efa246c0Sriastradh 		return r;
199efa246c0Sriastradh 	}
200efa246c0Sriastradh 
201efa246c0Sriastradh 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
202efa246c0Sriastradh 		atomic_set(&adev->vce.handles[i], 0);
203efa246c0Sriastradh 		adev->vce.filp[i] = NULL;
204efa246c0Sriastradh 	}
205efa246c0Sriastradh 
20641ec0267Sriastradh 	INIT_DELAYED_WORK(&adev->vce.idle_work, amdgpu_vce_idle_work_handler);
20741ec0267Sriastradh 	mutex_init(&adev->vce.idle_mutex);
20841ec0267Sriastradh 
209efa246c0Sriastradh 	return 0;
210efa246c0Sriastradh }
211efa246c0Sriastradh 
212efa246c0Sriastradh /**
213efa246c0Sriastradh  * amdgpu_vce_fini - free memory
214efa246c0Sriastradh  *
215efa246c0Sriastradh  * @adev: amdgpu_device pointer
216efa246c0Sriastradh  *
217efa246c0Sriastradh  * Last step on VCE teardown, free firmware memory
218efa246c0Sriastradh  */
amdgpu_vce_sw_fini(struct amdgpu_device * adev)219efa246c0Sriastradh int amdgpu_vce_sw_fini(struct amdgpu_device *adev)
220efa246c0Sriastradh {
22141ec0267Sriastradh 	unsigned i;
22241ec0267Sriastradh 
223efa246c0Sriastradh 	if (adev->vce.vcpu_bo == NULL)
224efa246c0Sriastradh 		return 0;
225efa246c0Sriastradh 
22641ec0267Sriastradh 	cancel_delayed_work_sync(&adev->vce.idle_work);
22741ec0267Sriastradh 	drm_sched_entity_destroy(&adev->vce.entity);
228efa246c0Sriastradh 
22941ec0267Sriastradh 	amdgpu_bo_free_kernel(&adev->vce.vcpu_bo, &adev->vce.gpu_addr,
23041ec0267Sriastradh 		(void **)&adev->vce.cpu_addr);
23141ec0267Sriastradh 
23241ec0267Sriastradh 	for (i = 0; i < adev->vce.num_rings; i++)
23341ec0267Sriastradh 		amdgpu_ring_fini(&adev->vce.ring[i]);
234efa246c0Sriastradh 
235efa246c0Sriastradh 	release_firmware(adev->vce.fw);
23641ec0267Sriastradh 	mutex_destroy(&adev->vce.idle_mutex);
23741ec0267Sriastradh 
23841ec0267Sriastradh 	return 0;
23941ec0267Sriastradh }
24041ec0267Sriastradh 
24141ec0267Sriastradh /**
24241ec0267Sriastradh  * amdgpu_vce_entity_init - init entity
24341ec0267Sriastradh  *
24441ec0267Sriastradh  * @adev: amdgpu_device pointer
24541ec0267Sriastradh  *
24641ec0267Sriastradh  */
amdgpu_vce_entity_init(struct amdgpu_device * adev)24741ec0267Sriastradh int amdgpu_vce_entity_init(struct amdgpu_device *adev)
24841ec0267Sriastradh {
24941ec0267Sriastradh 	struct amdgpu_ring *ring;
25041ec0267Sriastradh 	struct drm_gpu_scheduler *sched;
25141ec0267Sriastradh 	int r;
25241ec0267Sriastradh 
25341ec0267Sriastradh 	ring = &adev->vce.ring[0];
25441ec0267Sriastradh 	sched = &ring->sched;
25541ec0267Sriastradh 	r = drm_sched_entity_init(&adev->vce.entity, DRM_SCHED_PRIORITY_NORMAL,
25641ec0267Sriastradh 				  &sched, 1, NULL);
25741ec0267Sriastradh 	if (r != 0) {
25841ec0267Sriastradh 		DRM_ERROR("Failed setting up VCE run queue.\n");
25941ec0267Sriastradh 		return r;
26041ec0267Sriastradh 	}
261efa246c0Sriastradh 
262efa246c0Sriastradh 	return 0;
263efa246c0Sriastradh }
264efa246c0Sriastradh 
265efa246c0Sriastradh /**
266efa246c0Sriastradh  * amdgpu_vce_suspend - unpin VCE fw memory
267efa246c0Sriastradh  *
268efa246c0Sriastradh  * @adev: amdgpu_device pointer
269efa246c0Sriastradh  *
270efa246c0Sriastradh  */
amdgpu_vce_suspend(struct amdgpu_device * adev)271efa246c0Sriastradh int amdgpu_vce_suspend(struct amdgpu_device *adev)
272efa246c0Sriastradh {
273efa246c0Sriastradh 	int i;
274efa246c0Sriastradh 
27541ec0267Sriastradh 	cancel_delayed_work_sync(&adev->vce.idle_work);
27641ec0267Sriastradh 
277efa246c0Sriastradh 	if (adev->vce.vcpu_bo == NULL)
278efa246c0Sriastradh 		return 0;
279efa246c0Sriastradh 
280efa246c0Sriastradh 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
281efa246c0Sriastradh 		if (atomic_read(&adev->vce.handles[i]))
282efa246c0Sriastradh 			break;
283efa246c0Sriastradh 
284efa246c0Sriastradh 	if (i == AMDGPU_MAX_VCE_HANDLES)
285efa246c0Sriastradh 		return 0;
286efa246c0Sriastradh 
287efa246c0Sriastradh 	/* TODO: suspending running encoding sessions isn't supported */
288efa246c0Sriastradh 	return -EINVAL;
289efa246c0Sriastradh }
290efa246c0Sriastradh 
291efa246c0Sriastradh /**
292efa246c0Sriastradh  * amdgpu_vce_resume - pin VCE fw memory
293efa246c0Sriastradh  *
294efa246c0Sriastradh  * @adev: amdgpu_device pointer
295efa246c0Sriastradh  *
296efa246c0Sriastradh  */
amdgpu_vce_resume(struct amdgpu_device * adev)297efa246c0Sriastradh int amdgpu_vce_resume(struct amdgpu_device *adev)
298efa246c0Sriastradh {
299efa246c0Sriastradh 	void *cpu_addr;
300efa246c0Sriastradh 	const struct common_firmware_header *hdr;
301efa246c0Sriastradh 	unsigned offset;
302efa246c0Sriastradh 	int r;
303efa246c0Sriastradh 
304efa246c0Sriastradh 	if (adev->vce.vcpu_bo == NULL)
305efa246c0Sriastradh 		return -EINVAL;
306efa246c0Sriastradh 
307efa246c0Sriastradh 	r = amdgpu_bo_reserve(adev->vce.vcpu_bo, false);
308efa246c0Sriastradh 	if (r) {
309efa246c0Sriastradh 		dev_err(adev->dev, "(%d) failed to reserve VCE bo\n", r);
310efa246c0Sriastradh 		return r;
311efa246c0Sriastradh 	}
312efa246c0Sriastradh 
313efa246c0Sriastradh 	r = amdgpu_bo_kmap(adev->vce.vcpu_bo, &cpu_addr);
314efa246c0Sriastradh 	if (r) {
315efa246c0Sriastradh 		amdgpu_bo_unreserve(adev->vce.vcpu_bo);
316efa246c0Sriastradh 		dev_err(adev->dev, "(%d) VCE map failed\n", r);
317efa246c0Sriastradh 		return r;
318efa246c0Sriastradh 	}
319efa246c0Sriastradh 
320efa246c0Sriastradh 	hdr = (const struct common_firmware_header *)adev->vce.fw->data;
321efa246c0Sriastradh 	offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
32241ec0267Sriastradh 	memcpy_toio(cpu_addr, adev->vce.fw->data + offset,
32341ec0267Sriastradh 		    adev->vce.fw->size - offset);
324efa246c0Sriastradh 
325efa246c0Sriastradh 	amdgpu_bo_kunmap(adev->vce.vcpu_bo);
326efa246c0Sriastradh 
327efa246c0Sriastradh 	amdgpu_bo_unreserve(adev->vce.vcpu_bo);
328efa246c0Sriastradh 
329efa246c0Sriastradh 	return 0;
330efa246c0Sriastradh }
331efa246c0Sriastradh 
332efa246c0Sriastradh /**
333efa246c0Sriastradh  * amdgpu_vce_idle_work_handler - power off VCE
334efa246c0Sriastradh  *
335efa246c0Sriastradh  * @work: pointer to work structure
336efa246c0Sriastradh  *
337efa246c0Sriastradh  * power of VCE when it's not used any more
338efa246c0Sriastradh  */
amdgpu_vce_idle_work_handler(struct work_struct * work)339efa246c0Sriastradh static void amdgpu_vce_idle_work_handler(struct work_struct *work)
340efa246c0Sriastradh {
341efa246c0Sriastradh 	struct amdgpu_device *adev =
342efa246c0Sriastradh 		container_of(work, struct amdgpu_device, vce.idle_work.work);
34341ec0267Sriastradh 	unsigned i, count = 0;
344efa246c0Sriastradh 
34541ec0267Sriastradh 	for (i = 0; i < adev->vce.num_rings; i++)
34641ec0267Sriastradh 		count += amdgpu_fence_count_emitted(&adev->vce.ring[i]);
34741ec0267Sriastradh 
34841ec0267Sriastradh 	if (count == 0) {
349efa246c0Sriastradh 		if (adev->pm.dpm_enabled) {
350efa246c0Sriastradh 			amdgpu_dpm_enable_vce(adev, false);
351efa246c0Sriastradh 		} else {
352efa246c0Sriastradh 			amdgpu_asic_set_vce_clocks(adev, 0, 0);
35341ec0267Sriastradh 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
354efa246c0Sriastradh 							       AMD_PG_STATE_GATE);
35541ec0267Sriastradh 			amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
356efa246c0Sriastradh 							       AMD_CG_STATE_GATE);
357efa246c0Sriastradh 		}
358efa246c0Sriastradh 	} else {
35941ec0267Sriastradh 		schedule_delayed_work(&adev->vce.idle_work, VCE_IDLE_TIMEOUT);
360efa246c0Sriastradh 	}
361efa246c0Sriastradh }
362efa246c0Sriastradh 
363efa246c0Sriastradh /**
36441ec0267Sriastradh  * amdgpu_vce_ring_begin_use - power up VCE
365efa246c0Sriastradh  *
36641ec0267Sriastradh  * @ring: amdgpu ring
367efa246c0Sriastradh  *
368efa246c0Sriastradh  * Make sure VCE is powerd up when we want to use it
369efa246c0Sriastradh  */
amdgpu_vce_ring_begin_use(struct amdgpu_ring * ring)37041ec0267Sriastradh void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring)
371efa246c0Sriastradh {
37241ec0267Sriastradh 	struct amdgpu_device *adev = ring->adev;
37341ec0267Sriastradh 	bool set_clocks;
374efa246c0Sriastradh 
37541ec0267Sriastradh 	if (amdgpu_sriov_vf(adev))
37641ec0267Sriastradh 		return;
377efa246c0Sriastradh 
37841ec0267Sriastradh 	mutex_lock(&adev->vce.idle_mutex);
37941ec0267Sriastradh 	set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work);
38041ec0267Sriastradh 	if (set_clocks) {
381efa246c0Sriastradh 		if (adev->pm.dpm_enabled) {
382efa246c0Sriastradh 			amdgpu_dpm_enable_vce(adev, true);
383efa246c0Sriastradh 		} else {
384efa246c0Sriastradh 			amdgpu_asic_set_vce_clocks(adev, 53300, 40000);
38541ec0267Sriastradh 			amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
386efa246c0Sriastradh 							       AMD_CG_STATE_UNGATE);
38741ec0267Sriastradh 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
388efa246c0Sriastradh 							       AMD_PG_STATE_UNGATE);
389efa246c0Sriastradh 
390efa246c0Sriastradh 		}
391efa246c0Sriastradh 	}
39241ec0267Sriastradh 	mutex_unlock(&adev->vce.idle_mutex);
39341ec0267Sriastradh }
39441ec0267Sriastradh 
39541ec0267Sriastradh /**
39641ec0267Sriastradh  * amdgpu_vce_ring_end_use - power VCE down
39741ec0267Sriastradh  *
39841ec0267Sriastradh  * @ring: amdgpu ring
39941ec0267Sriastradh  *
40041ec0267Sriastradh  * Schedule work to power VCE down again
40141ec0267Sriastradh  */
amdgpu_vce_ring_end_use(struct amdgpu_ring * ring)40241ec0267Sriastradh void amdgpu_vce_ring_end_use(struct amdgpu_ring *ring)
40341ec0267Sriastradh {
40441ec0267Sriastradh 	if (!amdgpu_sriov_vf(ring->adev))
40541ec0267Sriastradh 		schedule_delayed_work(&ring->adev->vce.idle_work, VCE_IDLE_TIMEOUT);
406efa246c0Sriastradh }
407efa246c0Sriastradh 
408efa246c0Sriastradh /**
409efa246c0Sriastradh  * amdgpu_vce_free_handles - free still open VCE handles
410efa246c0Sriastradh  *
411efa246c0Sriastradh  * @adev: amdgpu_device pointer
412efa246c0Sriastradh  * @filp: drm file pointer
413efa246c0Sriastradh  *
414efa246c0Sriastradh  * Close all VCE handles still open by this file pointer
415efa246c0Sriastradh  */
amdgpu_vce_free_handles(struct amdgpu_device * adev,struct drm_file * filp)416efa246c0Sriastradh void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
417efa246c0Sriastradh {
418efa246c0Sriastradh 	struct amdgpu_ring *ring = &adev->vce.ring[0];
419efa246c0Sriastradh 	int i, r;
420efa246c0Sriastradh 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
421efa246c0Sriastradh 		uint32_t handle = atomic_read(&adev->vce.handles[i]);
42241ec0267Sriastradh 
423efa246c0Sriastradh 		if (!handle || adev->vce.filp[i] != filp)
424efa246c0Sriastradh 			continue;
425efa246c0Sriastradh 
42641ec0267Sriastradh 		r = amdgpu_vce_get_destroy_msg(ring, handle, false, NULL);
427efa246c0Sriastradh 		if (r)
428efa246c0Sriastradh 			DRM_ERROR("Error destroying VCE handle (%d)!\n", r);
429efa246c0Sriastradh 
430efa246c0Sriastradh 		adev->vce.filp[i] = NULL;
431efa246c0Sriastradh 		atomic_set(&adev->vce.handles[i], 0);
432efa246c0Sriastradh 	}
433efa246c0Sriastradh }
434efa246c0Sriastradh 
435efa246c0Sriastradh /**
436efa246c0Sriastradh  * amdgpu_vce_get_create_msg - generate a VCE create msg
437efa246c0Sriastradh  *
438efa246c0Sriastradh  * @adev: amdgpu_device pointer
439efa246c0Sriastradh  * @ring: ring we should submit the msg to
440efa246c0Sriastradh  * @handle: VCE session handle to use
441efa246c0Sriastradh  * @fence: optional fence to return
442efa246c0Sriastradh  *
443efa246c0Sriastradh  * Open up a stream for HW test
444efa246c0Sriastradh  */
amdgpu_vce_get_create_msg(struct amdgpu_ring * ring,uint32_t handle,struct amdgpu_bo * bo,struct dma_fence ** fence)44541ec0267Sriastradh static int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
44641ec0267Sriastradh 				     struct amdgpu_bo *bo,
44741ec0267Sriastradh 				     struct dma_fence **fence)
448efa246c0Sriastradh {
449efa246c0Sriastradh 	const unsigned ib_size_dw = 1024;
45041ec0267Sriastradh 	struct amdgpu_job *job;
45141ec0267Sriastradh 	struct amdgpu_ib *ib;
45241ec0267Sriastradh 	struct dma_fence *f = NULL;
45341ec0267Sriastradh 	uint64_t addr;
454efa246c0Sriastradh 	int i, r;
455efa246c0Sriastradh 
45641ec0267Sriastradh 	r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job);
45741ec0267Sriastradh 	if (r)
458efa246c0Sriastradh 		return r;
459efa246c0Sriastradh 
46041ec0267Sriastradh 	ib = &job->ibs[0];
46141ec0267Sriastradh 
46241ec0267Sriastradh 	addr = amdgpu_bo_gpu_offset(bo);
463efa246c0Sriastradh 
464efa246c0Sriastradh 	/* stitch together an VCE create msg */
465efa246c0Sriastradh 	ib->length_dw = 0;
466efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x0000000c; /* len */
467efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
468efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = handle;
469efa246c0Sriastradh 
470efa246c0Sriastradh 	if ((ring->adev->vce.fw_version >> 24) >= 52)
471efa246c0Sriastradh 		ib->ptr[ib->length_dw++] = 0x00000040; /* len */
472efa246c0Sriastradh 	else
473efa246c0Sriastradh 		ib->ptr[ib->length_dw++] = 0x00000030; /* len */
474efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x01000001; /* create cmd */
475efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000000;
476efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000042;
477efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x0000000a;
478efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000001;
479efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000080;
480efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000060;
481efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000100;
482efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000100;
483efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x0000000c;
484efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000000;
485efa246c0Sriastradh 	if ((ring->adev->vce.fw_version >> 24) >= 52) {
486efa246c0Sriastradh 		ib->ptr[ib->length_dw++] = 0x00000000;
487efa246c0Sriastradh 		ib->ptr[ib->length_dw++] = 0x00000000;
488efa246c0Sriastradh 		ib->ptr[ib->length_dw++] = 0x00000000;
489efa246c0Sriastradh 		ib->ptr[ib->length_dw++] = 0x00000000;
490efa246c0Sriastradh 	}
491efa246c0Sriastradh 
492efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000014; /* len */
493efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */
49441ec0267Sriastradh 	ib->ptr[ib->length_dw++] = upper_32_bits(addr);
49541ec0267Sriastradh 	ib->ptr[ib->length_dw++] = addr;
496efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000001;
497efa246c0Sriastradh 
498efa246c0Sriastradh 	for (i = ib->length_dw; i < ib_size_dw; ++i)
499efa246c0Sriastradh 		ib->ptr[i] = 0x0;
500efa246c0Sriastradh 
50141ec0267Sriastradh 	r = amdgpu_job_submit_direct(job, ring, &f);
502efa246c0Sriastradh 	if (r)
503efa246c0Sriastradh 		goto err;
50441ec0267Sriastradh 
505efa246c0Sriastradh 	if (fence)
50641ec0267Sriastradh 		*fence = dma_fence_get(f);
50741ec0267Sriastradh 	dma_fence_put(f);
508efa246c0Sriastradh 	return 0;
50941ec0267Sriastradh 
510efa246c0Sriastradh err:
51141ec0267Sriastradh 	amdgpu_job_free(job);
512efa246c0Sriastradh 	return r;
513efa246c0Sriastradh }
514efa246c0Sriastradh 
515efa246c0Sriastradh /**
516efa246c0Sriastradh  * amdgpu_vce_get_destroy_msg - generate a VCE destroy msg
517efa246c0Sriastradh  *
518efa246c0Sriastradh  * @adev: amdgpu_device pointer
519efa246c0Sriastradh  * @ring: ring we should submit the msg to
520efa246c0Sriastradh  * @handle: VCE session handle to use
521efa246c0Sriastradh  * @fence: optional fence to return
522efa246c0Sriastradh  *
523efa246c0Sriastradh  * Close up a stream for HW test or if userspace failed to do so
524efa246c0Sriastradh  */
amdgpu_vce_get_destroy_msg(struct amdgpu_ring * ring,uint32_t handle,bool direct,struct dma_fence ** fence)52541ec0267Sriastradh static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
52641ec0267Sriastradh 				      bool direct, struct dma_fence **fence)
527efa246c0Sriastradh {
528efa246c0Sriastradh 	const unsigned ib_size_dw = 1024;
52941ec0267Sriastradh 	struct amdgpu_job *job;
53041ec0267Sriastradh 	struct amdgpu_ib *ib;
53141ec0267Sriastradh 	struct dma_fence *f = NULL;
532efa246c0Sriastradh 	int i, r;
533efa246c0Sriastradh 
53441ec0267Sriastradh 	r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job);
53541ec0267Sriastradh 	if (r)
536efa246c0Sriastradh 		return r;
537efa246c0Sriastradh 
53841ec0267Sriastradh 	ib = &job->ibs[0];
539efa246c0Sriastradh 
540efa246c0Sriastradh 	/* stitch together an VCE destroy msg */
541efa246c0Sriastradh 	ib->length_dw = 0;
542efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x0000000c; /* len */
543efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
544efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = handle;
545efa246c0Sriastradh 
54641ec0267Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000020; /* len */
54741ec0267Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000002; /* task info */
54841ec0267Sriastradh 	ib->ptr[ib->length_dw++] = 0xffffffff; /* next task info, set to 0xffffffff if no */
54941ec0267Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000001; /* destroy session */
55041ec0267Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000000;
55141ec0267Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000000;
55241ec0267Sriastradh 	ib->ptr[ib->length_dw++] = 0xffffffff; /* feedback is not needed, set to 0xffffffff and firmware will not output feedback */
55341ec0267Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000000;
554efa246c0Sriastradh 
555efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x00000008; /* len */
556efa246c0Sriastradh 	ib->ptr[ib->length_dw++] = 0x02000001; /* destroy cmd */
557efa246c0Sriastradh 
558efa246c0Sriastradh 	for (i = ib->length_dw; i < ib_size_dw; ++i)
559efa246c0Sriastradh 		ib->ptr[i] = 0x0;
56041ec0267Sriastradh 
56141ec0267Sriastradh 	if (direct)
56241ec0267Sriastradh 		r = amdgpu_job_submit_direct(job, ring, &f);
56341ec0267Sriastradh 	else
56441ec0267Sriastradh 		r = amdgpu_job_submit(job, &ring->adev->vce.entity,
56541ec0267Sriastradh 				      AMDGPU_FENCE_OWNER_UNDEFINED, &f);
566efa246c0Sriastradh 	if (r)
567efa246c0Sriastradh 		goto err;
56841ec0267Sriastradh 
569efa246c0Sriastradh 	if (fence)
57041ec0267Sriastradh 		*fence = dma_fence_get(f);
57141ec0267Sriastradh 	dma_fence_put(f);
572efa246c0Sriastradh 	return 0;
57341ec0267Sriastradh 
574efa246c0Sriastradh err:
57541ec0267Sriastradh 	amdgpu_job_free(job);
576efa246c0Sriastradh 	return r;
577efa246c0Sriastradh }
578efa246c0Sriastradh 
579efa246c0Sriastradh /**
58041ec0267Sriastradh  * amdgpu_vce_cs_validate_bo - make sure not to cross 4GB boundary
58141ec0267Sriastradh  *
58241ec0267Sriastradh  * @p: parser context
58341ec0267Sriastradh  * @lo: address of lower dword
58441ec0267Sriastradh  * @hi: address of higher dword
58541ec0267Sriastradh  * @size: minimum size
58641ec0267Sriastradh  * @index: bs/fb index
58741ec0267Sriastradh  *
58841ec0267Sriastradh  * Make sure that no BO cross a 4GB boundary.
58941ec0267Sriastradh  */
amdgpu_vce_validate_bo(struct amdgpu_cs_parser * p,uint32_t ib_idx,int lo,int hi,unsigned size,int32_t index)59041ec0267Sriastradh static int amdgpu_vce_validate_bo(struct amdgpu_cs_parser *p, uint32_t ib_idx,
59141ec0267Sriastradh 				  int lo, int hi, unsigned size, int32_t index)
59241ec0267Sriastradh {
59341ec0267Sriastradh 	int64_t offset = ((uint64_t)size) * ((int64_t)index);
59441ec0267Sriastradh 	struct ttm_operation_ctx ctx = { false, false };
59541ec0267Sriastradh 	struct amdgpu_bo_va_mapping *mapping;
59641ec0267Sriastradh 	unsigned i, fpfn, lpfn;
59741ec0267Sriastradh 	struct amdgpu_bo *bo;
59841ec0267Sriastradh 	uint64_t addr;
59941ec0267Sriastradh 	int r;
60041ec0267Sriastradh 
60141ec0267Sriastradh 	addr = ((uint64_t)amdgpu_get_ib_value(p, ib_idx, lo)) |
60241ec0267Sriastradh 	       ((uint64_t)amdgpu_get_ib_value(p, ib_idx, hi)) << 32;
60341ec0267Sriastradh 	if (index >= 0) {
60441ec0267Sriastradh 		addr += offset;
60541ec0267Sriastradh 		fpfn = PAGE_ALIGN(offset) >> PAGE_SHIFT;
60641ec0267Sriastradh 		lpfn = 0x100000000ULL >> PAGE_SHIFT;
60741ec0267Sriastradh 	} else {
60841ec0267Sriastradh 		fpfn = 0;
60941ec0267Sriastradh 		lpfn = (0x100000000ULL - PAGE_ALIGN(offset)) >> PAGE_SHIFT;
61041ec0267Sriastradh 	}
61141ec0267Sriastradh 
61241ec0267Sriastradh 	r = amdgpu_cs_find_mapping(p, addr, &bo, &mapping);
61341ec0267Sriastradh 	if (r) {
614*2b73d18aSriastradh 		DRM_ERROR("Can't find BO for addr 0x%010"PRIx64" %d %d %d %d\n",
61541ec0267Sriastradh 			  addr, lo, hi, size, index);
61641ec0267Sriastradh 		return r;
61741ec0267Sriastradh 	}
61841ec0267Sriastradh 
61941ec0267Sriastradh 	for (i = 0; i < bo->placement.num_placement; ++i) {
62041ec0267Sriastradh 		bo->placements[i].fpfn = max(bo->placements[i].fpfn, fpfn);
62141ec0267Sriastradh 		bo->placements[i].lpfn = bo->placements[i].lpfn ?
62241ec0267Sriastradh 			min(bo->placements[i].lpfn, lpfn) : lpfn;
62341ec0267Sriastradh 	}
62441ec0267Sriastradh 	return ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
62541ec0267Sriastradh }
62641ec0267Sriastradh 
62741ec0267Sriastradh 
62841ec0267Sriastradh /**
629efa246c0Sriastradh  * amdgpu_vce_cs_reloc - command submission relocation
630efa246c0Sriastradh  *
631efa246c0Sriastradh  * @p: parser context
632efa246c0Sriastradh  * @lo: address of lower dword
633efa246c0Sriastradh  * @hi: address of higher dword
634efa246c0Sriastradh  * @size: minimum size
635efa246c0Sriastradh  *
636efa246c0Sriastradh  * Patch relocation inside command stream with real buffer address
637efa246c0Sriastradh  */
amdgpu_vce_cs_reloc(struct amdgpu_cs_parser * p,uint32_t ib_idx,int lo,int hi,unsigned size,uint32_t index)638efa246c0Sriastradh static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx,
639efa246c0Sriastradh 			       int lo, int hi, unsigned size, uint32_t index)
640efa246c0Sriastradh {
641efa246c0Sriastradh 	struct amdgpu_bo_va_mapping *mapping;
642efa246c0Sriastradh 	struct amdgpu_bo *bo;
643efa246c0Sriastradh 	uint64_t addr;
64441ec0267Sriastradh 	int r;
645efa246c0Sriastradh 
646efa246c0Sriastradh 	if (index == 0xffffffff)
647efa246c0Sriastradh 		index = 0;
648efa246c0Sriastradh 
649efa246c0Sriastradh 	addr = ((uint64_t)amdgpu_get_ib_value(p, ib_idx, lo)) |
650efa246c0Sriastradh 	       ((uint64_t)amdgpu_get_ib_value(p, ib_idx, hi)) << 32;
651efa246c0Sriastradh 	addr += ((uint64_t)size) * ((uint64_t)index);
652efa246c0Sriastradh 
65341ec0267Sriastradh 	r = amdgpu_cs_find_mapping(p, addr, &bo, &mapping);
65441ec0267Sriastradh 	if (r) {
6550d50c49dSriastradh 		DRM_ERROR("Can't find BO for addr 0x%010"PRIx64" %d %d %d %d\n",
656efa246c0Sriastradh 			  addr, lo, hi, size, index);
65741ec0267Sriastradh 		return r;
658efa246c0Sriastradh 	}
659efa246c0Sriastradh 
660efa246c0Sriastradh 	if ((addr + (uint64_t)size) >
66141ec0267Sriastradh 	    ((uint64_t)mapping->last + 1) * AMDGPU_GPU_PAGE_SIZE) {
66241ec0267Sriastradh 		DRM_ERROR("BO too small for addr 0x%010"PRIx64" %d %d\n",
663efa246c0Sriastradh 			  addr, lo, hi);
664efa246c0Sriastradh 		return -EINVAL;
665efa246c0Sriastradh 	}
666efa246c0Sriastradh 
66741ec0267Sriastradh 	addr -= mapping->start * AMDGPU_GPU_PAGE_SIZE;
668efa246c0Sriastradh 	addr += amdgpu_bo_gpu_offset(bo);
669efa246c0Sriastradh 	addr -= ((uint64_t)size) * ((uint64_t)index);
670efa246c0Sriastradh 
67141ec0267Sriastradh 	amdgpu_set_ib_value(p, ib_idx, lo, lower_32_bits(addr));
67241ec0267Sriastradh 	amdgpu_set_ib_value(p, ib_idx, hi, upper_32_bits(addr));
673efa246c0Sriastradh 
674efa246c0Sriastradh 	return 0;
675efa246c0Sriastradh }
676efa246c0Sriastradh 
677efa246c0Sriastradh /**
678efa246c0Sriastradh  * amdgpu_vce_validate_handle - validate stream handle
679efa246c0Sriastradh  *
680efa246c0Sriastradh  * @p: parser context
681efa246c0Sriastradh  * @handle: handle to validate
682efa246c0Sriastradh  * @allocated: allocated a new handle?
683efa246c0Sriastradh  *
684efa246c0Sriastradh  * Validates the handle and return the found session index or -EINVAL
685efa246c0Sriastradh  * we we don't have another free session index.
686efa246c0Sriastradh  */
amdgpu_vce_validate_handle(struct amdgpu_cs_parser * p,uint32_t handle,uint32_t * allocated)687efa246c0Sriastradh static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p,
68841ec0267Sriastradh 				      uint32_t handle, uint32_t *allocated)
689efa246c0Sriastradh {
690efa246c0Sriastradh 	unsigned i;
691efa246c0Sriastradh 
692efa246c0Sriastradh 	/* validate the handle */
693efa246c0Sriastradh 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
694efa246c0Sriastradh 		if (atomic_read(&p->adev->vce.handles[i]) == handle) {
695efa246c0Sriastradh 			if (p->adev->vce.filp[i] != p->filp) {
696efa246c0Sriastradh 				DRM_ERROR("VCE handle collision detected!\n");
697efa246c0Sriastradh 				return -EINVAL;
698efa246c0Sriastradh 			}
699efa246c0Sriastradh 			return i;
700efa246c0Sriastradh 		}
701efa246c0Sriastradh 	}
702efa246c0Sriastradh 
703efa246c0Sriastradh 	/* handle not found try to alloc a new one */
704efa246c0Sriastradh 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
705efa246c0Sriastradh 		if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) {
706efa246c0Sriastradh 			p->adev->vce.filp[i] = p->filp;
707efa246c0Sriastradh 			p->adev->vce.img_size[i] = 0;
70841ec0267Sriastradh 			*allocated |= 1 << i;
709efa246c0Sriastradh 			return i;
710efa246c0Sriastradh 		}
711efa246c0Sriastradh 	}
712efa246c0Sriastradh 
713efa246c0Sriastradh 	DRM_ERROR("No more free VCE handles!\n");
714efa246c0Sriastradh 	return -EINVAL;
715efa246c0Sriastradh }
716efa246c0Sriastradh 
717efa246c0Sriastradh /**
718efa246c0Sriastradh  * amdgpu_vce_cs_parse - parse and validate the command stream
719efa246c0Sriastradh  *
720efa246c0Sriastradh  * @p: parser context
721efa246c0Sriastradh  *
722efa246c0Sriastradh  */
amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser * p,uint32_t ib_idx)723efa246c0Sriastradh int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
724efa246c0Sriastradh {
72541ec0267Sriastradh 	struct amdgpu_ib *ib = &p->job->ibs[ib_idx];
726efa246c0Sriastradh 	unsigned fb_idx = 0, bs_idx = 0;
727efa246c0Sriastradh 	int session_idx = -1;
72841ec0267Sriastradh 	uint32_t destroyed = 0;
72941ec0267Sriastradh 	uint32_t created = 0;
73041ec0267Sriastradh 	uint32_t allocated = 0;
731efa246c0Sriastradh 	uint32_t tmp, handle = 0;
732efa246c0Sriastradh 	uint32_t *size = &tmp;
73341ec0267Sriastradh 	unsigned idx;
73441ec0267Sriastradh 	int i, r = 0;
735efa246c0Sriastradh 
73641ec0267Sriastradh 	p->job->vm = NULL;
73741ec0267Sriastradh 	ib->gpu_addr = amdgpu_sa_bo_gpu_addr(ib->sa_bo);
738efa246c0Sriastradh 
73941ec0267Sriastradh 	for (idx = 0; idx < ib->length_dw;) {
740efa246c0Sriastradh 		uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
741efa246c0Sriastradh 		uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
742efa246c0Sriastradh 
743efa246c0Sriastradh 		if ((len < 8) || (len & 3)) {
744efa246c0Sriastradh 			DRM_ERROR("invalid VCE command length (%d)!\n", len);
745efa246c0Sriastradh 			r = -EINVAL;
746efa246c0Sriastradh 			goto out;
747efa246c0Sriastradh 		}
748efa246c0Sriastradh 
749efa246c0Sriastradh 		switch (cmd) {
75041ec0267Sriastradh 		case 0x00000002: /* task info */
751efa246c0Sriastradh 			fb_idx = amdgpu_get_ib_value(p, ib_idx, idx + 6);
752efa246c0Sriastradh 			bs_idx = amdgpu_get_ib_value(p, ib_idx, idx + 7);
753efa246c0Sriastradh 			break;
754efa246c0Sriastradh 
75541ec0267Sriastradh 		case 0x03000001: /* encode */
75641ec0267Sriastradh 			r = amdgpu_vce_validate_bo(p, ib_idx, idx + 10,
75741ec0267Sriastradh 						   idx + 9, 0, 0);
75841ec0267Sriastradh 			if (r)
75941ec0267Sriastradh 				goto out;
76041ec0267Sriastradh 
76141ec0267Sriastradh 			r = amdgpu_vce_validate_bo(p, ib_idx, idx + 12,
76241ec0267Sriastradh 						   idx + 11, 0, 0);
76341ec0267Sriastradh 			if (r)
76441ec0267Sriastradh 				goto out;
76541ec0267Sriastradh 			break;
76641ec0267Sriastradh 
76741ec0267Sriastradh 		case 0x05000001: /* context buffer */
76841ec0267Sriastradh 			r = amdgpu_vce_validate_bo(p, ib_idx, idx + 3,
76941ec0267Sriastradh 						   idx + 2, 0, 0);
77041ec0267Sriastradh 			if (r)
77141ec0267Sriastradh 				goto out;
77241ec0267Sriastradh 			break;
77341ec0267Sriastradh 
77441ec0267Sriastradh 		case 0x05000004: /* video bitstream buffer */
77541ec0267Sriastradh 			tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4);
77641ec0267Sriastradh 			r = amdgpu_vce_validate_bo(p, ib_idx, idx + 3, idx + 2,
77741ec0267Sriastradh 						   tmp, bs_idx);
77841ec0267Sriastradh 			if (r)
77941ec0267Sriastradh 				goto out;
78041ec0267Sriastradh 			break;
78141ec0267Sriastradh 
78241ec0267Sriastradh 		case 0x05000005: /* feedback buffer */
78341ec0267Sriastradh 			r = amdgpu_vce_validate_bo(p, ib_idx, idx + 3, idx + 2,
78441ec0267Sriastradh 						   4096, fb_idx);
78541ec0267Sriastradh 			if (r)
78641ec0267Sriastradh 				goto out;
78741ec0267Sriastradh 			break;
78841ec0267Sriastradh 
78941ec0267Sriastradh 		case 0x0500000d: /* MV buffer */
79041ec0267Sriastradh 			r = amdgpu_vce_validate_bo(p, ib_idx, idx + 3,
79141ec0267Sriastradh 							idx + 2, 0, 0);
79241ec0267Sriastradh 			if (r)
79341ec0267Sriastradh 				goto out;
79441ec0267Sriastradh 
79541ec0267Sriastradh 			r = amdgpu_vce_validate_bo(p, ib_idx, idx + 8,
79641ec0267Sriastradh 							idx + 7, 0, 0);
79741ec0267Sriastradh 			if (r)
79841ec0267Sriastradh 				goto out;
79941ec0267Sriastradh 			break;
80041ec0267Sriastradh 		}
80141ec0267Sriastradh 
80241ec0267Sriastradh 		idx += len / 4;
80341ec0267Sriastradh 	}
80441ec0267Sriastradh 
80541ec0267Sriastradh 	for (idx = 0; idx < ib->length_dw;) {
80641ec0267Sriastradh 		uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
80741ec0267Sriastradh 		uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
80841ec0267Sriastradh 
80941ec0267Sriastradh 		switch (cmd) {
81041ec0267Sriastradh 		case 0x00000001: /* session */
81141ec0267Sriastradh 			handle = amdgpu_get_ib_value(p, ib_idx, idx + 2);
81241ec0267Sriastradh 			session_idx = amdgpu_vce_validate_handle(p, handle,
81341ec0267Sriastradh 								 &allocated);
81441ec0267Sriastradh 			if (session_idx < 0) {
81541ec0267Sriastradh 				r = session_idx;
81641ec0267Sriastradh 				goto out;
81741ec0267Sriastradh 			}
81841ec0267Sriastradh 			size = &p->adev->vce.img_size[session_idx];
81941ec0267Sriastradh 			break;
82041ec0267Sriastradh 
82141ec0267Sriastradh 		case 0x00000002: /* task info */
82241ec0267Sriastradh 			fb_idx = amdgpu_get_ib_value(p, ib_idx, idx + 6);
82341ec0267Sriastradh 			bs_idx = amdgpu_get_ib_value(p, ib_idx, idx + 7);
82441ec0267Sriastradh 			break;
82541ec0267Sriastradh 
82641ec0267Sriastradh 		case 0x01000001: /* create */
82741ec0267Sriastradh 			created |= 1 << session_idx;
82841ec0267Sriastradh 			if (destroyed & (1 << session_idx)) {
82941ec0267Sriastradh 				destroyed &= ~(1 << session_idx);
83041ec0267Sriastradh 				allocated |= 1 << session_idx;
83141ec0267Sriastradh 
83241ec0267Sriastradh 			} else if (!(allocated & (1 << session_idx))) {
833efa246c0Sriastradh 				DRM_ERROR("Handle already in use!\n");
834efa246c0Sriastradh 				r = -EINVAL;
835efa246c0Sriastradh 				goto out;
836efa246c0Sriastradh 			}
837efa246c0Sriastradh 
838efa246c0Sriastradh 			*size = amdgpu_get_ib_value(p, ib_idx, idx + 8) *
839efa246c0Sriastradh 				amdgpu_get_ib_value(p, ib_idx, idx + 10) *
840efa246c0Sriastradh 				8 * 3 / 2;
841efa246c0Sriastradh 			break;
842efa246c0Sriastradh 
84341ec0267Sriastradh 		case 0x04000001: /* config extension */
84441ec0267Sriastradh 		case 0x04000002: /* pic control */
84541ec0267Sriastradh 		case 0x04000005: /* rate control */
84641ec0267Sriastradh 		case 0x04000007: /* motion estimation */
84741ec0267Sriastradh 		case 0x04000008: /* rdo */
84841ec0267Sriastradh 		case 0x04000009: /* vui */
84941ec0267Sriastradh 		case 0x05000002: /* auxiliary buffer */
85041ec0267Sriastradh 		case 0x05000009: /* clock table */
851efa246c0Sriastradh 			break;
852efa246c0Sriastradh 
85341ec0267Sriastradh 		case 0x0500000c: /* hw config */
85441ec0267Sriastradh 			switch (p->adev->asic_type) {
85541ec0267Sriastradh #ifdef CONFIG_DRM_AMDGPU_CIK
85641ec0267Sriastradh 			case CHIP_KAVERI:
85741ec0267Sriastradh 			case CHIP_MULLINS:
85841ec0267Sriastradh #endif
85941ec0267Sriastradh 			case CHIP_CARRIZO:
86041ec0267Sriastradh 				break;
86141ec0267Sriastradh 			default:
86241ec0267Sriastradh 				r = -EINVAL;
86341ec0267Sriastradh 				goto out;
86441ec0267Sriastradh 			}
86541ec0267Sriastradh 			break;
86641ec0267Sriastradh 
86741ec0267Sriastradh 		case 0x03000001: /* encode */
868efa246c0Sriastradh 			r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9,
869efa246c0Sriastradh 						*size, 0);
870efa246c0Sriastradh 			if (r)
871efa246c0Sriastradh 				goto out;
872efa246c0Sriastradh 
873efa246c0Sriastradh 			r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11,
874efa246c0Sriastradh 						*size / 3, 0);
875efa246c0Sriastradh 			if (r)
876efa246c0Sriastradh 				goto out;
877efa246c0Sriastradh 			break;
878efa246c0Sriastradh 
87941ec0267Sriastradh 		case 0x02000001: /* destroy */
88041ec0267Sriastradh 			destroyed |= 1 << session_idx;
881efa246c0Sriastradh 			break;
882efa246c0Sriastradh 
88341ec0267Sriastradh 		case 0x05000001: /* context buffer */
884efa246c0Sriastradh 			r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
885efa246c0Sriastradh 						*size * 2, 0);
886efa246c0Sriastradh 			if (r)
887efa246c0Sriastradh 				goto out;
888efa246c0Sriastradh 			break;
889efa246c0Sriastradh 
89041ec0267Sriastradh 		case 0x05000004: /* video bitstream buffer */
891efa246c0Sriastradh 			tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4);
892efa246c0Sriastradh 			r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
893efa246c0Sriastradh 						tmp, bs_idx);
894efa246c0Sriastradh 			if (r)
895efa246c0Sriastradh 				goto out;
896efa246c0Sriastradh 			break;
897efa246c0Sriastradh 
89841ec0267Sriastradh 		case 0x05000005: /* feedback buffer */
899efa246c0Sriastradh 			r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
900efa246c0Sriastradh 						4096, fb_idx);
901efa246c0Sriastradh 			if (r)
902efa246c0Sriastradh 				goto out;
903efa246c0Sriastradh 			break;
904efa246c0Sriastradh 
90541ec0267Sriastradh 		case 0x0500000d: /* MV buffer */
90641ec0267Sriastradh 			r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3,
90741ec0267Sriastradh 							idx + 2, *size, 0);
90841ec0267Sriastradh 			if (r)
90941ec0267Sriastradh 				goto out;
91041ec0267Sriastradh 
91141ec0267Sriastradh 			r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 8,
91241ec0267Sriastradh 							idx + 7, *size / 12, 0);
91341ec0267Sriastradh 			if (r)
91441ec0267Sriastradh 				goto out;
91541ec0267Sriastradh 			break;
91641ec0267Sriastradh 
917efa246c0Sriastradh 		default:
918efa246c0Sriastradh 			DRM_ERROR("invalid VCE command (0x%x)!\n", cmd);
919efa246c0Sriastradh 			r = -EINVAL;
920efa246c0Sriastradh 			goto out;
921efa246c0Sriastradh 		}
922efa246c0Sriastradh 
923efa246c0Sriastradh 		if (session_idx == -1) {
924efa246c0Sriastradh 			DRM_ERROR("no session command at start of IB\n");
925efa246c0Sriastradh 			r = -EINVAL;
926efa246c0Sriastradh 			goto out;
927efa246c0Sriastradh 		}
928efa246c0Sriastradh 
929efa246c0Sriastradh 		idx += len / 4;
930efa246c0Sriastradh 	}
931efa246c0Sriastradh 
93241ec0267Sriastradh 	if (allocated & ~created) {
933efa246c0Sriastradh 		DRM_ERROR("New session without create command!\n");
934efa246c0Sriastradh 		r = -ENOENT;
935efa246c0Sriastradh 	}
936efa246c0Sriastradh 
937efa246c0Sriastradh out:
93841ec0267Sriastradh 	if (!r) {
93941ec0267Sriastradh 		/* No error, free all destroyed handle slots */
94041ec0267Sriastradh 		tmp = destroyed;
94141ec0267Sriastradh 	} else {
94241ec0267Sriastradh 		/* Error during parsing, free all allocated handle slots */
94341ec0267Sriastradh 		tmp = allocated;
944efa246c0Sriastradh 	}
945efa246c0Sriastradh 
94641ec0267Sriastradh 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
94741ec0267Sriastradh 		if (tmp & (1 << i))
94841ec0267Sriastradh 			atomic_set(&p->adev->vce.handles[i], 0);
94941ec0267Sriastradh 
950efa246c0Sriastradh 	return r;
951efa246c0Sriastradh }
952efa246c0Sriastradh 
953efa246c0Sriastradh /**
95441ec0267Sriastradh  * amdgpu_vce_cs_parse_vm - parse the command stream in VM mode
955efa246c0Sriastradh  *
95641ec0267Sriastradh  * @p: parser context
957efa246c0Sriastradh  *
958efa246c0Sriastradh  */
amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser * p,uint32_t ib_idx)95941ec0267Sriastradh int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx)
960efa246c0Sriastradh {
96141ec0267Sriastradh 	struct amdgpu_ib *ib = &p->job->ibs[ib_idx];
96241ec0267Sriastradh 	int session_idx = -1;
96341ec0267Sriastradh 	uint32_t destroyed = 0;
96441ec0267Sriastradh 	uint32_t created = 0;
96541ec0267Sriastradh 	uint32_t allocated = 0;
96641ec0267Sriastradh 	uint32_t tmp, handle = 0;
96741ec0267Sriastradh 	int i, r = 0, idx = 0;
968efa246c0Sriastradh 
96941ec0267Sriastradh 	while (idx < ib->length_dw) {
97041ec0267Sriastradh 		uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
97141ec0267Sriastradh 		uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
972efa246c0Sriastradh 
97341ec0267Sriastradh 		if ((len < 8) || (len & 3)) {
97441ec0267Sriastradh 			DRM_ERROR("invalid VCE command length (%d)!\n", len);
97541ec0267Sriastradh 			r = -EINVAL;
97641ec0267Sriastradh 			goto out;
97741ec0267Sriastradh 		}
97841ec0267Sriastradh 
97941ec0267Sriastradh 		switch (cmd) {
98041ec0267Sriastradh 		case 0x00000001: /* session */
98141ec0267Sriastradh 			handle = amdgpu_get_ib_value(p, ib_idx, idx + 2);
98241ec0267Sriastradh 			session_idx = amdgpu_vce_validate_handle(p, handle,
98341ec0267Sriastradh 								 &allocated);
98441ec0267Sriastradh 			if (session_idx < 0) {
98541ec0267Sriastradh 				r = session_idx;
98641ec0267Sriastradh 				goto out;
98741ec0267Sriastradh 			}
98841ec0267Sriastradh 			break;
98941ec0267Sriastradh 
99041ec0267Sriastradh 		case 0x01000001: /* create */
99141ec0267Sriastradh 			created |= 1 << session_idx;
99241ec0267Sriastradh 			if (destroyed & (1 << session_idx)) {
99341ec0267Sriastradh 				destroyed &= ~(1 << session_idx);
99441ec0267Sriastradh 				allocated |= 1 << session_idx;
99541ec0267Sriastradh 
99641ec0267Sriastradh 			} else if (!(allocated & (1 << session_idx))) {
99741ec0267Sriastradh 				DRM_ERROR("Handle already in use!\n");
99841ec0267Sriastradh 				r = -EINVAL;
99941ec0267Sriastradh 				goto out;
100041ec0267Sriastradh 			}
100141ec0267Sriastradh 
100241ec0267Sriastradh 			break;
100341ec0267Sriastradh 
100441ec0267Sriastradh 		case 0x02000001: /* destroy */
100541ec0267Sriastradh 			destroyed |= 1 << session_idx;
100641ec0267Sriastradh 			break;
100741ec0267Sriastradh 
100841ec0267Sriastradh 		default:
100941ec0267Sriastradh 			break;
101041ec0267Sriastradh 		}
101141ec0267Sriastradh 
101241ec0267Sriastradh 		if (session_idx == -1) {
101341ec0267Sriastradh 			DRM_ERROR("no session command at start of IB\n");
101441ec0267Sriastradh 			r = -EINVAL;
101541ec0267Sriastradh 			goto out;
101641ec0267Sriastradh 		}
101741ec0267Sriastradh 
101841ec0267Sriastradh 		idx += len / 4;
101941ec0267Sriastradh 	}
102041ec0267Sriastradh 
102141ec0267Sriastradh 	if (allocated & ~created) {
102241ec0267Sriastradh 		DRM_ERROR("New session without create command!\n");
102341ec0267Sriastradh 		r = -ENOENT;
102441ec0267Sriastradh 	}
102541ec0267Sriastradh 
102641ec0267Sriastradh out:
102741ec0267Sriastradh 	if (!r) {
102841ec0267Sriastradh 		/* No error, free all destroyed handle slots */
102941ec0267Sriastradh 		tmp = destroyed;
103041ec0267Sriastradh 		amdgpu_ib_free(p->adev, ib, NULL);
103141ec0267Sriastradh 	} else {
103241ec0267Sriastradh 		/* Error during parsing, free all allocated handle slots */
103341ec0267Sriastradh 		tmp = allocated;
103441ec0267Sriastradh 	}
103541ec0267Sriastradh 
103641ec0267Sriastradh 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
103741ec0267Sriastradh 		if (tmp & (1 << i))
103841ec0267Sriastradh 			atomic_set(&p->adev->vce.handles[i], 0);
103941ec0267Sriastradh 
104041ec0267Sriastradh 	return r;
1041efa246c0Sriastradh }
1042efa246c0Sriastradh 
1043efa246c0Sriastradh /**
1044efa246c0Sriastradh  * amdgpu_vce_ring_emit_ib - execute indirect buffer
1045efa246c0Sriastradh  *
1046efa246c0Sriastradh  * @ring: engine to use
1047efa246c0Sriastradh  * @ib: the IB to execute
1048efa246c0Sriastradh  *
1049efa246c0Sriastradh  */
amdgpu_vce_ring_emit_ib(struct amdgpu_ring * ring,struct amdgpu_job * job,struct amdgpu_ib * ib,uint32_t flags)105041ec0267Sriastradh void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring,
105141ec0267Sriastradh 				struct amdgpu_job *job,
105241ec0267Sriastradh 				struct amdgpu_ib *ib,
105341ec0267Sriastradh 				uint32_t flags)
1054efa246c0Sriastradh {
1055efa246c0Sriastradh 	amdgpu_ring_write(ring, VCE_CMD_IB);
1056efa246c0Sriastradh 	amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
1057efa246c0Sriastradh 	amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
1058efa246c0Sriastradh 	amdgpu_ring_write(ring, ib->length_dw);
1059efa246c0Sriastradh }
1060efa246c0Sriastradh 
1061efa246c0Sriastradh /**
1062efa246c0Sriastradh  * amdgpu_vce_ring_emit_fence - add a fence command to the ring
1063efa246c0Sriastradh  *
1064efa246c0Sriastradh  * @ring: engine to use
1065efa246c0Sriastradh  * @fence: the fence
1066efa246c0Sriastradh  *
1067efa246c0Sriastradh  */
amdgpu_vce_ring_emit_fence(struct amdgpu_ring * ring,u64 addr,u64 seq,unsigned flags)1068efa246c0Sriastradh void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
1069efa246c0Sriastradh 				unsigned flags)
1070efa246c0Sriastradh {
1071efa246c0Sriastradh 	WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
1072efa246c0Sriastradh 
1073efa246c0Sriastradh 	amdgpu_ring_write(ring, VCE_CMD_FENCE);
1074efa246c0Sriastradh 	amdgpu_ring_write(ring, addr);
1075efa246c0Sriastradh 	amdgpu_ring_write(ring, upper_32_bits(addr));
1076efa246c0Sriastradh 	amdgpu_ring_write(ring, seq);
1077efa246c0Sriastradh 	amdgpu_ring_write(ring, VCE_CMD_TRAP);
1078efa246c0Sriastradh 	amdgpu_ring_write(ring, VCE_CMD_END);
1079efa246c0Sriastradh }
1080efa246c0Sriastradh 
1081efa246c0Sriastradh /**
1082efa246c0Sriastradh  * amdgpu_vce_ring_test_ring - test if VCE ring is working
1083efa246c0Sriastradh  *
1084efa246c0Sriastradh  * @ring: the engine to test on
1085efa246c0Sriastradh  *
1086efa246c0Sriastradh  */
amdgpu_vce_ring_test_ring(struct amdgpu_ring * ring)1087efa246c0Sriastradh int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
1088efa246c0Sriastradh {
1089efa246c0Sriastradh 	struct amdgpu_device *adev = ring->adev;
109041ec0267Sriastradh 	uint32_t rptr;
1091efa246c0Sriastradh 	unsigned i;
109241ec0267Sriastradh 	int r, timeout = adev->usec_timeout;
1093efa246c0Sriastradh 
109441ec0267Sriastradh 	/* skip ring test for sriov*/
109541ec0267Sriastradh 	if (amdgpu_sriov_vf(adev))
109641ec0267Sriastradh 		return 0;
109741ec0267Sriastradh 
109841ec0267Sriastradh 	r = amdgpu_ring_alloc(ring, 16);
109941ec0267Sriastradh 	if (r)
1100efa246c0Sriastradh 		return r;
1101efa246c0Sriastradh 
110241ec0267Sriastradh 	rptr = amdgpu_ring_get_rptr(ring);
110341ec0267Sriastradh 
110441ec0267Sriastradh 	amdgpu_ring_write(ring, VCE_CMD_END);
110541ec0267Sriastradh 	amdgpu_ring_commit(ring);
110641ec0267Sriastradh 
110741ec0267Sriastradh 	for (i = 0; i < timeout; i++) {
1108efa246c0Sriastradh 		if (amdgpu_ring_get_rptr(ring) != rptr)
1109efa246c0Sriastradh 			break;
111041ec0267Sriastradh 		udelay(1);
1111efa246c0Sriastradh 	}
1112efa246c0Sriastradh 
111341ec0267Sriastradh 	if (i >= timeout)
1114efa246c0Sriastradh 		r = -ETIMEDOUT;
1115efa246c0Sriastradh 
1116efa246c0Sriastradh 	return r;
1117efa246c0Sriastradh }
1118efa246c0Sriastradh 
1119efa246c0Sriastradh /**
1120efa246c0Sriastradh  * amdgpu_vce_ring_test_ib - test if VCE IBs are working
1121efa246c0Sriastradh  *
1122efa246c0Sriastradh  * @ring: the engine to test on
1123efa246c0Sriastradh  *
1124efa246c0Sriastradh  */
amdgpu_vce_ring_test_ib(struct amdgpu_ring * ring,long timeout)112541ec0267Sriastradh int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout)
1126efa246c0Sriastradh {
112741ec0267Sriastradh 	struct dma_fence *fence = NULL;
112841ec0267Sriastradh 	struct amdgpu_bo *bo = NULL;
112941ec0267Sriastradh 	long r;
1130efa246c0Sriastradh 
113141ec0267Sriastradh 	/* skip vce ring1/2 ib test for now, since it's not reliable */
113241ec0267Sriastradh 	if (ring != &ring->adev->vce.ring[0])
1133efa246c0Sriastradh 		return 0;
1134efa246c0Sriastradh 
113541ec0267Sriastradh 	r = amdgpu_bo_create_reserved(ring->adev, 512, PAGE_SIZE,
113641ec0267Sriastradh 				      AMDGPU_GEM_DOMAIN_VRAM,
113741ec0267Sriastradh 				      &bo, NULL, NULL);
113841ec0267Sriastradh 	if (r)
113941ec0267Sriastradh 		return r;
1140efa246c0Sriastradh 
114141ec0267Sriastradh 	r = amdgpu_vce_get_create_msg(ring, 1, bo, NULL);
114241ec0267Sriastradh 	if (r)
1143efa246c0Sriastradh 		goto error;
1144efa246c0Sriastradh 
114541ec0267Sriastradh 	r = amdgpu_vce_get_destroy_msg(ring, 1, true, &fence);
114641ec0267Sriastradh 	if (r)
114741ec0267Sriastradh 		goto error;
114841ec0267Sriastradh 
114941ec0267Sriastradh 	r = dma_fence_wait_timeout(fence, false, timeout);
115041ec0267Sriastradh 	if (r == 0)
115141ec0267Sriastradh 		r = -ETIMEDOUT;
115241ec0267Sriastradh 	else if (r > 0)
115341ec0267Sriastradh 		r = 0;
115441ec0267Sriastradh 
1155efa246c0Sriastradh error:
115641ec0267Sriastradh 	dma_fence_put(fence);
115741ec0267Sriastradh 	amdgpu_bo_unreserve(bo);
115841ec0267Sriastradh 	amdgpu_bo_unref(&bo);
1159efa246c0Sriastradh 	return r;
1160efa246c0Sriastradh }
1161