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 <christian.koenig@amd.com>
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
16152215e2aSMario Limonciello r = amdgpu_ucode_request(adev, &adev->vce.fw, 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
223*3990ef74SVitaly Prosyak amdgpu_bo_free_kernel(&adev->vce.vcpu_bo, &adev->vce.gpu_addr,
224*3990ef74SVitaly Prosyak (void **)&adev->vce.cpu_addr);
225*3990ef74SVitaly 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
23320acbed4SEmily Deng *
23420acbed4SEmily Deng */
amdgpu_vce_entity_init(struct amdgpu_device * adev)23520acbed4SEmily Deng int amdgpu_vce_entity_init(struct amdgpu_device *adev)
23620acbed4SEmily Deng {
23720acbed4SEmily Deng struct amdgpu_ring *ring;
238b3ac1766SNirmoy Das struct drm_gpu_scheduler *sched;
23920acbed4SEmily Deng int r;
24020acbed4SEmily Deng
24120acbed4SEmily Deng ring = &adev->vce.ring[0];
242b3ac1766SNirmoy Das sched = &ring->sched;
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 }
24920acbed4SEmily Deng
25020acbed4SEmily Deng return 0;
25120acbed4SEmily Deng }
25220acbed4SEmily Deng
25320acbed4SEmily Deng /**
254d38ceaf9SAlex Deucher * amdgpu_vce_suspend - unpin VCE fw memory
255d38ceaf9SAlex Deucher *
256d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
257d38ceaf9SAlex Deucher *
258d38ceaf9SAlex Deucher */
amdgpu_vce_suspend(struct amdgpu_device * adev)259d38ceaf9SAlex Deucher int amdgpu_vce_suspend(struct amdgpu_device *adev)
260d38ceaf9SAlex Deucher {
261d38ceaf9SAlex Deucher int i;
262d38ceaf9SAlex Deucher
26361ea6f58SRex Zhu cancel_delayed_work_sync(&adev->vce.idle_work);
26461ea6f58SRex Zhu
265d38ceaf9SAlex Deucher if (adev->vce.vcpu_bo == NULL)
266d38ceaf9SAlex Deucher return 0;
267d38ceaf9SAlex Deucher
268d38ceaf9SAlex Deucher for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
269d38ceaf9SAlex Deucher if (atomic_read(&adev->vce.handles[i]))
270d38ceaf9SAlex Deucher break;
271d38ceaf9SAlex Deucher
272d38ceaf9SAlex Deucher if (i == AMDGPU_MAX_VCE_HANDLES)
273d38ceaf9SAlex Deucher return 0;
274d38ceaf9SAlex Deucher
275d38ceaf9SAlex Deucher /* TODO: suspending running encoding sessions isn't supported */
276d38ceaf9SAlex Deucher return -EINVAL;
277d38ceaf9SAlex Deucher }
278d38ceaf9SAlex Deucher
279d38ceaf9SAlex Deucher /**
280d38ceaf9SAlex Deucher * amdgpu_vce_resume - pin VCE fw memory
281d38ceaf9SAlex Deucher *
282d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
283d38ceaf9SAlex Deucher *
284d38ceaf9SAlex Deucher */
amdgpu_vce_resume(struct amdgpu_device * adev)285d38ceaf9SAlex Deucher int amdgpu_vce_resume(struct amdgpu_device *adev)
286d38ceaf9SAlex Deucher {
287d38ceaf9SAlex Deucher void *cpu_addr;
288d38ceaf9SAlex Deucher const struct common_firmware_header *hdr;
289f10984a3SSrinivasan Shanmugam unsigned int offset;
290f89f8c6bSAndrey Grodzovsky int r, idx;
291d38ceaf9SAlex Deucher
292d38ceaf9SAlex Deucher if (adev->vce.vcpu_bo == NULL)
293d38ceaf9SAlex Deucher return -EINVAL;
294d38ceaf9SAlex Deucher
295d38ceaf9SAlex Deucher r = amdgpu_bo_reserve(adev->vce.vcpu_bo, false);
296d38ceaf9SAlex Deucher if (r) {
297d38ceaf9SAlex Deucher dev_err(adev->dev, "(%d) failed to reserve VCE bo\n", r);
298d38ceaf9SAlex Deucher return r;
299d38ceaf9SAlex Deucher }
300d38ceaf9SAlex Deucher
301d38ceaf9SAlex Deucher r = amdgpu_bo_kmap(adev->vce.vcpu_bo, &cpu_addr);
302d38ceaf9SAlex Deucher if (r) {
303d38ceaf9SAlex Deucher amdgpu_bo_unreserve(adev->vce.vcpu_bo);
304d38ceaf9SAlex Deucher dev_err(adev->dev, "(%d) VCE map failed\n", r);
305d38ceaf9SAlex Deucher return r;
306d38ceaf9SAlex Deucher }
307d38ceaf9SAlex Deucher
308d38ceaf9SAlex Deucher hdr = (const struct common_firmware_header *)adev->vce.fw->data;
309d38ceaf9SAlex Deucher offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
310f89f8c6bSAndrey Grodzovsky
311c58a863bSGuchun Chen if (drm_dev_enter(adev_to_drm(adev), &idx)) {
3127b4d3e29SChristian König memcpy_toio(cpu_addr, adev->vce.fw->data + offset,
3137b4d3e29SChristian König adev->vce.fw->size - offset);
314f89f8c6bSAndrey Grodzovsky drm_dev_exit(idx);
315f89f8c6bSAndrey Grodzovsky }
316d38ceaf9SAlex Deucher
317d38ceaf9SAlex Deucher amdgpu_bo_kunmap(adev->vce.vcpu_bo);
318d38ceaf9SAlex Deucher
319d38ceaf9SAlex Deucher amdgpu_bo_unreserve(adev->vce.vcpu_bo);
320d38ceaf9SAlex Deucher
321d38ceaf9SAlex Deucher return 0;
322d38ceaf9SAlex Deucher }
323d38ceaf9SAlex Deucher
324d38ceaf9SAlex Deucher /**
325d38ceaf9SAlex Deucher * amdgpu_vce_idle_work_handler - power off VCE
326d38ceaf9SAlex Deucher *
327d38ceaf9SAlex Deucher * @work: pointer to work structure
328d38ceaf9SAlex Deucher *
329d38ceaf9SAlex Deucher * power of VCE when it's not used any more
330d38ceaf9SAlex Deucher */
amdgpu_vce_idle_work_handler(struct work_struct * work)331d38ceaf9SAlex Deucher static void amdgpu_vce_idle_work_handler(struct work_struct *work)
332d38ceaf9SAlex Deucher {
333d38ceaf9SAlex Deucher struct amdgpu_device *adev =
334d38ceaf9SAlex Deucher container_of(work, struct amdgpu_device, vce.idle_work.work);
335f10984a3SSrinivasan Shanmugam unsigned int i, count = 0;
336d38ceaf9SAlex Deucher
33724c5fe56SAlex Deucher for (i = 0; i < adev->vce.num_rings; i++)
33824c5fe56SAlex Deucher count += amdgpu_fence_count_emitted(&adev->vce.ring[i]);
33924c5fe56SAlex Deucher
34024c5fe56SAlex Deucher if (count == 0) {
341d38ceaf9SAlex Deucher if (adev->pm.dpm_enabled) {
342d38ceaf9SAlex Deucher amdgpu_dpm_enable_vce(adev, false);
343d38ceaf9SAlex Deucher } else {
344d38ceaf9SAlex Deucher amdgpu_asic_set_vce_clocks(adev, 0, 0);
3452990a1fcSAlex Deucher amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
34628ed5504SRex Zhu AMD_PG_STATE_GATE);
3472990a1fcSAlex Deucher amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
34828ed5504SRex Zhu AMD_CG_STATE_GATE);
349d38ceaf9SAlex Deucher }
350d38ceaf9SAlex Deucher } else {
351182830a1SChristian König schedule_delayed_work(&adev->vce.idle_work, VCE_IDLE_TIMEOUT);
352d38ceaf9SAlex Deucher }
353d38ceaf9SAlex Deucher }
354d38ceaf9SAlex Deucher
355d38ceaf9SAlex Deucher /**
356ebff485eSChristian König * amdgpu_vce_ring_begin_use - power up VCE
357d38ceaf9SAlex Deucher *
358ebff485eSChristian König * @ring: amdgpu ring
359d38ceaf9SAlex Deucher *
360d38ceaf9SAlex Deucher * Make sure VCE is powerd up when we want to use it
361d38ceaf9SAlex Deucher */
amdgpu_vce_ring_begin_use(struct amdgpu_ring * ring)362ebff485eSChristian König void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring)
363d38ceaf9SAlex Deucher {
364ebff485eSChristian König struct amdgpu_device *adev = ring->adev;
365ebff485eSChristian König bool set_clocks;
366182830a1SChristian König
367d9af2259SXiangliang Yu if (amdgpu_sriov_vf(adev))
368d9af2259SXiangliang Yu return;
369d9af2259SXiangliang Yu
370ebff485eSChristian König mutex_lock(&adev->vce.idle_mutex);
371ebff485eSChristian König set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work);
372182830a1SChristian König if (set_clocks) {
373d38ceaf9SAlex Deucher if (adev->pm.dpm_enabled) {
374d38ceaf9SAlex Deucher amdgpu_dpm_enable_vce(adev, true);
375d38ceaf9SAlex Deucher } else {
376d38ceaf9SAlex Deucher amdgpu_asic_set_vce_clocks(adev, 53300, 40000);
3772990a1fcSAlex Deucher amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
37828ed5504SRex Zhu AMD_CG_STATE_UNGATE);
3792990a1fcSAlex Deucher amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE,
38028ed5504SRex Zhu AMD_PG_STATE_UNGATE);
38128ed5504SRex Zhu
382d38ceaf9SAlex Deucher }
383d38ceaf9SAlex Deucher }
384ebff485eSChristian König mutex_unlock(&adev->vce.idle_mutex);
385ebff485eSChristian König }
386ebff485eSChristian König
387ebff485eSChristian König /**
388ebff485eSChristian König * amdgpu_vce_ring_end_use - power VCE down
389ebff485eSChristian König *
390ebff485eSChristian König * @ring: amdgpu ring
391ebff485eSChristian König *
392ebff485eSChristian König * Schedule work to power VCE down again
393ebff485eSChristian König */
amdgpu_vce_ring_end_use(struct amdgpu_ring * ring)394ebff485eSChristian König void amdgpu_vce_ring_end_use(struct amdgpu_ring *ring)
395ebff485eSChristian König {
39614a8032aSMonk Liu if (!amdgpu_sriov_vf(ring->adev))
397ebff485eSChristian König schedule_delayed_work(&ring->adev->vce.idle_work, VCE_IDLE_TIMEOUT);
398d38ceaf9SAlex Deucher }
399d38ceaf9SAlex Deucher
400d38ceaf9SAlex Deucher /**
401d38ceaf9SAlex Deucher * amdgpu_vce_free_handles - free still open VCE handles
402d38ceaf9SAlex Deucher *
403d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
404d38ceaf9SAlex Deucher * @filp: drm file pointer
405d38ceaf9SAlex Deucher *
406d38ceaf9SAlex Deucher * Close all VCE handles still open by this file pointer
407d38ceaf9SAlex Deucher */
amdgpu_vce_free_handles(struct amdgpu_device * adev,struct drm_file * filp)408d38ceaf9SAlex Deucher void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
409d38ceaf9SAlex Deucher {
410d38ceaf9SAlex Deucher struct amdgpu_ring *ring = &adev->vce.ring[0];
411d38ceaf9SAlex Deucher int i, r;
412f10984a3SSrinivasan Shanmugam
413d38ceaf9SAlex Deucher for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
414d38ceaf9SAlex Deucher uint32_t handle = atomic_read(&adev->vce.handles[i]);
415182830a1SChristian König
416d38ceaf9SAlex Deucher if (!handle || adev->vce.filp[i] != filp)
417d38ceaf9SAlex Deucher continue;
418d38ceaf9SAlex Deucher
4199f2ade33SChristian König r = amdgpu_vce_get_destroy_msg(ring, handle, false, NULL);
420d38ceaf9SAlex Deucher if (r)
421d38ceaf9SAlex Deucher DRM_ERROR("Error destroying VCE handle (%d)!\n", r);
422d38ceaf9SAlex Deucher
423d38ceaf9SAlex Deucher adev->vce.filp[i] = NULL;
424d38ceaf9SAlex Deucher atomic_set(&adev->vce.handles[i], 0);
425d38ceaf9SAlex Deucher }
426d38ceaf9SAlex Deucher }
427d38ceaf9SAlex Deucher
428d38ceaf9SAlex Deucher /**
429d38ceaf9SAlex Deucher * amdgpu_vce_get_create_msg - generate a VCE create msg
430d38ceaf9SAlex Deucher *
431d38ceaf9SAlex Deucher * @ring: ring we should submit the msg to
432d38ceaf9SAlex Deucher * @handle: VCE session handle to use
433d38ceaf9SAlex Deucher * @fence: optional fence to return
434d38ceaf9SAlex Deucher *
435d38ceaf9SAlex Deucher * Open up a stream for HW test
436d38ceaf9SAlex Deucher */
amdgpu_vce_get_create_msg(struct amdgpu_ring * ring,uint32_t handle,struct dma_fence ** fence)43717523bd0SAlex Deucher static int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
438f54d1867SChris Wilson struct dma_fence **fence)
439d38ceaf9SAlex Deucher {
440f10984a3SSrinivasan Shanmugam const unsigned int ib_size_dw = 1024;
441d71518b5SChristian König struct amdgpu_job *job;
442d71518b5SChristian König struct amdgpu_ib *ib;
443cb9038aaSxinhui pan struct amdgpu_ib ib_msg;
444f54d1867SChris Wilson struct dma_fence *f = NULL;
445569557e5SAlex Deucher uint64_t addr;
446d38ceaf9SAlex Deucher int i, r;
447d38ceaf9SAlex Deucher
448f7d66fb2SChristian König r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity,
449f7d66fb2SChristian König AMDGPU_FENCE_OWNER_UNDEFINED,
450f7d66fb2SChristian König ib_size_dw * 4, AMDGPU_IB_POOL_DIRECT,
451f7d66fb2SChristian König &job);
452d71518b5SChristian König if (r)
453d38ceaf9SAlex Deucher return r;
454d71518b5SChristian König
455cb9038aaSxinhui pan memset(&ib_msg, 0, sizeof(ib_msg));
456cb9038aaSxinhui pan /* only one gpu page is needed, alloc +1 page to make addr aligned. */
457cb9038aaSxinhui pan r = amdgpu_ib_get(ring->adev, NULL, AMDGPU_GPU_PAGE_SIZE * 2,
458cb9038aaSxinhui pan AMDGPU_IB_POOL_DIRECT,
459cb9038aaSxinhui pan &ib_msg);
460cb9038aaSxinhui pan if (r)
461cb9038aaSxinhui pan goto err;
462d38ceaf9SAlex Deucher
463cb9038aaSxinhui pan ib = &job->ibs[0];
464cb9038aaSxinhui pan /* let addr point to page boundary */
465cb9038aaSxinhui pan addr = AMDGPU_GPU_PAGE_ALIGN(ib_msg.gpu_addr);
466d38ceaf9SAlex Deucher
467d38ceaf9SAlex Deucher /* stitch together an VCE create msg */
4688128765cSChunming Zhou ib->length_dw = 0;
4698128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x0000000c; /* len */
4708128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
4718128765cSChunming Zhou ib->ptr[ib->length_dw++] = handle;
472d38ceaf9SAlex Deucher
473d66f8e48SLeo Liu if ((ring->adev->vce.fw_version >> 24) >= 52)
474d66f8e48SLeo Liu ib->ptr[ib->length_dw++] = 0x00000040; /* len */
475d66f8e48SLeo Liu else
4768128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000030; /* len */
4778128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x01000001; /* create cmd */
4788128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000000;
4798128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000042;
4808128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x0000000a;
4818128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000001;
4828128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000080;
4838128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000060;
4848128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000100;
4858128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000100;
4868128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x0000000c;
4878128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000000;
488d66f8e48SLeo Liu if ((ring->adev->vce.fw_version >> 24) >= 52) {
489d66f8e48SLeo Liu ib->ptr[ib->length_dw++] = 0x00000000;
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 }
494d38ceaf9SAlex Deucher
4958128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000014; /* len */
4968128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */
497569557e5SAlex Deucher ib->ptr[ib->length_dw++] = upper_32_bits(addr);
498569557e5SAlex Deucher ib->ptr[ib->length_dw++] = addr;
4998128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000001;
500d38ceaf9SAlex Deucher
5018128765cSChunming Zhou for (i = ib->length_dw; i < ib_size_dw; ++i)
5028128765cSChunming Zhou ib->ptr[i] = 0x0;
503d38ceaf9SAlex Deucher
504ee913fd9SChristian König r = amdgpu_job_submit_direct(job, ring, &f);
505cb9038aaSxinhui pan amdgpu_ib_free(ring->adev, &ib_msg, f);
5068128765cSChunming Zhou if (r)
5078128765cSChunming Zhou goto err;
5089f2ade33SChristian König
509d38ceaf9SAlex Deucher if (fence)
510f54d1867SChris Wilson *fence = dma_fence_get(f);
511f54d1867SChris Wilson dma_fence_put(f);
5128128765cSChunming Zhou return 0;
513d71518b5SChristian König
5148128765cSChunming Zhou err:
515d71518b5SChristian König amdgpu_job_free(job);
516d38ceaf9SAlex Deucher return r;
517d38ceaf9SAlex Deucher }
518d38ceaf9SAlex Deucher
519d38ceaf9SAlex Deucher /**
520d38ceaf9SAlex Deucher * amdgpu_vce_get_destroy_msg - generate a VCE destroy msg
521d38ceaf9SAlex Deucher *
522d38ceaf9SAlex Deucher * @ring: ring we should submit the msg to
523d38ceaf9SAlex Deucher * @handle: VCE session handle to use
524184b762dSLee Jones * @direct: direct or delayed pool
525d38ceaf9SAlex Deucher * @fence: optional fence to return
526d38ceaf9SAlex Deucher *
527d38ceaf9SAlex Deucher * Close up a stream for HW test or if userspace failed to do so
528d38ceaf9SAlex Deucher */
amdgpu_vce_get_destroy_msg(struct amdgpu_ring * ring,uint32_t handle,bool direct,struct dma_fence ** fence)52917523bd0SAlex Deucher static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
530f54d1867SChris Wilson bool direct, struct dma_fence **fence)
531d38ceaf9SAlex Deucher {
532f10984a3SSrinivasan Shanmugam const unsigned int ib_size_dw = 1024;
533d71518b5SChristian König struct amdgpu_job *job;
534d71518b5SChristian König struct amdgpu_ib *ib;
535f54d1867SChris Wilson struct dma_fence *f = NULL;
536d38ceaf9SAlex Deucher int i, r;
537d38ceaf9SAlex Deucher
538f7d66fb2SChristian König r = amdgpu_job_alloc_with_ib(ring->adev, &ring->adev->vce.entity,
539f7d66fb2SChristian König AMDGPU_FENCE_OWNER_UNDEFINED,
540f7d66fb2SChristian König ib_size_dw * 4,
5419ecefb19SChristian König direct ? AMDGPU_IB_POOL_DIRECT :
5429ecefb19SChristian König AMDGPU_IB_POOL_DELAYED, &job);
543d71518b5SChristian König if (r)
544d38ceaf9SAlex Deucher return r;
545d38ceaf9SAlex Deucher
546d71518b5SChristian König ib = &job->ibs[0];
547d38ceaf9SAlex Deucher
548d38ceaf9SAlex Deucher /* stitch together an VCE destroy msg */
5498128765cSChunming Zhou ib->length_dw = 0;
5508128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x0000000c; /* len */
5518128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
5528128765cSChunming Zhou ib->ptr[ib->length_dw++] = handle;
553d38ceaf9SAlex Deucher
55499453a9eSRex Zhu ib->ptr[ib->length_dw++] = 0x00000020; /* len */
55599453a9eSRex Zhu ib->ptr[ib->length_dw++] = 0x00000002; /* task info */
55699453a9eSRex Zhu ib->ptr[ib->length_dw++] = 0xffffffff; /* next task info, set to 0xffffffff if no */
55799453a9eSRex Zhu ib->ptr[ib->length_dw++] = 0x00000001; /* destroy session */
55899453a9eSRex Zhu ib->ptr[ib->length_dw++] = 0x00000000;
55999453a9eSRex Zhu ib->ptr[ib->length_dw++] = 0x00000000;
56099453a9eSRex Zhu ib->ptr[ib->length_dw++] = 0xffffffff; /* feedback is not needed, set to 0xffffffff and firmware will not output feedback */
56199453a9eSRex Zhu ib->ptr[ib->length_dw++] = 0x00000000;
562d38ceaf9SAlex Deucher
5638128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x00000008; /* len */
5648128765cSChunming Zhou ib->ptr[ib->length_dw++] = 0x02000001; /* destroy cmd */
565d38ceaf9SAlex Deucher
5668128765cSChunming Zhou for (i = ib->length_dw; i < ib_size_dw; ++i)
5678128765cSChunming Zhou ib->ptr[i] = 0x0;
5689f2ade33SChristian König
569ee913fd9SChristian König if (direct)
570ee913fd9SChristian König r = amdgpu_job_submit_direct(job, ring, &f);
571ee913fd9SChristian König else
572f7d66fb2SChristian König f = amdgpu_job_submit(job);
5739f2ade33SChristian König if (r)
5749f2ade33SChristian König goto err;
5759f2ade33SChristian König
576d38ceaf9SAlex Deucher if (fence)
577f54d1867SChris Wilson *fence = dma_fence_get(f);
578f54d1867SChris Wilson dma_fence_put(f);
5798128765cSChunming Zhou return 0;
580d71518b5SChristian König
5818128765cSChunming Zhou err:
582d71518b5SChristian König amdgpu_job_free(job);
583d38ceaf9SAlex Deucher return r;
584d38ceaf9SAlex Deucher }
585d38ceaf9SAlex Deucher
586d38ceaf9SAlex Deucher /**
5871c7f15c7SLee Jones * amdgpu_vce_validate_bo - make sure not to cross 4GB boundary
58823594318SChristian König *
589a37558e6SLee Jones * @p: cs parser
590cdc7893fSChristian König * @ib: indirect buffer to use
59123594318SChristian König * @lo: address of lower dword
59223594318SChristian König * @hi: address of higher dword
59323594318SChristian König * @size: minimum size
59423594318SChristian König * @index: bs/fb index
59523594318SChristian König *
59623594318SChristian König * Make sure that no BO cross a 4GB boundary.
59723594318SChristian 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)598cdc7893fSChristian König static int amdgpu_vce_validate_bo(struct amdgpu_cs_parser *p,
599cdc7893fSChristian König struct amdgpu_ib *ib, int lo, int hi,
600f10984a3SSrinivasan Shanmugam unsigned int size, int32_t index)
60123594318SChristian König {
60223594318SChristian König int64_t offset = ((uint64_t)size) * ((int64_t)index);
60319be5570SChristian König struct ttm_operation_ctx ctx = { false, false };
60423594318SChristian König struct amdgpu_bo_va_mapping *mapping;
605f10984a3SSrinivasan Shanmugam unsigned int i, fpfn, lpfn;
60623594318SChristian König struct amdgpu_bo *bo;
60723594318SChristian König uint64_t addr;
60823594318SChristian König int r;
60923594318SChristian König
610cdc7893fSChristian König addr = ((uint64_t)amdgpu_ib_get_value(ib, lo)) |
611cdc7893fSChristian König ((uint64_t)amdgpu_ib_get_value(ib, hi)) << 32;
61223594318SChristian König if (index >= 0) {
61323594318SChristian König addr += offset;
61423594318SChristian König fpfn = PAGE_ALIGN(offset) >> PAGE_SHIFT;
61523594318SChristian König lpfn = 0x100000000ULL >> PAGE_SHIFT;
61623594318SChristian König } else {
61723594318SChristian König fpfn = 0;
61823594318SChristian König lpfn = (0x100000000ULL - PAGE_ALIGN(offset)) >> PAGE_SHIFT;
61923594318SChristian König }
62023594318SChristian König
62123594318SChristian König r = amdgpu_cs_find_mapping(p, addr, &bo, &mapping);
62223594318SChristian König if (r) {
623f10984a3SSrinivasan Shanmugam DRM_ERROR("Can't find BO for addr 0x%010llx %d %d %d %d\n",
62423594318SChristian König addr, lo, hi, size, index);
62523594318SChristian König return r;
62623594318SChristian König }
62723594318SChristian König
62823594318SChristian König for (i = 0; i < bo->placement.num_placement; ++i) {
62923594318SChristian König bo->placements[i].fpfn = max(bo->placements[i].fpfn, fpfn);
6304c63abb2SChristian König bo->placements[i].lpfn = bo->placements[i].lpfn ?
6314c63abb2SChristian König min(bo->placements[i].lpfn, lpfn) : lpfn;
63223594318SChristian König }
63319be5570SChristian König return ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
63423594318SChristian König }
63523594318SChristian König
63623594318SChristian König
63723594318SChristian König /**
638d38ceaf9SAlex Deucher * amdgpu_vce_cs_reloc - command submission relocation
639d38ceaf9SAlex Deucher *
640d38ceaf9SAlex Deucher * @p: parser context
641cdc7893fSChristian König * @ib: indirect buffer to use
642d38ceaf9SAlex Deucher * @lo: address of lower dword
643d38ceaf9SAlex Deucher * @hi: address of higher dword
644f1689ec1SChristian König * @size: minimum size
645184b762dSLee Jones * @index: bs/fb index
646d38ceaf9SAlex Deucher *
647d38ceaf9SAlex Deucher * Patch relocation inside command stream with real buffer address
648d38ceaf9SAlex Deucher */
amdgpu_vce_cs_reloc(struct amdgpu_cs_parser * p,struct amdgpu_ib * ib,int lo,int hi,unsigned int size,uint32_t index)649cdc7893fSChristian König static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib,
650f10984a3SSrinivasan Shanmugam int lo, int hi, unsigned int size, uint32_t index)
651d38ceaf9SAlex Deucher {
652d38ceaf9SAlex Deucher struct amdgpu_bo_va_mapping *mapping;
653d38ceaf9SAlex Deucher struct amdgpu_bo *bo;
654d38ceaf9SAlex Deucher uint64_t addr;
6559cca0b8eSChristian König int r;
656d38ceaf9SAlex Deucher
657dc78330aSChristian König if (index == 0xffffffff)
658dc78330aSChristian König index = 0;
659dc78330aSChristian König
660cdc7893fSChristian König addr = ((uint64_t)amdgpu_ib_get_value(ib, lo)) |
661cdc7893fSChristian König ((uint64_t)amdgpu_ib_get_value(ib, hi)) << 32;
662dc78330aSChristian König addr += ((uint64_t)size) * ((uint64_t)index);
663d38ceaf9SAlex Deucher
6649cca0b8eSChristian König r = amdgpu_cs_find_mapping(p, addr, &bo, &mapping);
6659cca0b8eSChristian König if (r) {
666f10984a3SSrinivasan Shanmugam DRM_ERROR("Can't find BO for addr 0x%010llx %d %d %d %d\n",
667dc78330aSChristian König addr, lo, hi, size, index);
6689cca0b8eSChristian König return r;
669d38ceaf9SAlex Deucher }
670d38ceaf9SAlex Deucher
671f1689ec1SChristian König if ((addr + (uint64_t)size) >
672a9f87f64SChristian König (mapping->last + 1) * AMDGPU_GPU_PAGE_SIZE) {
673f10984a3SSrinivasan Shanmugam DRM_ERROR("BO too small for addr 0x%010llx %d %d\n",
674f1689ec1SChristian König addr, lo, hi);
675f1689ec1SChristian König return -EINVAL;
676f1689ec1SChristian König }
677f1689ec1SChristian König
678a9f87f64SChristian König addr -= mapping->start * AMDGPU_GPU_PAGE_SIZE;
679d38ceaf9SAlex Deucher addr += amdgpu_bo_gpu_offset(bo);
680dc78330aSChristian König addr -= ((uint64_t)size) * ((uint64_t)index);
681d38ceaf9SAlex Deucher
682cdc7893fSChristian König amdgpu_ib_set_value(ib, lo, lower_32_bits(addr));
683cdc7893fSChristian König amdgpu_ib_set_value(ib, hi, upper_32_bits(addr));
684d38ceaf9SAlex Deucher
685d38ceaf9SAlex Deucher return 0;
686d38ceaf9SAlex Deucher }
687d38ceaf9SAlex Deucher
688d38ceaf9SAlex Deucher /**
689f1689ec1SChristian König * amdgpu_vce_validate_handle - validate stream handle
690f1689ec1SChristian König *
691f1689ec1SChristian König * @p: parser context
692f1689ec1SChristian König * @handle: handle to validate
6932f4b9368SChristian König * @allocated: allocated a new handle?
694f1689ec1SChristian König *
695f1689ec1SChristian König * Validates the handle and return the found session index or -EINVAL
696f10984a3SSrinivasan Shanmugam * we don't have another free session index.
697f1689ec1SChristian König */
amdgpu_vce_validate_handle(struct amdgpu_cs_parser * p,uint32_t handle,uint32_t * allocated)698f1689ec1SChristian König static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p,
699e5223214SChristian König uint32_t handle, uint32_t *allocated)
700f1689ec1SChristian König {
701f10984a3SSrinivasan Shanmugam unsigned int i;
702f1689ec1SChristian König
703f1689ec1SChristian König /* validate the handle */
704f1689ec1SChristian König for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
7052f4b9368SChristian König if (atomic_read(&p->adev->vce.handles[i]) == handle) {
7062f4b9368SChristian König if (p->adev->vce.filp[i] != p->filp) {
7072f4b9368SChristian König DRM_ERROR("VCE handle collision detected!\n");
7082f4b9368SChristian König return -EINVAL;
7092f4b9368SChristian König }
710f1689ec1SChristian König return i;
711f1689ec1SChristian König }
7122f4b9368SChristian König }
713f1689ec1SChristian König
714f1689ec1SChristian König /* handle not found try to alloc a new one */
715f1689ec1SChristian König for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
716f1689ec1SChristian König if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) {
717f1689ec1SChristian König p->adev->vce.filp[i] = p->filp;
718f1689ec1SChristian König p->adev->vce.img_size[i] = 0;
719e5223214SChristian König *allocated |= 1 << i;
720f1689ec1SChristian König return i;
721f1689ec1SChristian König }
722f1689ec1SChristian König }
723f1689ec1SChristian König
724f1689ec1SChristian König DRM_ERROR("No more free VCE handles!\n");
725f1689ec1SChristian König return -EINVAL;
726f1689ec1SChristian König }
727f1689ec1SChristian König
728f1689ec1SChristian König /**
7291c7f15c7SLee Jones * amdgpu_vce_ring_parse_cs - parse and validate the command stream
730d38ceaf9SAlex Deucher *
731d38ceaf9SAlex Deucher * @p: parser context
732cdc7893fSChristian König * @job: the job to parse
733cdc7893fSChristian König * @ib: the IB to patch
734d38ceaf9SAlex Deucher */
amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser * p,struct amdgpu_job * job,struct amdgpu_ib * ib)735cdc7893fSChristian König int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p,
736cdc7893fSChristian König struct amdgpu_job *job,
737cdc7893fSChristian König struct amdgpu_ib *ib)
738d38ceaf9SAlex Deucher {
739f10984a3SSrinivasan Shanmugam unsigned int fb_idx = 0, bs_idx = 0;
740f1689ec1SChristian König int session_idx = -1;
741e5223214SChristian König uint32_t destroyed = 0;
742e5223214SChristian König uint32_t created = 0;
743e5223214SChristian König uint32_t allocated = 0;
744f1689ec1SChristian König uint32_t tmp, handle = 0;
745855ae72cSJesse Zhang uint32_t dummy = 0xffffffff;
746855ae72cSJesse Zhang uint32_t *size = &dummy;
747f10984a3SSrinivasan Shanmugam unsigned int idx;
74823594318SChristian König int i, r = 0;
749c855e250SChristian König
750cdc7893fSChristian König job->vm = NULL;
75145088efcSChristian König ib->gpu_addr = amdgpu_sa_bo_gpu_addr(ib->sa_bo);
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 amdgpu_ib_free(p->adev, ib, NULL);
104798614701SChristian König } else {
104898614701SChristian König /* Error during parsing, free all allocated handle slots */
104998614701SChristian König tmp = allocated;
105098614701SChristian König }
105198614701SChristian König
105298614701SChristian König for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
105398614701SChristian König if (tmp & (1 << i))
105498614701SChristian König atomic_set(&p->adev->vce.handles[i], 0);
105598614701SChristian König
105698614701SChristian König return r;
105798614701SChristian König }
105898614701SChristian König
105998614701SChristian König /**
1060d38ceaf9SAlex Deucher * amdgpu_vce_ring_emit_ib - execute indirect buffer
1061d38ceaf9SAlex Deucher *
1062d38ceaf9SAlex Deucher * @ring: engine to use
1063184b762dSLee Jones * @job: job to retrieve vmid from
1064d38ceaf9SAlex Deucher * @ib: the IB to execute
1065184b762dSLee Jones * @flags: unused
1066d38ceaf9SAlex Deucher *
1067d38ceaf9SAlex Deucher */
amdgpu_vce_ring_emit_ib(struct amdgpu_ring * ring,struct amdgpu_job * job,struct amdgpu_ib * ib,uint32_t flags)106834955e03SRex Zhu void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring,
106934955e03SRex Zhu struct amdgpu_job *job,
107034955e03SRex Zhu struct amdgpu_ib *ib,
1071c4c905ecSJack Xiao uint32_t flags)
1072d38ceaf9SAlex Deucher {
1073d38ceaf9SAlex Deucher amdgpu_ring_write(ring, VCE_CMD_IB);
1074d38ceaf9SAlex Deucher amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
1075d38ceaf9SAlex Deucher amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
1076d38ceaf9SAlex Deucher amdgpu_ring_write(ring, ib->length_dw);
1077d38ceaf9SAlex Deucher }
1078d38ceaf9SAlex Deucher
1079d38ceaf9SAlex Deucher /**
1080d38ceaf9SAlex Deucher * amdgpu_vce_ring_emit_fence - add a fence command to the ring
1081d38ceaf9SAlex Deucher *
1082d38ceaf9SAlex Deucher * @ring: engine to use
1083184b762dSLee Jones * @addr: address
1084184b762dSLee Jones * @seq: sequence number
1085184b762dSLee Jones * @flags: fence related flags
1086d38ceaf9SAlex Deucher *
1087d38ceaf9SAlex Deucher */
amdgpu_vce_ring_emit_fence(struct amdgpu_ring * ring,u64 addr,u64 seq,unsigned int flags)1088d38ceaf9SAlex Deucher void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
1089f10984a3SSrinivasan Shanmugam unsigned int flags)
1090d38ceaf9SAlex Deucher {
1091890ee23fSChunming Zhou WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
1092d38ceaf9SAlex Deucher
1093d38ceaf9SAlex Deucher amdgpu_ring_write(ring, VCE_CMD_FENCE);
1094d38ceaf9SAlex Deucher amdgpu_ring_write(ring, addr);
1095d38ceaf9SAlex Deucher amdgpu_ring_write(ring, upper_32_bits(addr));
1096d38ceaf9SAlex Deucher amdgpu_ring_write(ring, seq);
1097d38ceaf9SAlex Deucher amdgpu_ring_write(ring, VCE_CMD_TRAP);
1098d38ceaf9SAlex Deucher amdgpu_ring_write(ring, VCE_CMD_END);
1099d38ceaf9SAlex Deucher }
1100d38ceaf9SAlex Deucher
1101d38ceaf9SAlex Deucher /**
1102d38ceaf9SAlex Deucher * amdgpu_vce_ring_test_ring - test if VCE ring is working
1103d38ceaf9SAlex Deucher *
1104d38ceaf9SAlex Deucher * @ring: the engine to test on
1105d38ceaf9SAlex Deucher *
1106d38ceaf9SAlex Deucher */
amdgpu_vce_ring_test_ring(struct amdgpu_ring * ring)1107d38ceaf9SAlex Deucher int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
1108d38ceaf9SAlex Deucher {
1109d38ceaf9SAlex Deucher struct amdgpu_device *adev = ring->adev;
1110ce0e22f5SLouis Li uint32_t rptr;
1111f10984a3SSrinivasan Shanmugam unsigned int i;
1112a2f537e0SXiangliang Yu int r, timeout = adev->usec_timeout;
1113a2f537e0SXiangliang Yu
1114a1b9022aSFrank Min /* skip ring test for sriov*/
1115a2f537e0SXiangliang Yu if (amdgpu_sriov_vf(adev))
1116a1b9022aSFrank Min return 0;
1117d38ceaf9SAlex Deucher
1118a27de35cSChristian König r = amdgpu_ring_alloc(ring, 16);
1119dc9eeff8SChristian König if (r)
1120d38ceaf9SAlex Deucher return r;
1121dc9eeff8SChristian König
1122ce0e22f5SLouis Li rptr = amdgpu_ring_get_rptr(ring);
1123ce0e22f5SLouis Li
1124d38ceaf9SAlex Deucher amdgpu_ring_write(ring, VCE_CMD_END);
1125a27de35cSChristian König amdgpu_ring_commit(ring);
1126d38ceaf9SAlex Deucher
1127a2f537e0SXiangliang Yu for (i = 0; i < timeout; i++) {
1128d38ceaf9SAlex Deucher if (amdgpu_ring_get_rptr(ring) != rptr)
1129d38ceaf9SAlex Deucher break;
1130c366be54SSam Ravnborg udelay(1);
1131d38ceaf9SAlex Deucher }
1132d38ceaf9SAlex Deucher
1133dc9eeff8SChristian König if (i >= timeout)
1134d38ceaf9SAlex Deucher r = -ETIMEDOUT;
1135d38ceaf9SAlex Deucher
1136d38ceaf9SAlex Deucher return r;
1137d38ceaf9SAlex Deucher }
1138d38ceaf9SAlex Deucher
1139d38ceaf9SAlex Deucher /**
1140d38ceaf9SAlex Deucher * amdgpu_vce_ring_test_ib - test if VCE IBs are working
1141d38ceaf9SAlex Deucher *
1142d38ceaf9SAlex Deucher * @ring: the engine to test on
1143184b762dSLee Jones * @timeout: timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT
1144d38ceaf9SAlex Deucher *
1145d38ceaf9SAlex Deucher */
amdgpu_vce_ring_test_ib(struct amdgpu_ring * ring,long timeout)1146bbec97aaSChristian König int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout)
1147d38ceaf9SAlex Deucher {
1148f54d1867SChris Wilson struct dma_fence *fence = NULL;
1149bbec97aaSChristian König long r;
1150d38ceaf9SAlex Deucher
11516f0359ffSAlex Deucher /* skip vce ring1/2 ib test for now, since it's not reliable */
11526f0359ffSAlex Deucher if (ring != &ring->adev->vce.ring[0])
1153898e50d4SLeo Liu return 0;
1154898e50d4SLeo Liu
1155cb9038aaSxinhui pan r = amdgpu_vce_get_create_msg(ring, 1, NULL);
115698079389SChristian König if (r)
1157d38ceaf9SAlex Deucher goto error;
1158d38ceaf9SAlex Deucher
11599f2ade33SChristian König r = amdgpu_vce_get_destroy_msg(ring, 1, true, &fence);
116098079389SChristian König if (r)
1161d38ceaf9SAlex Deucher goto error;
1162d38ceaf9SAlex Deucher
1163f54d1867SChris Wilson r = dma_fence_wait_timeout(fence, false, timeout);
116498079389SChristian König if (r == 0)
1165bbec97aaSChristian König r = -ETIMEDOUT;
116698079389SChristian König else if (r > 0)
1167bbec97aaSChristian König r = 0;
116898079389SChristian König
1169d38ceaf9SAlex Deucher error:
1170f54d1867SChris Wilson dma_fence_put(fence);
1171d38ceaf9SAlex Deucher return r;
1172d38ceaf9SAlex Deucher }
1173080e613cSSatyajit Sahu
amdgpu_vce_get_ring_prio(int ring)1174080e613cSSatyajit Sahu enum amdgpu_ring_priority_level amdgpu_vce_get_ring_prio(int ring)
1175080e613cSSatyajit Sahu {
1176080e613cSSatyajit Sahu switch (ring) {
1177080e613cSSatyajit Sahu case 0:
1178080e613cSSatyajit Sahu return AMDGPU_RING_PRIO_0;
1179080e613cSSatyajit Sahu case 1:
1180080e613cSSatyajit Sahu return AMDGPU_RING_PRIO_1;
1181080e613cSSatyajit Sahu case 2:
1182080e613cSSatyajit Sahu return AMDGPU_RING_PRIO_2;
1183080e613cSSatyajit Sahu default:
1184080e613cSSatyajit Sahu return AMDGPU_RING_PRIO_0;
1185080e613cSSatyajit Sahu }
1186080e613cSSatyajit Sahu }
1187