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