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