1d38ceaf9SAlex Deucher /*
2d38ceaf9SAlex Deucher  * Copyright 2013 Advanced Micro Devices, Inc.
3d38ceaf9SAlex Deucher  * All Rights Reserved.
4d38ceaf9SAlex Deucher  *
5d38ceaf9SAlex Deucher  * Permission is hereby granted, free of charge, to any person obtaining a
6d38ceaf9SAlex Deucher  * copy of this software and associated documentation files (the
7d38ceaf9SAlex Deucher  * "Software"), to deal in the Software without restriction, including
8d38ceaf9SAlex Deucher  * without limitation the rights to use, copy, modify, merge, publish,
9d38ceaf9SAlex Deucher  * distribute, sub license, and/or sell copies of the Software, and to
10d38ceaf9SAlex Deucher  * permit persons to whom the Software is furnished to do so, subject to
11d38ceaf9SAlex Deucher  * the following conditions:
12d38ceaf9SAlex Deucher  *
13d38ceaf9SAlex Deucher  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14d38ceaf9SAlex Deucher  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15d38ceaf9SAlex Deucher  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16d38ceaf9SAlex Deucher  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17d38ceaf9SAlex Deucher  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18d38ceaf9SAlex Deucher  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19d38ceaf9SAlex Deucher  * USE OR OTHER DEALINGS IN THE SOFTWARE.
20d38ceaf9SAlex Deucher  *
21d38ceaf9SAlex Deucher  * The above copyright notice and this permission notice (including the
22d38ceaf9SAlex Deucher  * next paragraph) shall be included in all copies or substantial portions
23d38ceaf9SAlex Deucher  * of the Software.
24d38ceaf9SAlex Deucher  *
25d38ceaf9SAlex Deucher  * Authors: Christian König <[email protected]>
26d38ceaf9SAlex Deucher  */
27d38ceaf9SAlex Deucher 
28d38ceaf9SAlex Deucher #include <linux/firmware.h>
29d38ceaf9SAlex Deucher #include <linux/module.h>
30fdf2f6c5SSam Ravnborg 
31d38ceaf9SAlex Deucher #include <drm/drm.h>
32f89f8c6bSAndrey Grodzovsky #include <drm/drm_drv.h>
33d38ceaf9SAlex Deucher 
34d38ceaf9SAlex Deucher #include "amdgpu.h"
35d38ceaf9SAlex Deucher #include "amdgpu_pm.h"
36d38ceaf9SAlex Deucher #include "amdgpu_vce.h"
37a190f8dcSChristian König #include "amdgpu_cs.h"
38d38ceaf9SAlex Deucher #include "cikd.h"
39d38ceaf9SAlex Deucher 
40d38ceaf9SAlex Deucher /* 1 second timeout */
41182830a1SChristian König #define VCE_IDLE_TIMEOUT	msecs_to_jiffies(1000)
42d38ceaf9SAlex Deucher 
43d38ceaf9SAlex Deucher /* Firmware Names */
44d38ceaf9SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_CIK
45ce206464SAlex Deucher #define FIRMWARE_BONAIRE	"amdgpu/bonaire_vce.bin"
46ce206464SAlex Deucher #define FIRMWARE_KABINI	"amdgpu/kabini_vce.bin"
47ce206464SAlex Deucher #define FIRMWARE_KAVERI	"amdgpu/kaveri_vce.bin"
48ce206464SAlex Deucher #define FIRMWARE_HAWAII	"amdgpu/hawaii_vce.bin"
49ce206464SAlex Deucher #define FIRMWARE_MULLINS	"amdgpu/mullins_vce.bin"
50d38ceaf9SAlex Deucher #endif
51c65444feSJammy Zhou #define FIRMWARE_TONGA		"amdgpu/tonga_vce.bin"
52c65444feSJammy Zhou #define FIRMWARE_CARRIZO	"amdgpu/carrizo_vce.bin"
53188a9bcdSAlex Deucher #define FIRMWARE_FIJI		"amdgpu/fiji_vce.bin"
54cfaba566SSamuel Li #define FIRMWARE_STONEY		"amdgpu/stoney_vce.bin"
552cc0c0b5SFlora Cui #define FIRMWARE_POLARIS10	"amdgpu/polaris10_vce.bin"
562cc0c0b5SFlora Cui #define FIRMWARE_POLARIS11	"amdgpu/polaris11_vce.bin"
57c4642a47SJunwei Zhang #define FIRMWARE_POLARIS12	"amdgpu/polaris12_vce.bin"
58f11ded5eSLeo Liu #define FIRMWARE_VEGAM		"amdgpu/vegam_vce.bin"
59d38ceaf9SAlex Deucher 
60c1dc356aSLeo Liu #define FIRMWARE_VEGA10		"amdgpu/vega10_vce.bin"
619aa52bc4SAlex Deucher #define FIRMWARE_VEGA12		"amdgpu/vega12_vce.bin"
62341b4ce2SFeifei Xu #define FIRMWARE_VEGA20		"amdgpu/vega20_vce.bin"
63c1dc356aSLeo Liu 
64d38ceaf9SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_CIK
65d38ceaf9SAlex Deucher MODULE_FIRMWARE(FIRMWARE_BONAIRE);
66d38ceaf9SAlex Deucher MODULE_FIRMWARE(FIRMWARE_KABINI);
67d38ceaf9SAlex Deucher MODULE_FIRMWARE(FIRMWARE_KAVERI);
68d38ceaf9SAlex Deucher MODULE_FIRMWARE(FIRMWARE_HAWAII);
69d38ceaf9SAlex Deucher MODULE_FIRMWARE(FIRMWARE_MULLINS);
70d38ceaf9SAlex Deucher #endif
71d38ceaf9SAlex Deucher MODULE_FIRMWARE(FIRMWARE_TONGA);
72d38ceaf9SAlex Deucher MODULE_FIRMWARE(FIRMWARE_CARRIZO);
73188a9bcdSAlex Deucher MODULE_FIRMWARE(FIRMWARE_FIJI);
74cfaba566SSamuel Li MODULE_FIRMWARE(FIRMWARE_STONEY);
752cc0c0b5SFlora Cui MODULE_FIRMWARE(FIRMWARE_POLARIS10);
762cc0c0b5SFlora Cui MODULE_FIRMWARE(FIRMWARE_POLARIS11);
77c4642a47SJunwei Zhang MODULE_FIRMWARE(FIRMWARE_POLARIS12);
78f11ded5eSLeo Liu MODULE_FIRMWARE(FIRMWARE_VEGAM);
79d38ceaf9SAlex Deucher 
80c1dc356aSLeo Liu MODULE_FIRMWARE(FIRMWARE_VEGA10);
819aa52bc4SAlex Deucher MODULE_FIRMWARE(FIRMWARE_VEGA12);
82341b4ce2SFeifei Xu MODULE_FIRMWARE(FIRMWARE_VEGA20);
83c1dc356aSLeo Liu 
84d38ceaf9SAlex Deucher static void amdgpu_vce_idle_work_handler(struct work_struct *work);
8517523bd0SAlex Deucher static int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
8617523bd0SAlex Deucher 				     struct dma_fence **fence);
8717523bd0SAlex Deucher static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
8817523bd0SAlex Deucher 				      bool direct, struct dma_fence **fence);
89d38ceaf9SAlex Deucher 
90d38ceaf9SAlex Deucher /**
911c7f15c7SLee Jones  * amdgpu_vce_sw_init - allocate memory, load vce firmware
92d38ceaf9SAlex Deucher  *
93d38ceaf9SAlex Deucher  * @adev: amdgpu_device pointer
94184b762dSLee Jones  * @size: size for the new BO
95d38ceaf9SAlex Deucher  *
96d38ceaf9SAlex Deucher  * First step to get VCE online, allocate memory and load the firmware
97d38ceaf9SAlex Deucher  */
amdgpu_vce_sw_init(struct amdgpu_device * adev,unsigned long size)98e9822622SLeo Liu int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
99d38ceaf9SAlex Deucher {
100d38ceaf9SAlex Deucher 	const char *fw_name;
101d38ceaf9SAlex Deucher 	const struct common_firmware_header *hdr;
102f10984a3SSrinivasan Shanmugam 	unsigned int ucode_version, version_major, version_minor, binary_id;
103d38ceaf9SAlex Deucher 	int i, r;
104d38ceaf9SAlex Deucher 
105d38ceaf9SAlex Deucher 	switch (adev->asic_type) {
106d38ceaf9SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_CIK
107d38ceaf9SAlex Deucher 	case CHIP_BONAIRE:
108d38ceaf9SAlex Deucher 		fw_name = FIRMWARE_BONAIRE;
109d38ceaf9SAlex Deucher 		break;
110d38ceaf9SAlex Deucher 	case CHIP_KAVERI:
111d38ceaf9SAlex Deucher 		fw_name = FIRMWARE_KAVERI;
112d38ceaf9SAlex Deucher 		break;
113d38ceaf9SAlex Deucher 	case CHIP_KABINI:
114d38ceaf9SAlex Deucher 		fw_name = FIRMWARE_KABINI;
115d38ceaf9SAlex Deucher 		break;
116d38ceaf9SAlex Deucher 	case CHIP_HAWAII:
117d38ceaf9SAlex Deucher 		fw_name = FIRMWARE_HAWAII;
118d38ceaf9SAlex Deucher 		break;
119d38ceaf9SAlex Deucher 	case CHIP_MULLINS:
120d38ceaf9SAlex Deucher 		fw_name = FIRMWARE_MULLINS;
121d38ceaf9SAlex Deucher 		break;
122d38ceaf9SAlex Deucher #endif
123d38ceaf9SAlex Deucher 	case CHIP_TONGA:
124d38ceaf9SAlex Deucher 		fw_name = FIRMWARE_TONGA;
125d38ceaf9SAlex Deucher 		break;
126d38ceaf9SAlex Deucher 	case CHIP_CARRIZO:
127d38ceaf9SAlex Deucher 		fw_name = FIRMWARE_CARRIZO;
128d38ceaf9SAlex Deucher 		break;
129188a9bcdSAlex Deucher 	case CHIP_FIJI:
130188a9bcdSAlex Deucher 		fw_name = FIRMWARE_FIJI;
131188a9bcdSAlex Deucher 		break;
132cfaba566SSamuel Li 	case CHIP_STONEY:
133cfaba566SSamuel Li 		fw_name = FIRMWARE_STONEY;
134cfaba566SSamuel Li 		break;
1352cc0c0b5SFlora Cui 	case CHIP_POLARIS10:
1362cc0c0b5SFlora Cui 		fw_name = FIRMWARE_POLARIS10;
1371b4eeea5SSonny Jiang 		break;
1382cc0c0b5SFlora Cui 	case CHIP_POLARIS11:
1392cc0c0b5SFlora Cui 		fw_name = FIRMWARE_POLARIS11;
1401b4eeea5SSonny Jiang 		break;
1419aa52bc4SAlex Deucher 	case CHIP_POLARIS12:
1429aa52bc4SAlex Deucher 		fw_name = FIRMWARE_POLARIS12;
1439aa52bc4SAlex Deucher 		break;
144f11ded5eSLeo Liu 	case CHIP_VEGAM:
145f11ded5eSLeo Liu 		fw_name = FIRMWARE_VEGAM;
146f11ded5eSLeo Liu 		break;
147c1dc356aSLeo Liu 	case CHIP_VEGA10:
148c1dc356aSLeo Liu 		fw_name = FIRMWARE_VEGA10;
149c1dc356aSLeo Liu 		break;
1509aa52bc4SAlex Deucher 	case CHIP_VEGA12:
1519aa52bc4SAlex Deucher 		fw_name = FIRMWARE_VEGA12;
152c4642a47SJunwei Zhang 		break;
153341b4ce2SFeifei Xu 	case CHIP_VEGA20:
154341b4ce2SFeifei Xu 		fw_name = FIRMWARE_VEGA20;
155341b4ce2SFeifei Xu 		break;
156d38ceaf9SAlex Deucher 
157d38ceaf9SAlex Deucher 	default:
158d38ceaf9SAlex Deucher 		return -EINVAL;
159d38ceaf9SAlex Deucher 	}
160d38ceaf9SAlex Deucher 
161ea5d4934SMario Limonciello 	r = amdgpu_ucode_request(adev, &adev->vce.fw, AMDGPU_UCODE_REQUIRED, "%s", fw_name);
162d38ceaf9SAlex Deucher 	if (r) {
163d38ceaf9SAlex Deucher 		dev_err(adev->dev, "amdgpu_vce: Can't validate firmware \"%s\"\n",
164d38ceaf9SAlex Deucher 			fw_name);
16552215e2aSMario Limonciello 		amdgpu_ucode_release(&adev->vce.fw);
166d38ceaf9SAlex Deucher 		return r;
167d38ceaf9SAlex Deucher 	}
168d38ceaf9SAlex Deucher 
169d38ceaf9SAlex Deucher 	hdr = (const struct common_firmware_header *)adev->vce.fw->data;
170d38ceaf9SAlex Deucher 
171d38ceaf9SAlex Deucher 	ucode_version = le32_to_cpu(hdr->ucode_version);
172d38ceaf9SAlex Deucher 	version_major = (ucode_version >> 20) & 0xfff;
173d38ceaf9SAlex Deucher 	version_minor = (ucode_version >> 8) & 0xfff;
174d38ceaf9SAlex Deucher 	binary_id = ucode_version & 0xff;
1750b437e64STom Rix 	DRM_INFO("Found VCE firmware Version: %d.%d Binary ID: %d\n",
176d38ceaf9SAlex Deucher 		version_major, version_minor, binary_id);
177d38ceaf9SAlex Deucher 	adev->vce.fw_version = ((version_major << 24) | (version_minor << 16) |
178d38ceaf9SAlex Deucher 				(binary_id << 8));
179d38ceaf9SAlex Deucher 
18078b3c839SLeo Liu 	r = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE,
18158ab2c08SChristian König 				    AMDGPU_GEM_DOMAIN_VRAM |
18258ab2c08SChristian König 				    AMDGPU_GEM_DOMAIN_GTT,
18358ab2c08SChristian König 				    &adev->vce.vcpu_bo,
18478b3c839SLeo Liu 				    &adev->vce.gpu_addr, &adev->vce.cpu_addr);
185d38ceaf9SAlex Deucher 	if (r) {
186d38ceaf9SAlex Deucher 		dev_err(adev->dev, "(%d) failed to allocate VCE bo\n", r);
187d38ceaf9SAlex Deucher 		return r;
188d38ceaf9SAlex Deucher 	}
189d38ceaf9SAlex Deucher 
190d38ceaf9SAlex Deucher 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
191d38ceaf9SAlex Deucher 		atomic_set(&adev->vce.handles[i], 0);
192d38ceaf9SAlex Deucher 		adev->vce.filp[i] = NULL;
193d38ceaf9SAlex Deucher 	}
194d38ceaf9SAlex Deucher 
195ebff485eSChristian König 	INIT_DELAYED_WORK(&adev->vce.idle_work, amdgpu_vce_idle_work_handler);
196ebff485eSChristian König 	mutex_init(&adev->vce.idle_mutex);
197ebff485eSChristian König 
198d38ceaf9SAlex Deucher 	return 0;
199d38ceaf9SAlex Deucher }
200d38ceaf9SAlex Deucher 
201d38ceaf9SAlex Deucher /**
2021c7f15c7SLee Jones  * amdgpu_vce_sw_fini - free memory
203d38ceaf9SAlex Deucher  *
204d38ceaf9SAlex Deucher  * @adev: amdgpu_device pointer
205d38ceaf9SAlex Deucher  *
206d38ceaf9SAlex Deucher  * Last step on VCE teardown, free firmware memory
207d38ceaf9SAlex Deucher  */
amdgpu_vce_sw_fini(struct amdgpu_device * adev)208d38ceaf9SAlex Deucher int amdgpu_vce_sw_fini(struct amdgpu_device *adev)
209d38ceaf9SAlex Deucher {
210f10984a3SSrinivasan Shanmugam 	unsigned int i;
2114cd00d37SGrazvydas Ignotas 
212d38ceaf9SAlex Deucher 	if (adev->vce.vcpu_bo == NULL)
213d38ceaf9SAlex Deucher 		return 0;
214d38ceaf9SAlex Deucher 
215cdc50176SNayan Deshmukh 	drm_sched_entity_destroy(&adev->vce.entity);
216c594989cSChristian König 
2174cd00d37SGrazvydas Ignotas 	for (i = 0; i < adev->vce.num_rings; i++)
2184cd00d37SGrazvydas Ignotas 		amdgpu_ring_fini(&adev->vce.ring[i]);
219d38ceaf9SAlex Deucher 
22052215e2aSMario Limonciello 	amdgpu_ucode_release(&adev->vce.fw);
221ebff485eSChristian König 	mutex_destroy(&adev->vce.idle_mutex);
222d38ceaf9SAlex Deucher 
223b61badd2SVitaly Prosyak 	amdgpu_bo_free_kernel(&adev->vce.vcpu_bo, &adev->vce.gpu_addr,
224b61badd2SVitaly Prosyak 		(void **)&adev->vce.cpu_addr);
225b61badd2SVitaly Prosyak 
226d38ceaf9SAlex Deucher 	return 0;
227d38ceaf9SAlex Deucher }
228d38ceaf9SAlex Deucher 
229d38ceaf9SAlex Deucher /**
23020acbed4SEmily Deng  * amdgpu_vce_entity_init - init entity
23120acbed4SEmily Deng  *
23220acbed4SEmily Deng  * @adev: amdgpu_device pointer
2338a0173cdSSrinivasan Shanmugam  * @ring: amdgpu_ring pointer to check
23420acbed4SEmily Deng  *
235037b98a2SAlex Deucher  * Initialize the entity used for handle management in the kernel driver.
23620acbed4SEmily Deng  */
amdgpu_vce_entity_init(struct amdgpu_device * adev,struct amdgpu_ring * ring)237037b98a2SAlex Deucher int amdgpu_vce_entity_init(struct amdgpu_device *adev, struct amdgpu_ring *ring)
23820acbed4SEmily Deng {
239037b98a2SAlex Deucher 	if (ring == &adev->vce.ring[0]) {
240037b98a2SAlex Deucher 		struct drm_gpu_scheduler *sched = &ring->sched;
24120acbed4SEmily Deng 		int r;
24220acbed4SEmily Deng 
243b3ac1766SNirmoy Das 		r = drm_sched_entity_init(&adev->vce.entity, DRM_SCHED_PRIORITY_NORMAL,
244b3ac1766SNirmoy Das 					  &sched, 1, NULL);
24520acbed4SEmily Deng 		if (r != 0) {
24620acbed4SEmily Deng 			DRM_ERROR("Failed setting up VCE run queue.\n");
24720acbed4SEmily Deng 			return r;
24820acbed4SEmily Deng 		}
249037b98a2SAlex Deucher 	}
25020acbed4SEmily Deng 
25120acbed4SEmily Deng 	return 0;
25220acbed4SEmily Deng }
25320acbed4SEmily Deng 
25420acbed4SEmily Deng /**
255d38ceaf9SAlex Deucher  * amdgpu_vce_suspend - unpin VCE fw memory
256d38ceaf9SAlex Deucher  *
257d38ceaf9SAlex Deucher  * @adev: amdgpu_device pointer
258d38ceaf9SAlex Deucher  *
259d38ceaf9SAlex Deucher  */
amdgpu_vce_suspend(struct amdgpu_device * adev)260d38ceaf9SAlex Deucher int amdgpu_vce_suspend(struct amdgpu_device *adev)
261d38ceaf9SAlex Deucher {
262d38ceaf9SAlex Deucher 	int i;
263d38ceaf9SAlex Deucher 
26461ea6f58SRex Zhu 	cancel_delayed_work_sync(&adev->vce.idle_work);
26561ea6f58SRex Zhu 
266d38ceaf9SAlex Deucher 	if (adev->vce.vcpu_bo == NULL)
267d38ceaf9SAlex Deucher 		return 0;
268d38ceaf9SAlex Deucher 
269d38ceaf9SAlex Deucher 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
270d38ceaf9SAlex Deucher 		if (atomic_read(&adev->vce.handles[i]))
271d38ceaf9SAlex Deucher 			break;
272d38ceaf9SAlex Deucher 
273d38ceaf9SAlex Deucher 	if (i == AMDGPU_MAX_VCE_HANDLES)
274d38ceaf9SAlex Deucher 		return 0;
275d38ceaf9SAlex Deucher 
276d38ceaf9SAlex Deucher 	/* TODO: suspending running encoding sessions isn't supported */
277d38ceaf9SAlex Deucher 	return -EINVAL;
278d38ceaf9SAlex Deucher }
279d38ceaf9SAlex Deucher 
280d38ceaf9SAlex Deucher /**
281d38ceaf9SAlex Deucher  * amdgpu_vce_resume - pin VCE fw memory
282d38ceaf9SAlex Deucher  *
283d38ceaf9SAlex Deucher  * @adev: amdgpu_device pointer
284d38ceaf9SAlex Deucher  *
285d38ceaf9SAlex Deucher  */
amdgpu_vce_resume(struct amdgpu_device * adev)286d38ceaf9SAlex Deucher int amdgpu_vce_resume(struct amdgpu_device *adev)
287d38ceaf9SAlex Deucher {
288d38ceaf9SAlex Deucher 	void *cpu_addr;
289d38ceaf9SAlex Deucher 	const struct common_firmware_header *hdr;
290f10984a3SSrinivasan Shanmugam 	unsigned int offset;
291f89f8c6bSAndrey Grodzovsky 	int r, idx;
292d38ceaf9SAlex Deucher 
293d38ceaf9SAlex Deucher 	if (adev->vce.vcpu_bo == NULL)
294d38ceaf9SAlex Deucher 		return -EINVAL;
295d38ceaf9SAlex Deucher 
296d38ceaf9SAlex Deucher 	r = amdgpu_bo_reserve(adev->vce.vcpu_bo, false);
297d38ceaf9SAlex Deucher 	if (r) {
298d38ceaf9SAlex Deucher 		dev_err(adev->dev, "(%d) failed to reserve VCE bo\n", r);
299d38ceaf9SAlex Deucher 		return r;
300d38ceaf9SAlex Deucher 	}
301d38ceaf9SAlex Deucher 
302d38ceaf9SAlex Deucher 	r = amdgpu_bo_kmap(adev->vce.vcpu_bo, &cpu_addr);
303d38ceaf9SAlex Deucher 	if (r) {
304d38ceaf9SAlex Deucher 		amdgpu_bo_unreserve(adev->vce.vcpu_bo);
305d38ceaf9SAlex Deucher 		dev_err(adev->dev, "(%d) VCE map failed\n", r);
306d38ceaf9SAlex Deucher 		return r;
307d38ceaf9SAlex Deucher 	}
308d38ceaf9SAlex Deucher 
309d38ceaf9SAlex Deucher 	hdr = (const struct common_firmware_header *)adev->vce.fw->data;
310d38ceaf9SAlex Deucher 	offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
311f89f8c6bSAndrey Grodzovsky 
312c58a863bSGuchun Chen 	if (drm_dev_enter(adev_to_drm(adev), &idx)) {
3137b4d3e29SChristian König 		memcpy_toio(cpu_addr, adev->vce.fw->data + offset,
3147b4d3e29SChristian König 			    adev->vce.fw->size - offset);
315f89f8c6bSAndrey Grodzovsky 		drm_dev_exit(idx);
316f89f8c6bSAndrey Grodzovsky 	}
317d38ceaf9SAlex Deucher 
318d38ceaf9SAlex Deucher 	amdgpu_bo_kunmap(adev->vce.vcpu_bo);
319d38ceaf9SAlex Deucher 
320d38ceaf9SAlex Deucher 	amdgpu_bo_unreserve(adev->vce.vcpu_bo);
321d38ceaf9SAlex Deucher 
322d38ceaf9SAlex Deucher 	return 0;
323d38ceaf9SAlex Deucher }
324d38ceaf9SAlex Deucher 
325d38ceaf9SAlex Deucher /**
326d38ceaf9SAlex Deucher  * amdgpu_vce_idle_work_handler - power off VCE
327d38ceaf9SAlex Deucher  *
328d38ceaf9SAlex Deucher  * @work: pointer to work structure
329d38ceaf9SAlex Deucher  *
330d38ceaf9SAlex Deucher  * power of VCE when it's not used any more
331d38ceaf9SAlex Deucher  */
amdgpu_vce_idle_work_handler(struct work_struct * work)332d38ceaf9SAlex Deucher static void amdgpu_vce_idle_work_handler(struct work_struct *work)
333d38ceaf9SAlex Deucher {
334d38ceaf9SAlex Deucher 	struct amdgpu_device *adev =
335d38ceaf9SAlex Deucher 		container_of(work, struct amdgpu_device, vce.idle_work.work);
336f10984a3SSrinivasan Shanmugam 	unsigned int i, count = 0;
337d38ceaf9SAlex Deucher 
33824c5fe56SAlex Deucher 	for (i = 0; i < adev->vce.num_rings; i++)
33924c5fe56SAlex Deucher 		count += amdgpu_fence_count_emitted(&adev->vce.ring[i]);
34024c5fe56SAlex Deucher 
34124c5fe56SAlex Deucher 	if (count == 0) {
342d38ceaf9SAlex Deucher 		if (adev->pm.dpm_enabled) {
343d38ceaf9SAlex Deucher 			amdgpu_dpm_enable_vce(adev, false);
344d38ceaf9SAlex Deucher 		} else {
345d38ceaf9SAlex Deucher 			amdgpu_asic_set_vce_clocks(adev, 0, 0);
3462990a1fcSAlex Deucher 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
34728ed5504SRex Zhu 							       AMD_PG_STATE_GATE);
3482990a1fcSAlex Deucher 			amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
34928ed5504SRex Zhu 							       AMD_CG_STATE_GATE);
350d38ceaf9SAlex Deucher 		}
351d38ceaf9SAlex Deucher 	} else {
352182830a1SChristian König 		schedule_delayed_work(&adev->vce.idle_work, VCE_IDLE_TIMEOUT);
353d38ceaf9SAlex Deucher 	}
354d38ceaf9SAlex Deucher }
355d38ceaf9SAlex Deucher 
356d38ceaf9SAlex Deucher /**
357ebff485eSChristian König  * amdgpu_vce_ring_begin_use - power up VCE
358d38ceaf9SAlex Deucher  *
359ebff485eSChristian König  * @ring: amdgpu ring
360d38ceaf9SAlex Deucher  *
361d38ceaf9SAlex Deucher  * Make sure VCE is powerd up when we want to use it
362d38ceaf9SAlex Deucher  */
amdgpu_vce_ring_begin_use(struct amdgpu_ring * ring)363ebff485eSChristian König void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring)
364d38ceaf9SAlex Deucher {
365ebff485eSChristian König 	struct amdgpu_device *adev = ring->adev;
366ebff485eSChristian König 	bool set_clocks;
367182830a1SChristian König 
368d9af2259SXiangliang Yu 	if (amdgpu_sriov_vf(adev))
369d9af2259SXiangliang Yu 		return;
370d9af2259SXiangliang Yu 
371ebff485eSChristian König 	mutex_lock(&adev->vce.idle_mutex);
372ebff485eSChristian König 	set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work);
373182830a1SChristian König 	if (set_clocks) {
374d38ceaf9SAlex Deucher 		if (adev->pm.dpm_enabled) {
375d38ceaf9SAlex Deucher 			amdgpu_dpm_enable_vce(adev, true);
376d38ceaf9SAlex Deucher 		} else {
377d38ceaf9SAlex Deucher 			amdgpu_asic_set_vce_clocks(adev, 53300, 40000);
3782990a1fcSAlex Deucher 			amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
37928ed5504SRex Zhu 							       AMD_CG_STATE_UNGATE);
3802990a1fcSAlex Deucher 			amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
38128ed5504SRex Zhu 							       AMD_PG_STATE_UNGATE);
38228ed5504SRex Zhu 
383d38ceaf9SAlex Deucher 		}
384d38ceaf9SAlex Deucher 	}
385ebff485eSChristian König 	mutex_unlock(&adev->vce.idle_mutex);
386ebff485eSChristian König }
387ebff485eSChristian König 
388ebff485eSChristian König /**
389ebff485eSChristian König  * amdgpu_vce_ring_end_use - power VCE down
390ebff485eSChristian König  *
391ebff485eSChristian König  * @ring: amdgpu ring
392ebff485eSChristian König  *
393ebff485eSChristian König  * Schedule work to power VCE down again
394ebff485eSChristian König  */
amdgpu_vce_ring_end_use(struct amdgpu_ring * ring)395ebff485eSChristian König void amdgpu_vce_ring_end_use(struct amdgpu_ring *ring)
396ebff485eSChristian König {
39714a8032aSMonk Liu 	if (!amdgpu_sriov_vf(ring->adev))
398ebff485eSChristian König 		schedule_delayed_work(&ring->adev->vce.idle_work, VCE_IDLE_TIMEOUT);
399d38ceaf9SAlex Deucher }
400d38ceaf9SAlex Deucher 
401d38ceaf9SAlex Deucher /**
402d38ceaf9SAlex Deucher  * amdgpu_vce_free_handles - free still open VCE handles
403d38ceaf9SAlex Deucher  *
404d38ceaf9SAlex Deucher  * @adev: amdgpu_device pointer
405d38ceaf9SAlex Deucher  * @filp: drm file pointer
406d38ceaf9SAlex Deucher  *
407d38ceaf9SAlex Deucher  * Close all VCE handles still open by this file pointer
408d38ceaf9SAlex Deucher  */
amdgpu_vce_free_handles(struct amdgpu_device * adev,struct drm_file * filp)409d38ceaf9SAlex Deucher void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
410d38ceaf9SAlex Deucher {
411d38ceaf9SAlex Deucher 	struct amdgpu_ring *ring = &adev->vce.ring[0];
412d38ceaf9SAlex Deucher 	int i, r;
413f10984a3SSrinivasan Shanmugam 
414d38ceaf9SAlex Deucher 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
415d38ceaf9SAlex Deucher 		uint32_t handle = atomic_read(&adev->vce.handles[i]);
416182830a1SChristian König 
417d38ceaf9SAlex Deucher 		if (!handle || adev->vce.filp[i] != filp)
418d38ceaf9SAlex Deucher 			continue;
419d38ceaf9SAlex Deucher 
4209f2ade33SChristian König 		r = amdgpu_vce_get_destroy_msg(ring, handle, false, NULL);
421d38ceaf9SAlex Deucher 		if (r)
422d38ceaf9SAlex Deucher 			DRM_ERROR("Error destroying VCE handle (%d)!\n", r);
423d38ceaf9SAlex Deucher 
424d38ceaf9SAlex Deucher 		adev->vce.filp[i] = NULL;
425d38ceaf9SAlex Deucher 		atomic_set(&adev->vce.handles[i], 0);
426d38ceaf9SAlex Deucher 	}
427d38ceaf9SAlex Deucher }
428d38ceaf9SAlex Deucher 
429d38ceaf9SAlex Deucher /**
430d38ceaf9SAlex Deucher  * amdgpu_vce_get_create_msg - generate a VCE create msg
431d38ceaf9SAlex Deucher  *
432d38ceaf9SAlex Deucher  * @ring: ring we should submit the msg to
433d38ceaf9SAlex Deucher  * @handle: VCE session handle to use
434d38ceaf9SAlex Deucher  * @fence: optional fence to return
435d38ceaf9SAlex Deucher  *
436d38ceaf9SAlex Deucher  * Open up a stream for HW test
437d38ceaf9SAlex Deucher  */
amdgpu_vce_get_create_msg(struct amdgpu_ring * ring,uint32_t handle,struct dma_fence ** fence)43817523bd0SAlex Deucher static int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
439f54d1867SChris Wilson 				     struct dma_fence **fence)
440d38ceaf9SAlex Deucher {
441f10984a3SSrinivasan Shanmugam 	const unsigned int ib_size_dw = 1024;
442d71518b5SChristian König 	struct amdgpu_job *job;
443d71518b5SChristian König 	struct amdgpu_ib *ib;
444cb9038aaSxinhui pan 	struct amdgpu_ib ib_msg;
445f54d1867SChris Wilson 	struct dma_fence *f = NULL;
446569557e5SAlex Deucher 	uint64_t addr;
447d38ceaf9SAlex Deucher 	int i, r;
448d38ceaf9SAlex Deucher 
449f7d66fb2SChristian König 	r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity,
450f7d66fb2SChristian König 				     AMDGPU_FENCE_OWNER_UNDEFINED,
451f7d66fb2SChristian König 				     ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT,
452f7d66fb2SChristian König 				     &job);
453d71518b5SChristian König 	if (r)
454d38ceaf9SAlex Deucher 		return r;
455d71518b5SChristian König 
456cb9038aaSxinhui pan 	memset(&ib_msg, 0, sizeof(ib_msg));
457cb9038aaSxinhui pan 	/* only one gpu page is needed, alloc +1 page to make addr aligned. */
458cb9038aaSxinhui pan 	r = amdgpu_ib_get(ring->adev, NULL, AMDGPU_GPU_PAGE_SIZE * 2,
459cb9038aaSxinhui pan 			  AMDGPU_IB_POOL_DIRECT,
460cb9038aaSxinhui pan 			  &ib_msg);
461cb9038aaSxinhui pan 	if (r)
462cb9038aaSxinhui pan 		goto err;
463d38ceaf9SAlex Deucher 
464cb9038aaSxinhui pan 	ib = &job->ibs[0];
465cb9038aaSxinhui pan 	/* let addr point to page boundary */
466cb9038aaSxinhui pan 	addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg.gpu_addr);
467d38ceaf9SAlex Deucher 
468d38ceaf9SAlex Deucher 	/* stitch together an VCE create msg */
4698128765cSChunming Zhou 	ib->length_dw = 0;
4708128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x0000000c; /* len */
4718128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
4728128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = handle;
473d38ceaf9SAlex Deucher 
474d66f8e48SLeo Liu 	if ((ring->adev->vce.fw_version >> 24) >= 52)
475d66f8e48SLeo Liu 		ib->ptr[ib->length_dw++] = 0x00000040; /* len */
476d66f8e48SLeo Liu 	else
4778128765cSChunming Zhou 		ib->ptr[ib->length_dw++] = 0x00000030; /* len */
4788128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x01000001; /* create cmd */
4798128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000000;
4808128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000042;
4818128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x0000000a;
4828128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000001;
4838128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000080;
4848128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000060;
4858128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000100;
4868128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000100;
4878128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x0000000c;
4888128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000000;
489d66f8e48SLeo Liu 	if ((ring->adev->vce.fw_version >> 24) >= 52) {
490d66f8e48SLeo Liu 		ib->ptr[ib->length_dw++] = 0x00000000;
491d66f8e48SLeo Liu 		ib->ptr[ib->length_dw++] = 0x00000000;
492d66f8e48SLeo Liu 		ib->ptr[ib->length_dw++] = 0x00000000;
493d66f8e48SLeo Liu 		ib->ptr[ib->length_dw++] = 0x00000000;
494d66f8e48SLeo Liu 	}
495d38ceaf9SAlex Deucher 
4968128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000014; /* len */
4978128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */
498569557e5SAlex Deucher 	ib->ptr[ib->length_dw++] = upper_32_bits(addr);
499569557e5SAlex Deucher 	ib->ptr[ib->length_dw++] = addr;
5008128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000001;
501d38ceaf9SAlex Deucher 
5028128765cSChunming Zhou 	for (i = ib->length_dw; i < ib_size_dw; ++i)
5038128765cSChunming Zhou 		ib->ptr[i] = 0x0;
504d38ceaf9SAlex Deucher 
505ee913fd9SChristian König 	r = amdgpu_job_submit_direct(job, ring, &f);
506*0014952bSPierre-Eric Pelloux-Prayer 	amdgpu_ib_free(&ib_msg, f);
5078128765cSChunming Zhou 	if (r)
5088128765cSChunming Zhou 		goto err;
5099f2ade33SChristian König 
510d38ceaf9SAlex Deucher 	if (fence)
511f54d1867SChris Wilson 		*fence = dma_fence_get(f);
512f54d1867SChris Wilson 	dma_fence_put(f);
5138128765cSChunming Zhou 	return 0;
514d71518b5SChristian König 
5158128765cSChunming Zhou err:
516d71518b5SChristian König 	amdgpu_job_free(job);
517d38ceaf9SAlex Deucher 	return r;
518d38ceaf9SAlex Deucher }
519d38ceaf9SAlex Deucher 
520d38ceaf9SAlex Deucher /**
521d38ceaf9SAlex Deucher  * amdgpu_vce_get_destroy_msg - generate a VCE destroy msg
522d38ceaf9SAlex Deucher  *
523d38ceaf9SAlex Deucher  * @ring: ring we should submit the msg to
524d38ceaf9SAlex Deucher  * @handle: VCE session handle to use
525184b762dSLee Jones  * @direct: direct or delayed pool
526d38ceaf9SAlex Deucher  * @fence: optional fence to return
527d38ceaf9SAlex Deucher  *
528d38ceaf9SAlex Deucher  * Close up a stream for HW test or if userspace failed to do so
529d38ceaf9SAlex Deucher  */
amdgpu_vce_get_destroy_msg(struct amdgpu_ring * ring,uint32_t handle,bool direct,struct dma_fence ** fence)53017523bd0SAlex Deucher static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
531f54d1867SChris Wilson 				      bool direct, struct dma_fence **fence)
532d38ceaf9SAlex Deucher {
533f10984a3SSrinivasan Shanmugam 	const unsigned int ib_size_dw = 1024;
534d71518b5SChristian König 	struct amdgpu_job *job;
535d71518b5SChristian König 	struct amdgpu_ib *ib;
536f54d1867SChris Wilson 	struct dma_fence *f = NULL;
537d38ceaf9SAlex Deucher 	int i, r;
538d38ceaf9SAlex Deucher 
539f7d66fb2SChristian König 	r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity,
540f7d66fb2SChristian König 				     AMDGPU_FENCE_OWNER_UNDEFINED,
541f7d66fb2SChristian König 				     ib_size_dw * 4,
5429ecefb19SChristian König 				     direct ? AMDGPU_IB_POOL_DIRECT :
5439ecefb19SChristian König 				     AMDGPU_IB_POOL_DELAYED, &job);
544d71518b5SChristian König 	if (r)
545d38ceaf9SAlex Deucher 		return r;
546d38ceaf9SAlex Deucher 
547d71518b5SChristian König 	ib = &job->ibs[0];
548d38ceaf9SAlex Deucher 
549d38ceaf9SAlex Deucher 	/* stitch together an VCE destroy msg */
5508128765cSChunming Zhou 	ib->length_dw = 0;
5518128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x0000000c; /* len */
5528128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
5538128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = handle;
554d38ceaf9SAlex Deucher 
55599453a9eSRex Zhu 	ib->ptr[ib->length_dw++] = 0x00000020; /* len */
55699453a9eSRex Zhu 	ib->ptr[ib->length_dw++] = 0x00000002; /* task info */
55799453a9eSRex Zhu 	ib->ptr[ib->length_dw++] = 0xffffffff; /* next task info, set to 0xffffffff if no */
55899453a9eSRex Zhu 	ib->ptr[ib->length_dw++] = 0x00000001; /* destroy session */
55999453a9eSRex Zhu 	ib->ptr[ib->length_dw++] = 0x00000000;
56099453a9eSRex Zhu 	ib->ptr[ib->length_dw++] = 0x00000000;
56199453a9eSRex Zhu 	ib->ptr[ib->length_dw++] = 0xffffffff; /* feedback is not needed, set to 0xffffffff and firmware will not output feedback */
56299453a9eSRex Zhu 	ib->ptr[ib->length_dw++] = 0x00000000;
563d38ceaf9SAlex Deucher 
5648128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x00000008; /* len */
5658128765cSChunming Zhou 	ib->ptr[ib->length_dw++] = 0x02000001; /* destroy cmd */
566d38ceaf9SAlex Deucher 
5678128765cSChunming Zhou 	for (i = ib->length_dw; i < ib_size_dw; ++i)
5688128765cSChunming Zhou 		ib->ptr[i] = 0x0;
5699f2ade33SChristian König 
570ee913fd9SChristian König 	if (direct)
571ee913fd9SChristian König 		r = amdgpu_job_submit_direct(job, ring, &f);
572ee913fd9SChristian König 	else
573f7d66fb2SChristian König 		f = amdgpu_job_submit(job);
5749f2ade33SChristian König 	if (r)
5759f2ade33SChristian König 		goto err;
5769f2ade33SChristian König 
577d38ceaf9SAlex Deucher 	if (fence)
578f54d1867SChris Wilson 		*fence = dma_fence_get(f);
579f54d1867SChris Wilson 	dma_fence_put(f);
5808128765cSChunming Zhou 	return 0;
581d71518b5SChristian König 
5828128765cSChunming Zhou err:
583d71518b5SChristian König 	amdgpu_job_free(job);
584d38ceaf9SAlex Deucher 	return r;
585d38ceaf9SAlex Deucher }
586d38ceaf9SAlex Deucher 
587d38ceaf9SAlex Deucher /**
5881c7f15c7SLee Jones  * amdgpu_vce_validate_bo - make sure not to cross 4GB boundary
58923594318SChristian König  *
590a37558e6SLee Jones  * @p: cs parser
591cdc7893fSChristian König  * @ib: indirect buffer to use
59223594318SChristian König  * @lo: address of lower dword
59323594318SChristian König  * @hi: address of higher dword
59423594318SChristian König  * @size: minimum size
59523594318SChristian König  * @index: bs/fb index
59623594318SChristian König  *
59723594318SChristian König  * Make sure that no BO cross a 4GB boundary.
59823594318SChristian König  */
amdgpu_vce_validate_bo(struct amdgpu_cs_parser * p,struct amdgpu_ib * ib,int lo,int hi,unsigned int size,int32_t index)599cdc7893fSChristian König static int amdgpu_vce_validate_bo(struct amdgpu_cs_parser *p,
600cdc7893fSChristian König 				  struct amdgpu_ib *ib, int lo, int hi,
601f10984a3SSrinivasan Shanmugam 				  unsigned int size, int32_t index)
60223594318SChristian König {
60323594318SChristian König 	int64_t offset = ((uint64_t)size) * ((int64_t)index);
60419be5570SChristian König 	struct ttm_operation_ctx ctx = { false, false };
60523594318SChristian König 	struct amdgpu_bo_va_mapping *mapping;
606f10984a3SSrinivasan Shanmugam 	unsigned int i, fpfn, lpfn;
60723594318SChristian König 	struct amdgpu_bo *bo;
60823594318SChristian König 	uint64_t addr;
60923594318SChristian König 	int r;
61023594318SChristian König 
611cdc7893fSChristian König 	addr = ((uint64_t)amdgpu_ib_get_value(ib, lo)) |
612cdc7893fSChristian König 	       ((uint64_t)amdgpu_ib_get_value(ib, hi)) << 32;
61323594318SChristian König 	if (index >= 0) {
61423594318SChristian König 		addr += offset;
61523594318SChristian König 		fpfn = PAGE_ALIGN(offset) >> PAGE_SHIFT;
61623594318SChristian König 		lpfn = 0x100000000ULL >> PAGE_SHIFT;
61723594318SChristian König 	} else {
61823594318SChristian König 		fpfn = 0;
61923594318SChristian König 		lpfn = (0x100000000ULL - PAGE_ALIGN(offset)) >> PAGE_SHIFT;
62023594318SChristian König 	}
62123594318SChristian König 
62223594318SChristian König 	r = amdgpu_cs_find_mapping(p, addr, &bo, &mapping);
62323594318SChristian König 	if (r) {
624f10984a3SSrinivasan Shanmugam 		DRM_ERROR("Can't find BO for addr 0x%010llx %d %d %d %d\n",
62523594318SChristian König 			  addr, lo, hi, size, index);
62623594318SChristian König 		return r;
62723594318SChristian König 	}
62823594318SChristian König 
62923594318SChristian König 	for (i = 0; i < bo->placement.num_placement; ++i) {
63023594318SChristian König 		bo->placements[i].fpfn = max(bo->placements[i].fpfn, fpfn);
6314c63abb2SChristian König 		bo->placements[i].lpfn = bo->placements[i].lpfn ?
6324c63abb2SChristian König 			min(bo->placements[i].lpfn, lpfn) : lpfn;
63323594318SChristian König 	}
63419be5570SChristian König 	return ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
63523594318SChristian König }
63623594318SChristian König 
63723594318SChristian König 
63823594318SChristian König /**
639d38ceaf9SAlex Deucher  * amdgpu_vce_cs_reloc - command submission relocation
640d38ceaf9SAlex Deucher  *
641d38ceaf9SAlex Deucher  * @p: parser context
642cdc7893fSChristian König  * @ib: indirect buffer to use
643d38ceaf9SAlex Deucher  * @lo: address of lower dword
644d38ceaf9SAlex Deucher  * @hi: address of higher dword
645f1689ec1SChristian König  * @size: minimum size
646184b762dSLee Jones  * @index: bs/fb index
647d38ceaf9SAlex Deucher  *
648d38ceaf9SAlex Deucher  * Patch relocation inside command stream with real buffer address
649d38ceaf9SAlex Deucher  */
amdgpu_vce_cs_reloc(struct amdgpu_cs_parser * p,struct amdgpu_ib * ib,int lo,int hi,unsigned int size,uint32_t index)650cdc7893fSChristian König static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib,
651f10984a3SSrinivasan Shanmugam 			       int lo, int hi, unsigned int size, uint32_t index)
652d38ceaf9SAlex Deucher {
653d38ceaf9SAlex Deucher 	struct amdgpu_bo_va_mapping *mapping;
654d38ceaf9SAlex Deucher 	struct amdgpu_bo *bo;
655d38ceaf9SAlex Deucher 	uint64_t addr;
6569cca0b8eSChristian König 	int r;
657d38ceaf9SAlex Deucher 
658dc78330aSChristian König 	if (index == 0xffffffff)
659dc78330aSChristian König 		index = 0;
660dc78330aSChristian König 
661cdc7893fSChristian König 	addr = ((uint64_t)amdgpu_ib_get_value(ib, lo)) |
662cdc7893fSChristian König 	       ((uint64_t)amdgpu_ib_get_value(ib, hi)) << 32;
663dc78330aSChristian König 	addr += ((uint64_t)size) * ((uint64_t)index);
664d38ceaf9SAlex Deucher 
6659cca0b8eSChristian König 	r = amdgpu_cs_find_mapping(p, addr, &bo, &mapping);
6669cca0b8eSChristian König 	if (r) {
667f10984a3SSrinivasan Shanmugam 		DRM_ERROR("Can't find BO for addr 0x%010llx %d %d %d %d\n",
668dc78330aSChristian König 			  addr, lo, hi, size, index);
6699cca0b8eSChristian König 		return r;
670d38ceaf9SAlex Deucher 	}
671d38ceaf9SAlex Deucher 
672f1689ec1SChristian König 	if ((addr + (uint64_t)size) >
673a9f87f64SChristian König 	    (mapping->last + 1) * AMDGPU_GPU_PAGE_SIZE) {
674f10984a3SSrinivasan Shanmugam 		DRM_ERROR("BO too small for addr 0x%010llx %d %d\n",
675f1689ec1SChristian König 			  addr, lo, hi);
676f1689ec1SChristian König 		return -EINVAL;
677f1689ec1SChristian König 	}
678f1689ec1SChristian König 
679a9f87f64SChristian König 	addr -= mapping->start * AMDGPU_GPU_PAGE_SIZE;
680d38ceaf9SAlex Deucher 	addr += amdgpu_bo_gpu_offset(bo);
681dc78330aSChristian König 	addr -= ((uint64_t)size) * ((uint64_t)index);
682d38ceaf9SAlex Deucher 
683cdc7893fSChristian König 	amdgpu_ib_set_value(ib, lo, lower_32_bits(addr));
684cdc7893fSChristian König 	amdgpu_ib_set_value(ib, hi, upper_32_bits(addr));
685d38ceaf9SAlex Deucher 
686d38ceaf9SAlex Deucher 	return 0;
687d38ceaf9SAlex Deucher }
688d38ceaf9SAlex Deucher 
689d38ceaf9SAlex Deucher /**
690f1689ec1SChristian König  * amdgpu_vce_validate_handle - validate stream handle
691f1689ec1SChristian König  *
692f1689ec1SChristian König  * @p: parser context
693f1689ec1SChristian König  * @handle: handle to validate
6942f4b9368SChristian König  * @allocated: allocated a new handle?
695f1689ec1SChristian König  *
696f1689ec1SChristian König  * Validates the handle and return the found session index or -EINVAL
697f10984a3SSrinivasan Shanmugam  * we don't have another free session index.
698f1689ec1SChristian König  */
amdgpu_vce_validate_handle(struct amdgpu_cs_parser * p,uint32_t handle,uint32_t * allocated)699f1689ec1SChristian König static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p,
700e5223214SChristian König 				      uint32_t handle, uint32_t *allocated)
701f1689ec1SChristian König {
702f10984a3SSrinivasan Shanmugam 	unsigned int i;
703f1689ec1SChristian König 
704f1689ec1SChristian König 	/* validate the handle */
705f1689ec1SChristian König 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
7062f4b9368SChristian König 		if (atomic_read(&p->adev->vce.handles[i]) == handle) {
7072f4b9368SChristian König 			if (p->adev->vce.filp[i] != p->filp) {
7082f4b9368SChristian König 				DRM_ERROR("VCE handle collision detected!\n");
7092f4b9368SChristian König 				return -EINVAL;
7102f4b9368SChristian König 			}
711f1689ec1SChristian König 			return i;
712f1689ec1SChristian König 		}
7132f4b9368SChristian König 	}
714f1689ec1SChristian König 
715f1689ec1SChristian König 	/* handle not found try to alloc a new one */
716f1689ec1SChristian König 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
717f1689ec1SChristian König 		if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) {
718f1689ec1SChristian König 			p->adev->vce.filp[i] = p->filp;
719f1689ec1SChristian König 			p->adev->vce.img_size[i] = 0;
720e5223214SChristian König 			*allocated |= 1 << i;
721f1689ec1SChristian König 			return i;
722f1689ec1SChristian König 		}
723f1689ec1SChristian König 	}
724f1689ec1SChristian König 
725f1689ec1SChristian König 	DRM_ERROR("No more free VCE handles!\n");
726f1689ec1SChristian König 	return -EINVAL;
727f1689ec1SChristian König }
728f1689ec1SChristian König 
729f1689ec1SChristian König /**
7301c7f15c7SLee Jones  * amdgpu_vce_ring_parse_cs - parse and validate the command stream
731d38ceaf9SAlex Deucher  *
732d38ceaf9SAlex Deucher  * @p: parser context
733cdc7893fSChristian König  * @job: the job to parse
734cdc7893fSChristian König  * @ib: the IB to patch
735d38ceaf9SAlex Deucher  */
amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser * p,struct amdgpu_job * job,struct amdgpu_ib * ib)736cdc7893fSChristian König int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p,
737cdc7893fSChristian König 			     struct amdgpu_job *job,
738cdc7893fSChristian König 			     struct amdgpu_ib *ib)
739d38ceaf9SAlex Deucher {
740f10984a3SSrinivasan Shanmugam 	unsigned int fb_idx = 0, bs_idx = 0;
741f1689ec1SChristian König 	int session_idx = -1;
742e5223214SChristian König 	uint32_t destroyed = 0;
743e5223214SChristian König 	uint32_t created = 0;
744e5223214SChristian König 	uint32_t allocated = 0;
745f1689ec1SChristian König 	uint32_t tmp, handle = 0;
74688a9a467SJesse Zhang 	uint32_t dummy = 0xffffffff;
74788a9a467SJesse Zhang 	uint32_t *size = &dummy;
748f10984a3SSrinivasan Shanmugam 	unsigned int idx;
74923594318SChristian König 	int i, r = 0;
750c855e250SChristian König 
751cdc7893fSChristian König 	job->vm = NULL;
75245088efcSChristian König 
75323594318SChristian König 	for (idx = 0; idx < ib->length_dw;) {
754cdc7893fSChristian König 		uint32_t len = amdgpu_ib_get_value(ib, idx);
755cdc7893fSChristian König 		uint32_t cmd = amdgpu_ib_get_value(ib, idx + 1);
756d38ceaf9SAlex Deucher 
757d38ceaf9SAlex Deucher 		if ((len < 8) || (len & 3)) {
758d38ceaf9SAlex Deucher 			DRM_ERROR("invalid VCE command length (%d)!\n", len);
7592f4b9368SChristian König 			r = -EINVAL;
7602f4b9368SChristian König 			goto out;
761d38ceaf9SAlex Deucher 		}
762d38ceaf9SAlex Deucher 
763d38ceaf9SAlex Deucher 		switch (cmd) {
76423594318SChristian König 		case 0x00000002: /* task info */
765cdc7893fSChristian König 			fb_idx = amdgpu_ib_get_value(ib, idx + 6);
766cdc7893fSChristian König 			bs_idx = amdgpu_ib_get_value(ib, idx + 7);
76723594318SChristian König 			break;
76823594318SChristian König 
76923594318SChristian König 		case 0x03000001: /* encode */
770cdc7893fSChristian König 			r = amdgpu_vce_validate_bo(p, ib, idx + 10, idx + 9,
771cdc7893fSChristian König 						   0, 0);
77223594318SChristian König 			if (r)
77323594318SChristian König 				goto out;
77423594318SChristian König 
775cdc7893fSChristian König 			r = amdgpu_vce_validate_bo(p, ib, idx + 12, idx + 11,
776cdc7893fSChristian König 						   0, 0);
77723594318SChristian König 			if (r)
77823594318SChristian König 				goto out;
77923594318SChristian König 			break;
78023594318SChristian König 
78123594318SChristian König 		case 0x05000001: /* context buffer */
782cdc7893fSChristian König 			r = amdgpu_vce_validate_bo(p, ib, idx + 3, idx + 2,
783cdc7893fSChristian König 						   0, 0);
78423594318SChristian König 			if (r)
78523594318SChristian König 				goto out;
78623594318SChristian König 			break;
78723594318SChristian König 
78823594318SChristian König 		case 0x05000004: /* video bitstream buffer */
789cdc7893fSChristian König 			tmp = amdgpu_ib_get_value(ib, idx + 4);
790cdc7893fSChristian König 			r = amdgpu_vce_validate_bo(p, ib, idx + 3, idx + 2,
79123594318SChristian König 						   tmp, bs_idx);
79223594318SChristian König 			if (r)
79323594318SChristian König 				goto out;
79423594318SChristian König 			break;
79523594318SChristian König 
79623594318SChristian König 		case 0x05000005: /* feedback buffer */
797cdc7893fSChristian König 			r = amdgpu_vce_validate_bo(p, ib, idx + 3, idx + 2,
79823594318SChristian König 						   4096, fb_idx);
79923594318SChristian König 			if (r)
80023594318SChristian König 				goto out;
80123594318SChristian König 			break;
8021eb1547fSJames Zhu 
8031eb1547fSJames Zhu 		case 0x0500000d: /* MV buffer */
804cdc7893fSChristian König 			r = amdgpu_vce_validate_bo(p, ib, idx + 3, idx + 2,
805cdc7893fSChristian König 						   0, 0);
8061eb1547fSJames Zhu 			if (r)
8071eb1547fSJames Zhu 				goto out;
8081eb1547fSJames Zhu 
809cdc7893fSChristian König 			r = amdgpu_vce_validate_bo(p, ib, idx + 8, idx + 7,
810cdc7893fSChristian König 						   0, 0);
8111eb1547fSJames Zhu 			if (r)
8121eb1547fSJames Zhu 				goto out;
8131eb1547fSJames Zhu 			break;
81423594318SChristian König 		}
81523594318SChristian König 
81623594318SChristian König 		idx += len / 4;
81723594318SChristian König 	}
81823594318SChristian König 
81923594318SChristian König 	for (idx = 0; idx < ib->length_dw;) {
820cdc7893fSChristian König 		uint32_t len = amdgpu_ib_get_value(ib, idx);
821cdc7893fSChristian König 		uint32_t cmd = amdgpu_ib_get_value(ib, idx + 1);
82223594318SChristian König 
82323594318SChristian König 		switch (cmd) {
824182830a1SChristian König 		case 0x00000001: /* session */
825cdc7893fSChristian König 			handle = amdgpu_ib_get_value(ib, idx + 2);
8262f4b9368SChristian König 			session_idx = amdgpu_vce_validate_handle(p, handle,
8272f4b9368SChristian König 								 &allocated);
828e5223214SChristian König 			if (session_idx < 0) {
829e5223214SChristian König 				r = session_idx;
830e5223214SChristian König 				goto out;
831e5223214SChristian König 			}
832f1689ec1SChristian König 			size = &p->adev->vce.img_size[session_idx];
833d38ceaf9SAlex Deucher 			break;
834d38ceaf9SAlex Deucher 
835182830a1SChristian König 		case 0x00000002: /* task info */
836cdc7893fSChristian König 			fb_idx = amdgpu_ib_get_value(ib, idx + 6);
837cdc7893fSChristian König 			bs_idx = amdgpu_ib_get_value(ib, idx + 7);
838f1689ec1SChristian König 			break;
839f1689ec1SChristian König 
840182830a1SChristian König 		case 0x01000001: /* create */
841e5223214SChristian König 			created |= 1 << session_idx;
842e5223214SChristian König 			if (destroyed & (1 << session_idx)) {
843e5223214SChristian König 				destroyed &= ~(1 << session_idx);
844e5223214SChristian König 				allocated |= 1 << session_idx;
845e5223214SChristian König 
846e5223214SChristian König 			} else if (!(allocated & (1 << session_idx))) {
8472f4b9368SChristian König 				DRM_ERROR("Handle already in use!\n");
8482f4b9368SChristian König 				r = -EINVAL;
8492f4b9368SChristian König 				goto out;
8502f4b9368SChristian König 			}
8512f4b9368SChristian König 
852cdc7893fSChristian König 			*size = amdgpu_ib_get_value(ib, idx + 8) *
853cdc7893fSChristian König 				amdgpu_ib_get_value(ib, idx + 10) *
854f1689ec1SChristian König 				8 * 3 / 2;
855f1689ec1SChristian König 			break;
856f1689ec1SChristian König 
857182830a1SChristian König 		case 0x04000001: /* config extension */
858182830a1SChristian König 		case 0x04000002: /* pic control */
859182830a1SChristian König 		case 0x04000005: /* rate control */
860182830a1SChristian König 		case 0x04000007: /* motion estimation */
861182830a1SChristian König 		case 0x04000008: /* rdo */
862182830a1SChristian König 		case 0x04000009: /* vui */
863182830a1SChristian König 		case 0x05000002: /* auxiliary buffer */
8644f827785SAlex Deucher 		case 0x05000009: /* clock table */
865d38ceaf9SAlex Deucher 			break;
866d38ceaf9SAlex Deucher 
8675eeda8a4SAlex Deucher 		case 0x0500000c: /* hw config */
8685eeda8a4SAlex Deucher 			switch (p->adev->asic_type) {
8695eeda8a4SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_CIK
8705eeda8a4SAlex Deucher 			case CHIP_KAVERI:
8715eeda8a4SAlex Deucher 			case CHIP_MULLINS:
8725eeda8a4SAlex Deucher #endif
8735eeda8a4SAlex Deucher 			case CHIP_CARRIZO:
8745eeda8a4SAlex Deucher 				break;
8755eeda8a4SAlex Deucher 			default:
8765eeda8a4SAlex Deucher 				r = -EINVAL;
8775eeda8a4SAlex Deucher 				goto out;
8785eeda8a4SAlex Deucher 			}
8795eeda8a4SAlex Deucher 			break;
8805eeda8a4SAlex Deucher 
881182830a1SChristian König 		case 0x03000001: /* encode */
882cdc7893fSChristian König 			r = amdgpu_vce_cs_reloc(p, ib, idx + 10, idx + 9,
883dc78330aSChristian König 						*size, 0);
884d38ceaf9SAlex Deucher 			if (r)
8852f4b9368SChristian König 				goto out;
886d38ceaf9SAlex Deucher 
887cdc7893fSChristian König 			r = amdgpu_vce_cs_reloc(p, ib, idx + 12, idx + 11,
888dc78330aSChristian König 						*size / 3, 0);
889d38ceaf9SAlex Deucher 			if (r)
8902f4b9368SChristian König 				goto out;
891d38ceaf9SAlex Deucher 			break;
892d38ceaf9SAlex Deucher 
893182830a1SChristian König 		case 0x02000001: /* destroy */
894e5223214SChristian König 			destroyed |= 1 << session_idx;
895d38ceaf9SAlex Deucher 			break;
896d38ceaf9SAlex Deucher 
897182830a1SChristian König 		case 0x05000001: /* context buffer */
898cdc7893fSChristian König 			r = amdgpu_vce_cs_reloc(p, ib, idx + 3, idx + 2,
899dc78330aSChristian König 						*size * 2, 0);
900f1689ec1SChristian König 			if (r)
9012f4b9368SChristian König 				goto out;
902f1689ec1SChristian König 			break;
903f1689ec1SChristian König 
904182830a1SChristian König 		case 0x05000004: /* video bitstream buffer */
905cdc7893fSChristian König 			tmp = amdgpu_ib_get_value(ib, idx + 4);
906cdc7893fSChristian König 			r = amdgpu_vce_cs_reloc(p, ib, idx + 3, idx + 2,
907dc78330aSChristian König 						tmp, bs_idx);
908f1689ec1SChristian König 			if (r)
9092f4b9368SChristian König 				goto out;
910f1689ec1SChristian König 			break;
911f1689ec1SChristian König 
912182830a1SChristian König 		case 0x05000005: /* feedback buffer */
913cdc7893fSChristian König 			r = amdgpu_vce_cs_reloc(p, ib, idx + 3, idx + 2,
914dc78330aSChristian König 						4096, fb_idx);
915d38ceaf9SAlex Deucher 			if (r)
9162f4b9368SChristian König 				goto out;
917d38ceaf9SAlex Deucher 			break;
918d38ceaf9SAlex Deucher 
9191eb1547fSJames Zhu 		case 0x0500000d: /* MV buffer */
920cdc7893fSChristian König 			r = amdgpu_vce_cs_reloc(p, ib, idx + 3,
9211eb1547fSJames Zhu 						idx + 2, *size, 0);
9221eb1547fSJames Zhu 			if (r)
9231eb1547fSJames Zhu 				goto out;
9241eb1547fSJames Zhu 
925cdc7893fSChristian König 			r = amdgpu_vce_cs_reloc(p, ib, idx + 8,
9261eb1547fSJames Zhu 						idx + 7, *size / 12, 0);
9271eb1547fSJames Zhu 			if (r)
9281eb1547fSJames Zhu 				goto out;
9291eb1547fSJames Zhu 			break;
9301eb1547fSJames Zhu 
931d38ceaf9SAlex Deucher 		default:
932d38ceaf9SAlex Deucher 			DRM_ERROR("invalid VCE command (0x%x)!\n", cmd);
9332f4b9368SChristian König 			r = -EINVAL;
9342f4b9368SChristian König 			goto out;
935d38ceaf9SAlex Deucher 		}
936d38ceaf9SAlex Deucher 
937f1689ec1SChristian König 		if (session_idx == -1) {
938f1689ec1SChristian König 			DRM_ERROR("no session command at start of IB\n");
9392f4b9368SChristian König 			r = -EINVAL;
9402f4b9368SChristian König 			goto out;
941f1689ec1SChristian König 		}
942f1689ec1SChristian König 
943d38ceaf9SAlex Deucher 		idx += len / 4;
944d38ceaf9SAlex Deucher 	}
945d38ceaf9SAlex Deucher 
946e5223214SChristian König 	if (allocated & ~created) {
9472f4b9368SChristian König 		DRM_ERROR("New session without create command!\n");
9482f4b9368SChristian König 		r = -ENOENT;
9492f4b9368SChristian König 	}
9502f4b9368SChristian König 
9512f4b9368SChristian König out:
952e5223214SChristian König 	if (!r) {
953e5223214SChristian König 		/* No error, free all destroyed handle slots */
954e5223214SChristian König 		tmp = destroyed;
955e5223214SChristian König 	} else {
956e5223214SChristian König 		/* Error during parsing, free all allocated handle slots */
957e5223214SChristian König 		tmp = allocated;
958f1689ec1SChristian König 	}
959d38ceaf9SAlex Deucher 
960e5223214SChristian König 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
961e5223214SChristian König 		if (tmp & (1 << i))
962e5223214SChristian König 			atomic_set(&p->adev->vce.handles[i], 0);
963e5223214SChristian König 
9642f4b9368SChristian König 	return r;
965d38ceaf9SAlex Deucher }
966d38ceaf9SAlex Deucher 
967d38ceaf9SAlex Deucher /**
9681c7f15c7SLee Jones  * amdgpu_vce_ring_parse_cs_vm - parse the command stream in VM mode
96998614701SChristian König  *
97098614701SChristian König  * @p: parser context
971cdc7893fSChristian König  * @job: the job to parse
972cdc7893fSChristian König  * @ib: the IB to patch
97398614701SChristian König  */
amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser * p,struct amdgpu_job * job,struct amdgpu_ib * ib)974cdc7893fSChristian König int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p,
975cdc7893fSChristian König 				struct amdgpu_job *job,
976cdc7893fSChristian König 				struct amdgpu_ib *ib)
97798614701SChristian König {
97898614701SChristian König 	int session_idx = -1;
97998614701SChristian König 	uint32_t destroyed = 0;
98098614701SChristian König 	uint32_t created = 0;
98198614701SChristian König 	uint32_t allocated = 0;
98298614701SChristian König 	uint32_t tmp, handle = 0;
98398614701SChristian König 	int i, r = 0, idx = 0;
98498614701SChristian König 
98598614701SChristian König 	while (idx < ib->length_dw) {
986cdc7893fSChristian König 		uint32_t len = amdgpu_ib_get_value(ib, idx);
987cdc7893fSChristian König 		uint32_t cmd = amdgpu_ib_get_value(ib, idx + 1);
98898614701SChristian König 
98998614701SChristian König 		if ((len < 8) || (len & 3)) {
99098614701SChristian König 			DRM_ERROR("invalid VCE command length (%d)!\n", len);
99198614701SChristian König 			r = -EINVAL;
99298614701SChristian König 			goto out;
99398614701SChristian König 		}
99498614701SChristian König 
99598614701SChristian König 		switch (cmd) {
99698614701SChristian König 		case 0x00000001: /* session */
997cdc7893fSChristian König 			handle = amdgpu_ib_get_value(ib, idx + 2);
99898614701SChristian König 			session_idx = amdgpu_vce_validate_handle(p, handle,
99998614701SChristian König 								 &allocated);
100098614701SChristian König 			if (session_idx < 0) {
100198614701SChristian König 				r = session_idx;
100298614701SChristian König 				goto out;
100398614701SChristian König 			}
100498614701SChristian König 			break;
100598614701SChristian König 
100698614701SChristian König 		case 0x01000001: /* create */
100798614701SChristian König 			created |= 1 << session_idx;
100898614701SChristian König 			if (destroyed & (1 << session_idx)) {
100998614701SChristian König 				destroyed &= ~(1 << session_idx);
101098614701SChristian König 				allocated |= 1 << session_idx;
101198614701SChristian König 
101298614701SChristian König 			} else if (!(allocated & (1 << session_idx))) {
101398614701SChristian König 				DRM_ERROR("Handle already in use!\n");
101498614701SChristian König 				r = -EINVAL;
101598614701SChristian König 				goto out;
101698614701SChristian König 			}
101798614701SChristian König 
101898614701SChristian König 			break;
101998614701SChristian König 
102098614701SChristian König 		case 0x02000001: /* destroy */
102198614701SChristian König 			destroyed |= 1 << session_idx;
102298614701SChristian König 			break;
102398614701SChristian König 
102498614701SChristian König 		default:
102598614701SChristian König 			break;
102698614701SChristian König 		}
102798614701SChristian König 
102898614701SChristian König 		if (session_idx == -1) {
102998614701SChristian König 			DRM_ERROR("no session command at start of IB\n");
103098614701SChristian König 			r = -EINVAL;
103198614701SChristian König 			goto out;
103298614701SChristian König 		}
103398614701SChristian König 
103498614701SChristian König 		idx += len / 4;
103598614701SChristian König 	}
103698614701SChristian König 
103798614701SChristian König 	if (allocated & ~created) {
103898614701SChristian König 		DRM_ERROR("New session without create command!\n");
103998614701SChristian König 		r = -ENOENT;
104098614701SChristian König 	}
104198614701SChristian König 
104298614701SChristian König out:
104398614701SChristian König 	if (!r) {
104498614701SChristian König 		/* No error, free all destroyed handle slots */
104598614701SChristian König 		tmp = destroyed;
104698614701SChristian König 	} else {
104798614701SChristian König 		/* Error during parsing, free all allocated handle slots */
104898614701SChristian König 		tmp = allocated;
104998614701SChristian König 	}
105098614701SChristian König 
105198614701SChristian König 	for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
105298614701SChristian König 		if (tmp & (1 << i))
105398614701SChristian König 			atomic_set(&p->adev->vce.handles[i], 0);
105498614701SChristian König 
105598614701SChristian König 	return r;
105698614701SChristian König }
105798614701SChristian König 
105898614701SChristian König /**
1059d38ceaf9SAlex Deucher  * amdgpu_vce_ring_emit_ib - execute indirect buffer
1060d38ceaf9SAlex Deucher  *
1061d38ceaf9SAlex Deucher  * @ring: engine to use
1062184b762dSLee Jones  * @job: job to retrieve vmid from
1063d38ceaf9SAlex Deucher  * @ib: the IB to execute
1064184b762dSLee Jones  * @flags: unused
1065d38ceaf9SAlex Deucher  *
1066d38ceaf9SAlex Deucher  */
amdgpu_vce_ring_emit_ib(struct amdgpu_ring * ring,struct amdgpu_job * job,struct amdgpu_ib * ib,uint32_t flags)106734955e03SRex Zhu void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring,
106834955e03SRex Zhu 				struct amdgpu_job *job,
106934955e03SRex Zhu 				struct amdgpu_ib *ib,
1070c4c905ecSJack Xiao 				uint32_t flags)
1071d38ceaf9SAlex Deucher {
1072d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, VCE_CMD_IB);
1073d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
1074d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
1075d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, ib->length_dw);
1076d38ceaf9SAlex Deucher }
1077d38ceaf9SAlex Deucher 
1078d38ceaf9SAlex Deucher /**
1079d38ceaf9SAlex Deucher  * amdgpu_vce_ring_emit_fence - add a fence command to the ring
1080d38ceaf9SAlex Deucher  *
1081d38ceaf9SAlex Deucher  * @ring: engine to use
1082184b762dSLee Jones  * @addr: address
1083184b762dSLee Jones  * @seq: sequence number
1084184b762dSLee Jones  * @flags: fence related flags
1085d38ceaf9SAlex Deucher  *
1086d38ceaf9SAlex Deucher  */
amdgpu_vce_ring_emit_fence(struct amdgpu_ring * ring,u64 addr,u64 seq,unsigned int flags)1087d38ceaf9SAlex Deucher void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
1088f10984a3SSrinivasan Shanmugam 				unsigned int flags)
1089d38ceaf9SAlex Deucher {
1090890ee23fSChunming Zhou 	WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
1091d38ceaf9SAlex Deucher 
1092d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, VCE_CMD_FENCE);
1093d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, addr);
1094d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, upper_32_bits(addr));
1095d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, seq);
1096d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, VCE_CMD_TRAP);
1097d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, VCE_CMD_END);
1098d38ceaf9SAlex Deucher }
1099d38ceaf9SAlex Deucher 
1100d38ceaf9SAlex Deucher /**
1101d38ceaf9SAlex Deucher  * amdgpu_vce_ring_test_ring - test if VCE ring is working
1102d38ceaf9SAlex Deucher  *
1103d38ceaf9SAlex Deucher  * @ring: the engine to test on
1104d38ceaf9SAlex Deucher  *
1105d38ceaf9SAlex Deucher  */
amdgpu_vce_ring_test_ring(struct amdgpu_ring * ring)1106d38ceaf9SAlex Deucher int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
1107d38ceaf9SAlex Deucher {
1108d38ceaf9SAlex Deucher 	struct amdgpu_device *adev = ring->adev;
1109ce0e22f5SLouis Li 	uint32_t rptr;
1110f10984a3SSrinivasan Shanmugam 	unsigned int i;
1111a2f537e0SXiangliang Yu 	int r, timeout = adev->usec_timeout;
1112a2f537e0SXiangliang Yu 
1113a1b9022aSFrank Min 	/* skip ring test for sriov*/
1114a2f537e0SXiangliang Yu 	if (amdgpu_sriov_vf(adev))
1115a1b9022aSFrank Min 		return 0;
1116d38ceaf9SAlex Deucher 
1117a27de35cSChristian König 	r = amdgpu_ring_alloc(ring, 16);
1118dc9eeff8SChristian König 	if (r)
1119d38ceaf9SAlex Deucher 		return r;
1120dc9eeff8SChristian König 
1121ce0e22f5SLouis Li 	rptr = amdgpu_ring_get_rptr(ring);
1122ce0e22f5SLouis Li 
1123d38ceaf9SAlex Deucher 	amdgpu_ring_write(ring, VCE_CMD_END);
1124a27de35cSChristian König 	amdgpu_ring_commit(ring);
1125d38ceaf9SAlex Deucher 
1126a2f537e0SXiangliang Yu 	for (i = 0; i < timeout; i++) {
1127d38ceaf9SAlex Deucher 		if (amdgpu_ring_get_rptr(ring) != rptr)
1128d38ceaf9SAlex Deucher 			break;
1129c366be54SSam Ravnborg 		udelay(1);
1130d38ceaf9SAlex Deucher 	}
1131d38ceaf9SAlex Deucher 
1132dc9eeff8SChristian König 	if (i >= timeout)
1133d38ceaf9SAlex Deucher 		r = -ETIMEDOUT;
1134d38ceaf9SAlex Deucher 
1135d38ceaf9SAlex Deucher 	return r;
1136d38ceaf9SAlex Deucher }
1137d38ceaf9SAlex Deucher 
1138d38ceaf9SAlex Deucher /**
1139d38ceaf9SAlex Deucher  * amdgpu_vce_ring_test_ib - test if VCE IBs are working
1140d38ceaf9SAlex Deucher  *
1141d38ceaf9SAlex Deucher  * @ring: the engine to test on
1142184b762dSLee Jones  * @timeout: timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT
1143d38ceaf9SAlex Deucher  *
1144d38ceaf9SAlex Deucher  */
amdgpu_vce_ring_test_ib(struct amdgpu_ring * ring,long timeout)1145bbec97aaSChristian König int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout)
1146d38ceaf9SAlex Deucher {
1147f54d1867SChris Wilson 	struct dma_fence *fence = NULL;
1148bbec97aaSChristian König 	long r;
1149d38ceaf9SAlex Deucher 
11506f0359ffSAlex Deucher 	/* skip vce ring1/2 ib test for now, since it's not reliable */
11516f0359ffSAlex Deucher 	if (ring != &ring->adev->vce.ring[0])
1152898e50d4SLeo Liu 		return 0;
1153898e50d4SLeo Liu 
1154cb9038aaSxinhui pan 	r = amdgpu_vce_get_create_msg(ring, 1, NULL);
115598079389SChristian König 	if (r)
1156d38ceaf9SAlex Deucher 		goto error;
1157d38ceaf9SAlex Deucher 
11589f2ade33SChristian König 	r = amdgpu_vce_get_destroy_msg(ring, 1, true, &fence);
115998079389SChristian König 	if (r)
1160d38ceaf9SAlex Deucher 		goto error;
1161d38ceaf9SAlex Deucher 
1162f54d1867SChris Wilson 	r = dma_fence_wait_timeout(fence, false, timeout);
116398079389SChristian König 	if (r == 0)
1164bbec97aaSChristian König 		r = -ETIMEDOUT;
116598079389SChristian König 	else if (r > 0)
1166bbec97aaSChristian König 		r = 0;
116798079389SChristian König 
1168d38ceaf9SAlex Deucher error:
1169f54d1867SChris Wilson 	dma_fence_put(fence);
1170d38ceaf9SAlex Deucher 	return r;
1171d38ceaf9SAlex Deucher }
1172080e613cSSatyajit Sahu 
amdgpu_vce_get_ring_prio(int ring)1173080e613cSSatyajit Sahu enum amdgpu_ring_priority_level amdgpu_vce_get_ring_prio(int ring)
1174080e613cSSatyajit Sahu {
1175080e613cSSatyajit Sahu 	switch (ring) {
1176080e613cSSatyajit Sahu 	case 0:
1177080e613cSSatyajit Sahu 		return AMDGPU_RING_PRIO_0;
1178080e613cSSatyajit Sahu 	case 1:
1179080e613cSSatyajit Sahu 		return AMDGPU_RING_PRIO_1;
1180080e613cSSatyajit Sahu 	case 2:
1181080e613cSSatyajit Sahu 		return AMDGPU_RING_PRIO_2;
1182080e613cSSatyajit Sahu 	default:
1183080e613cSSatyajit Sahu 		return AMDGPU_RING_PRIO_0;
1184080e613cSSatyajit Sahu 	}
1185080e613cSSatyajit Sahu }
1186