Commit | Line | Data |
---|---|---|
d38ceaf9 AD |
1 | /* |
2 | * Copyright 2013 Advanced Micro Devices, Inc. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * Permission is hereby granted, free of charge, to any person obtaining a | |
6 | * copy of this software and associated documentation files (the | |
7 | * "Software"), to deal in the Software without restriction, including | |
8 | * without limitation the rights to use, copy, modify, merge, publish, | |
9 | * distribute, sub license, and/or sell copies of the Software, and to | |
10 | * permit persons to whom the Software is furnished to do so, subject to | |
11 | * the following conditions: | |
12 | * | |
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | |
16 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | |
17 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | |
19 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | |
20 | * | |
21 | * The above copyright notice and this permission notice (including the | |
22 | * next paragraph) shall be included in all copies or substantial portions | |
23 | * of the Software. | |
24 | * | |
25 | * Authors: Christian König <christian.koenig@amd.com> | |
26 | */ | |
27 | ||
28 | #include <linux/firmware.h> | |
29 | #include <linux/module.h> | |
fdf2f6c5 | 30 | |
d38ceaf9 AD |
31 | #include <drm/drm.h> |
32 | ||
33 | #include "amdgpu.h" | |
34 | #include "amdgpu_pm.h" | |
35 | #include "amdgpu_vce.h" | |
36 | #include "cikd.h" | |
37 | ||
38 | /* 1 second timeout */ | |
182830a1 | 39 | #define VCE_IDLE_TIMEOUT msecs_to_jiffies(1000) |
d38ceaf9 AD |
40 | |
41 | /* Firmware Names */ | |
42 | #ifdef CONFIG_DRM_AMDGPU_CIK | |
ce206464 AD |
43 | #define FIRMWARE_BONAIRE "amdgpu/bonaire_vce.bin" |
44 | #define FIRMWARE_KABINI "amdgpu/kabini_vce.bin" | |
45 | #define FIRMWARE_KAVERI "amdgpu/kaveri_vce.bin" | |
46 | #define FIRMWARE_HAWAII "amdgpu/hawaii_vce.bin" | |
47 | #define FIRMWARE_MULLINS "amdgpu/mullins_vce.bin" | |
d38ceaf9 | 48 | #endif |
c65444fe JZ |
49 | #define FIRMWARE_TONGA "amdgpu/tonga_vce.bin" |
50 | #define FIRMWARE_CARRIZO "amdgpu/carrizo_vce.bin" | |
188a9bcd | 51 | #define FIRMWARE_FIJI "amdgpu/fiji_vce.bin" |
cfaba566 | 52 | #define FIRMWARE_STONEY "amdgpu/stoney_vce.bin" |
2cc0c0b5 | 53 | #define FIRMWARE_POLARIS10 "amdgpu/polaris10_vce.bin" |
f11ded5e LL |
54 | #define FIRMWARE_POLARIS11 "amdgpu/polaris11_vce.bin" |
55 | #define FIRMWARE_POLARIS12 "amdgpu/polaris12_vce.bin" | |
56 | #define FIRMWARE_VEGAM "amdgpu/vegam_vce.bin" | |
d38ceaf9 | 57 | |
c1dc356a | 58 | #define FIRMWARE_VEGA10 "amdgpu/vega10_vce.bin" |
9aa52bc4 | 59 | #define FIRMWARE_VEGA12 "amdgpu/vega12_vce.bin" |
341b4ce2 | 60 | #define FIRMWARE_VEGA20 "amdgpu/vega20_vce.bin" |
c1dc356a | 61 | |
d38ceaf9 AD |
62 | #ifdef CONFIG_DRM_AMDGPU_CIK |
63 | MODULE_FIRMWARE(FIRMWARE_BONAIRE); | |
64 | MODULE_FIRMWARE(FIRMWARE_KABINI); | |
65 | MODULE_FIRMWARE(FIRMWARE_KAVERI); | |
66 | MODULE_FIRMWARE(FIRMWARE_HAWAII); | |
67 | MODULE_FIRMWARE(FIRMWARE_MULLINS); | |
68 | #endif | |
69 | MODULE_FIRMWARE(FIRMWARE_TONGA); | |
70 | MODULE_FIRMWARE(FIRMWARE_CARRIZO); | |
188a9bcd | 71 | MODULE_FIRMWARE(FIRMWARE_FIJI); |
cfaba566 | 72 | MODULE_FIRMWARE(FIRMWARE_STONEY); |
2cc0c0b5 FC |
73 | MODULE_FIRMWARE(FIRMWARE_POLARIS10); |
74 | MODULE_FIRMWARE(FIRMWARE_POLARIS11); | |
c4642a47 | 75 | MODULE_FIRMWARE(FIRMWARE_POLARIS12); |
f11ded5e | 76 | MODULE_FIRMWARE(FIRMWARE_VEGAM); |
d38ceaf9 | 77 | |
c1dc356a | 78 | MODULE_FIRMWARE(FIRMWARE_VEGA10); |
9aa52bc4 | 79 | MODULE_FIRMWARE(FIRMWARE_VEGA12); |
341b4ce2 | 80 | MODULE_FIRMWARE(FIRMWARE_VEGA20); |
c1dc356a | 81 | |
d38ceaf9 | 82 | static void amdgpu_vce_idle_work_handler(struct work_struct *work); |
17523bd0 AD |
83 | static int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, |
84 | struct amdgpu_bo *bo, | |
85 | struct dma_fence **fence); | |
86 | static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, | |
87 | bool direct, struct dma_fence **fence); | |
d38ceaf9 AD |
88 | |
89 | /** | |
90 | * amdgpu_vce_init - allocate memory, load vce firmware | |
91 | * | |
92 | * @adev: amdgpu_device pointer | |
184b762d | 93 | * @size: size for the new BO |
d38ceaf9 AD |
94 | * |
95 | * First step to get VCE online, allocate memory and load the firmware | |
96 | */ | |
e9822622 | 97 | int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) |
d38ceaf9 | 98 | { |
d38ceaf9 AD |
99 | const char *fw_name; |
100 | const struct common_firmware_header *hdr; | |
101 | unsigned ucode_version, version_major, version_minor, binary_id; | |
102 | int i, r; | |
103 | ||
d38ceaf9 AD |
104 | switch (adev->asic_type) { |
105 | #ifdef CONFIG_DRM_AMDGPU_CIK | |
106 | case CHIP_BONAIRE: | |
107 | fw_name = FIRMWARE_BONAIRE; | |
108 | break; | |
109 | case CHIP_KAVERI: | |
110 | fw_name = FIRMWARE_KAVERI; | |
111 | break; | |
112 | case CHIP_KABINI: | |
113 | fw_name = FIRMWARE_KABINI; | |
114 | break; | |
115 | case CHIP_HAWAII: | |
116 | fw_name = FIRMWARE_HAWAII; | |
117 | break; | |
118 | case CHIP_MULLINS: | |
119 | fw_name = FIRMWARE_MULLINS; | |
120 | break; | |
121 | #endif | |
122 | case CHIP_TONGA: | |
123 | fw_name = FIRMWARE_TONGA; | |
124 | break; | |
125 | case CHIP_CARRIZO: | |
126 | fw_name = FIRMWARE_CARRIZO; | |
127 | break; | |
188a9bcd AD |
128 | case CHIP_FIJI: |
129 | fw_name = FIRMWARE_FIJI; | |
130 | break; | |
cfaba566 SL |
131 | case CHIP_STONEY: |
132 | fw_name = FIRMWARE_STONEY; | |
133 | break; | |
2cc0c0b5 FC |
134 | case CHIP_POLARIS10: |
135 | fw_name = FIRMWARE_POLARIS10; | |
1b4eeea5 | 136 | break; |
2cc0c0b5 FC |
137 | case CHIP_POLARIS11: |
138 | fw_name = FIRMWARE_POLARIS11; | |
1b4eeea5 | 139 | break; |
9aa52bc4 AD |
140 | case CHIP_POLARIS12: |
141 | fw_name = FIRMWARE_POLARIS12; | |
142 | break; | |
f11ded5e LL |
143 | case CHIP_VEGAM: |
144 | fw_name = FIRMWARE_VEGAM; | |
145 | break; | |
c1dc356a LL |
146 | case CHIP_VEGA10: |
147 | fw_name = FIRMWARE_VEGA10; | |
148 | break; | |
9aa52bc4 AD |
149 | case CHIP_VEGA12: |
150 | fw_name = FIRMWARE_VEGA12; | |
c4642a47 | 151 | break; |
341b4ce2 FX |
152 | case CHIP_VEGA20: |
153 | fw_name = FIRMWARE_VEGA20; | |
154 | break; | |
d38ceaf9 AD |
155 | |
156 | default: | |
157 | return -EINVAL; | |
158 | } | |
159 | ||
160 | r = request_firmware(&adev->vce.fw, fw_name, adev->dev); | |
161 | if (r) { | |
162 | dev_err(adev->dev, "amdgpu_vce: Can't load firmware \"%s\"\n", | |
163 | fw_name); | |
164 | return r; | |
165 | } | |
166 | ||
167 | r = amdgpu_ucode_validate(adev->vce.fw); | |
168 | if (r) { | |
169 | dev_err(adev->dev, "amdgpu_vce: Can't validate firmware \"%s\"\n", | |
170 | fw_name); | |
171 | release_firmware(adev->vce.fw); | |
172 | adev->vce.fw = NULL; | |
173 | return r; | |
174 | } | |
175 | ||
176 | hdr = (const struct common_firmware_header *)adev->vce.fw->data; | |
177 | ||
178 | ucode_version = le32_to_cpu(hdr->ucode_version); | |
179 | version_major = (ucode_version >> 20) & 0xfff; | |
180 | version_minor = (ucode_version >> 8) & 0xfff; | |
181 | binary_id = ucode_version & 0xff; | |
0b437e64 | 182 | DRM_INFO("Found VCE firmware Version: %d.%d Binary ID: %d\n", |
d38ceaf9 AD |
183 | version_major, version_minor, binary_id); |
184 | adev->vce.fw_version = ((version_major << 24) | (version_minor << 16) | | |
185 | (binary_id << 8)); | |
186 | ||
78b3c839 LL |
187 | r = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE, |
188 | AMDGPU_GEM_DOMAIN_VRAM, &adev->vce.vcpu_bo, | |
189 | &adev->vce.gpu_addr, &adev->vce.cpu_addr); | |
d38ceaf9 AD |
190 | if (r) { |
191 | dev_err(adev->dev, "(%d) failed to allocate VCE bo\n", r); | |
192 | return r; | |
193 | } | |
194 | ||
d38ceaf9 AD |
195 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { |
196 | atomic_set(&adev->vce.handles[i], 0); | |
197 | adev->vce.filp[i] = NULL; | |
198 | } | |
199 | ||
ebff485e CK |
200 | INIT_DELAYED_WORK(&adev->vce.idle_work, amdgpu_vce_idle_work_handler); |
201 | mutex_init(&adev->vce.idle_mutex); | |
202 | ||
d38ceaf9 AD |
203 | return 0; |
204 | } | |
205 | ||
206 | /** | |
207 | * amdgpu_vce_fini - free memory | |
208 | * | |
209 | * @adev: amdgpu_device pointer | |
210 | * | |
211 | * Last step on VCE teardown, free firmware memory | |
212 | */ | |
213 | int amdgpu_vce_sw_fini(struct amdgpu_device *adev) | |
214 | { | |
4cd00d37 GI |
215 | unsigned i; |
216 | ||
d38ceaf9 AD |
217 | if (adev->vce.vcpu_bo == NULL) |
218 | return 0; | |
219 | ||
9f875167 | 220 | cancel_delayed_work_sync(&adev->vce.idle_work); |
cdc50176 | 221 | drm_sched_entity_destroy(&adev->vce.entity); |
c594989c | 222 | |
78b3c839 LL |
223 | amdgpu_bo_free_kernel(&adev->vce.vcpu_bo, &adev->vce.gpu_addr, |
224 | (void **)&adev->vce.cpu_addr); | |
d38ceaf9 | 225 | |
4cd00d37 GI |
226 | for (i = 0; i < adev->vce.num_rings; i++) |
227 | amdgpu_ring_fini(&adev->vce.ring[i]); | |
d38ceaf9 AD |
228 | |
229 | release_firmware(adev->vce.fw); | |
ebff485e | 230 | mutex_destroy(&adev->vce.idle_mutex); |
d38ceaf9 AD |
231 | |
232 | return 0; | |
233 | } | |
234 | ||
20acbed4 ED |
235 | /** |
236 | * amdgpu_vce_entity_init - init entity | |
237 | * | |
238 | * @adev: amdgpu_device pointer | |
239 | * | |
240 | */ | |
241 | int amdgpu_vce_entity_init(struct amdgpu_device *adev) | |
242 | { | |
243 | struct amdgpu_ring *ring; | |
b3ac1766 | 244 | struct drm_gpu_scheduler *sched; |
20acbed4 ED |
245 | int r; |
246 | ||
247 | ring = &adev->vce.ring[0]; | |
b3ac1766 ND |
248 | sched = &ring->sched; |
249 | r = drm_sched_entity_init(&adev->vce.entity, DRM_SCHED_PRIORITY_NORMAL, | |
250 | &sched, 1, NULL); | |
20acbed4 ED |
251 | if (r != 0) { |
252 | DRM_ERROR("Failed setting up VCE run queue.\n"); | |
253 | return r; | |
254 | } | |
255 | ||
256 | return 0; | |
257 | } | |
258 | ||
d38ceaf9 AD |
259 | /** |
260 | * amdgpu_vce_suspend - unpin VCE fw memory | |
261 | * | |
262 | * @adev: amdgpu_device pointer | |
263 | * | |
264 | */ | |
265 | int amdgpu_vce_suspend(struct amdgpu_device *adev) | |
266 | { | |
267 | int i; | |
268 | ||
61ea6f58 RZ |
269 | cancel_delayed_work_sync(&adev->vce.idle_work); |
270 | ||
d38ceaf9 AD |
271 | if (adev->vce.vcpu_bo == NULL) |
272 | return 0; | |
273 | ||
274 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) | |
275 | if (atomic_read(&adev->vce.handles[i])) | |
276 | break; | |
277 | ||
278 | if (i == AMDGPU_MAX_VCE_HANDLES) | |
279 | return 0; | |
280 | ||
281 | /* TODO: suspending running encoding sessions isn't supported */ | |
282 | return -EINVAL; | |
283 | } | |
284 | ||
285 | /** | |
286 | * amdgpu_vce_resume - pin VCE fw memory | |
287 | * | |
288 | * @adev: amdgpu_device pointer | |
289 | * | |
290 | */ | |
291 | int amdgpu_vce_resume(struct amdgpu_device *adev) | |
292 | { | |
293 | void *cpu_addr; | |
294 | const struct common_firmware_header *hdr; | |
295 | unsigned offset; | |
296 | int r; | |
297 | ||
298 | if (adev->vce.vcpu_bo == NULL) | |
299 | return -EINVAL; | |
300 | ||
301 | r = amdgpu_bo_reserve(adev->vce.vcpu_bo, false); | |
302 | if (r) { | |
303 | dev_err(adev->dev, "(%d) failed to reserve VCE bo\n", r); | |
304 | return r; | |
305 | } | |
306 | ||
307 | r = amdgpu_bo_kmap(adev->vce.vcpu_bo, &cpu_addr); | |
308 | if (r) { | |
309 | amdgpu_bo_unreserve(adev->vce.vcpu_bo); | |
310 | dev_err(adev->dev, "(%d) VCE map failed\n", r); | |
311 | return r; | |
312 | } | |
313 | ||
314 | hdr = (const struct common_firmware_header *)adev->vce.fw->data; | |
315 | offset = le32_to_cpu(hdr->ucode_array_offset_bytes); | |
7b4d3e29 CK |
316 | memcpy_toio(cpu_addr, adev->vce.fw->data + offset, |
317 | adev->vce.fw->size - offset); | |
d38ceaf9 AD |
318 | |
319 | amdgpu_bo_kunmap(adev->vce.vcpu_bo); | |
320 | ||
321 | amdgpu_bo_unreserve(adev->vce.vcpu_bo); | |
322 | ||
323 | return 0; | |
324 | } | |
325 | ||
326 | /** | |
327 | * amdgpu_vce_idle_work_handler - power off VCE | |
328 | * | |
329 | * @work: pointer to work structure | |
330 | * | |
331 | * power of VCE when it's not used any more | |
332 | */ | |
333 | static void amdgpu_vce_idle_work_handler(struct work_struct *work) | |
334 | { | |
335 | struct amdgpu_device *adev = | |
336 | container_of(work, struct amdgpu_device, vce.idle_work.work); | |
24c5fe56 | 337 | unsigned i, count = 0; |
d38ceaf9 | 338 | |
24c5fe56 AD |
339 | for (i = 0; i < adev->vce.num_rings; i++) |
340 | count += amdgpu_fence_count_emitted(&adev->vce.ring[i]); | |
341 | ||
342 | if (count == 0) { | |
d38ceaf9 AD |
343 | if (adev->pm.dpm_enabled) { |
344 | amdgpu_dpm_enable_vce(adev, false); | |
345 | } else { | |
346 | amdgpu_asic_set_vce_clocks(adev, 0, 0); | |
2990a1fc AD |
347 | amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE, |
348 | AMD_PG_STATE_GATE); | |
349 | amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE, | |
350 | AMD_CG_STATE_GATE); | |
d38ceaf9 AD |
351 | } |
352 | } else { | |
182830a1 | 353 | schedule_delayed_work(&adev->vce.idle_work, VCE_IDLE_TIMEOUT); |
d38ceaf9 AD |
354 | } |
355 | } | |
356 | ||
357 | /** | |
ebff485e | 358 | * amdgpu_vce_ring_begin_use - power up VCE |
d38ceaf9 | 359 | * |
ebff485e | 360 | * @ring: amdgpu ring |
d38ceaf9 AD |
361 | * |
362 | * Make sure VCE is powerd up when we want to use it | |
363 | */ | |
ebff485e | 364 | void amdgpu_vce_ring_begin_use(struct amdgpu_ring *ring) |
d38ceaf9 | 365 | { |
ebff485e CK |
366 | struct amdgpu_device *adev = ring->adev; |
367 | bool set_clocks; | |
d38ceaf9 | 368 | |
d9af2259 XY |
369 | if (amdgpu_sriov_vf(adev)) |
370 | return; | |
371 | ||
ebff485e CK |
372 | mutex_lock(&adev->vce.idle_mutex); |
373 | set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work); | |
182830a1 | 374 | if (set_clocks) { |
d38ceaf9 AD |
375 | if (adev->pm.dpm_enabled) { |
376 | amdgpu_dpm_enable_vce(adev, true); | |
377 | } else { | |
378 | amdgpu_asic_set_vce_clocks(adev, 53300, 40000); | |
2990a1fc AD |
379 | amdgpu_device_ip_set_clockgating_state(adev, AMD_IP_BLOCK_TYPE_VCE, |
380 | AMD_CG_STATE_UNGATE); | |
381 | amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VCE, | |
382 | AMD_PG_STATE_UNGATE); | |
28ed5504 | 383 | |
d38ceaf9 AD |
384 | } |
385 | } | |
ebff485e CK |
386 | mutex_unlock(&adev->vce.idle_mutex); |
387 | } | |
388 | ||
389 | /** | |
390 | * amdgpu_vce_ring_end_use - power VCE down | |
391 | * | |
392 | * @ring: amdgpu ring | |
393 | * | |
394 | * Schedule work to power VCE down again | |
395 | */ | |
396 | void amdgpu_vce_ring_end_use(struct amdgpu_ring *ring) | |
397 | { | |
14a8032a ML |
398 | if (!amdgpu_sriov_vf(ring->adev)) |
399 | schedule_delayed_work(&ring->adev->vce.idle_work, VCE_IDLE_TIMEOUT); | |
d38ceaf9 AD |
400 | } |
401 | ||
402 | /** | |
403 | * amdgpu_vce_free_handles - free still open VCE handles | |
404 | * | |
405 | * @adev: amdgpu_device pointer | |
406 | * @filp: drm file pointer | |
407 | * | |
408 | * Close all VCE handles still open by this file pointer | |
409 | */ | |
410 | void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp) | |
411 | { | |
412 | struct amdgpu_ring *ring = &adev->vce.ring[0]; | |
413 | int i, r; | |
414 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { | |
415 | uint32_t handle = atomic_read(&adev->vce.handles[i]); | |
182830a1 | 416 | |
d38ceaf9 AD |
417 | if (!handle || adev->vce.filp[i] != filp) |
418 | continue; | |
419 | ||
9f2ade33 | 420 | r = amdgpu_vce_get_destroy_msg(ring, handle, false, NULL); |
d38ceaf9 AD |
421 | if (r) |
422 | DRM_ERROR("Error destroying VCE handle (%d)!\n", r); | |
423 | ||
424 | adev->vce.filp[i] = NULL; | |
425 | atomic_set(&adev->vce.handles[i], 0); | |
426 | } | |
427 | } | |
428 | ||
429 | /** | |
430 | * amdgpu_vce_get_create_msg - generate a VCE create msg | |
431 | * | |
d38ceaf9 AD |
432 | * @ring: ring we should submit the msg to |
433 | * @handle: VCE session handle to use | |
184b762d | 434 | * @bo: amdgpu object for which we query the offset |
d38ceaf9 AD |
435 | * @fence: optional fence to return |
436 | * | |
437 | * Open up a stream for HW test | |
438 | */ | |
17523bd0 AD |
439 | static int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, |
440 | struct amdgpu_bo *bo, | |
441 | struct dma_fence **fence) | |
d38ceaf9 AD |
442 | { |
443 | const unsigned ib_size_dw = 1024; | |
d71518b5 CK |
444 | struct amdgpu_job *job; |
445 | struct amdgpu_ib *ib; | |
f54d1867 | 446 | struct dma_fence *f = NULL; |
569557e5 | 447 | uint64_t addr; |
d38ceaf9 AD |
448 | int i, r; |
449 | ||
c8e42d57 | 450 | r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, |
9ecefb19 | 451 | AMDGPU_IB_POOL_DIRECT, &job); |
d71518b5 | 452 | if (r) |
d38ceaf9 | 453 | return r; |
d71518b5 CK |
454 | |
455 | ib = &job->ibs[0]; | |
d38ceaf9 | 456 | |
569557e5 | 457 | addr = amdgpu_bo_gpu_offset(bo); |
d38ceaf9 AD |
458 | |
459 | /* stitch together an VCE create msg */ | |
8128765c CZ |
460 | ib->length_dw = 0; |
461 | ib->ptr[ib->length_dw++] = 0x0000000c; /* len */ | |
462 | ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */ | |
463 | ib->ptr[ib->length_dw++] = handle; | |
464 | ||
d66f8e48 LL |
465 | if ((ring->adev->vce.fw_version >> 24) >= 52) |
466 | ib->ptr[ib->length_dw++] = 0x00000040; /* len */ | |
467 | else | |
468 | ib->ptr[ib->length_dw++] = 0x00000030; /* len */ | |
8128765c CZ |
469 | ib->ptr[ib->length_dw++] = 0x01000001; /* create cmd */ |
470 | ib->ptr[ib->length_dw++] = 0x00000000; | |
471 | ib->ptr[ib->length_dw++] = 0x00000042; | |
472 | ib->ptr[ib->length_dw++] = 0x0000000a; | |
473 | ib->ptr[ib->length_dw++] = 0x00000001; | |
474 | ib->ptr[ib->length_dw++] = 0x00000080; | |
475 | ib->ptr[ib->length_dw++] = 0x00000060; | |
476 | ib->ptr[ib->length_dw++] = 0x00000100; | |
477 | ib->ptr[ib->length_dw++] = 0x00000100; | |
478 | ib->ptr[ib->length_dw++] = 0x0000000c; | |
479 | ib->ptr[ib->length_dw++] = 0x00000000; | |
d66f8e48 LL |
480 | if ((ring->adev->vce.fw_version >> 24) >= 52) { |
481 | ib->ptr[ib->length_dw++] = 0x00000000; | |
482 | ib->ptr[ib->length_dw++] = 0x00000000; | |
483 | ib->ptr[ib->length_dw++] = 0x00000000; | |
484 | ib->ptr[ib->length_dw++] = 0x00000000; | |
485 | } | |
8128765c CZ |
486 | |
487 | ib->ptr[ib->length_dw++] = 0x00000014; /* len */ | |
488 | ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */ | |
569557e5 AD |
489 | ib->ptr[ib->length_dw++] = upper_32_bits(addr); |
490 | ib->ptr[ib->length_dw++] = addr; | |
8128765c CZ |
491 | ib->ptr[ib->length_dw++] = 0x00000001; |
492 | ||
493 | for (i = ib->length_dw; i < ib_size_dw; ++i) | |
494 | ib->ptr[i] = 0x0; | |
495 | ||
ee913fd9 | 496 | r = amdgpu_job_submit_direct(job, ring, &f); |
8128765c CZ |
497 | if (r) |
498 | goto err; | |
9f2ade33 | 499 | |
d38ceaf9 | 500 | if (fence) |
f54d1867 CW |
501 | *fence = dma_fence_get(f); |
502 | dma_fence_put(f); | |
cadf97b1 | 503 | return 0; |
d71518b5 | 504 | |
8128765c | 505 | err: |
d71518b5 | 506 | amdgpu_job_free(job); |
d38ceaf9 AD |
507 | return r; |
508 | } | |
509 | ||
510 | /** | |
511 | * amdgpu_vce_get_destroy_msg - generate a VCE destroy msg | |
512 | * | |
d38ceaf9 AD |
513 | * @ring: ring we should submit the msg to |
514 | * @handle: VCE session handle to use | |
184b762d | 515 | * @direct: direct or delayed pool |
d38ceaf9 AD |
516 | * @fence: optional fence to return |
517 | * | |
518 | * Close up a stream for HW test or if userspace failed to do so | |
519 | */ | |
17523bd0 AD |
520 | static int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, |
521 | bool direct, struct dma_fence **fence) | |
d38ceaf9 AD |
522 | { |
523 | const unsigned ib_size_dw = 1024; | |
d71518b5 CK |
524 | struct amdgpu_job *job; |
525 | struct amdgpu_ib *ib; | |
f54d1867 | 526 | struct dma_fence *f = NULL; |
d38ceaf9 AD |
527 | int i, r; |
528 | ||
c8e42d57 | 529 | r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, |
9ecefb19 CK |
530 | direct ? AMDGPU_IB_POOL_DIRECT : |
531 | AMDGPU_IB_POOL_DELAYED, &job); | |
d71518b5 | 532 | if (r) |
d38ceaf9 | 533 | return r; |
d38ceaf9 | 534 | |
d71518b5 | 535 | ib = &job->ibs[0]; |
d38ceaf9 AD |
536 | |
537 | /* stitch together an VCE destroy msg */ | |
8128765c CZ |
538 | ib->length_dw = 0; |
539 | ib->ptr[ib->length_dw++] = 0x0000000c; /* len */ | |
540 | ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */ | |
541 | ib->ptr[ib->length_dw++] = handle; | |
542 | ||
99453a9e RZ |
543 | ib->ptr[ib->length_dw++] = 0x00000020; /* len */ |
544 | ib->ptr[ib->length_dw++] = 0x00000002; /* task info */ | |
545 | ib->ptr[ib->length_dw++] = 0xffffffff; /* next task info, set to 0xffffffff if no */ | |
546 | ib->ptr[ib->length_dw++] = 0x00000001; /* destroy session */ | |
547 | ib->ptr[ib->length_dw++] = 0x00000000; | |
548 | ib->ptr[ib->length_dw++] = 0x00000000; | |
549 | ib->ptr[ib->length_dw++] = 0xffffffff; /* feedback is not needed, set to 0xffffffff and firmware will not output feedback */ | |
550 | ib->ptr[ib->length_dw++] = 0x00000000; | |
8128765c CZ |
551 | |
552 | ib->ptr[ib->length_dw++] = 0x00000008; /* len */ | |
553 | ib->ptr[ib->length_dw++] = 0x02000001; /* destroy cmd */ | |
554 | ||
555 | for (i = ib->length_dw; i < ib_size_dw; ++i) | |
556 | ib->ptr[i] = 0x0; | |
9f2ade33 | 557 | |
ee913fd9 CK |
558 | if (direct) |
559 | r = amdgpu_job_submit_direct(job, ring, &f); | |
560 | else | |
0e28b10f | 561 | r = amdgpu_job_submit(job, &ring->adev->vce.entity, |
9f2ade33 | 562 | AMDGPU_FENCE_OWNER_UNDEFINED, &f); |
ee913fd9 CK |
563 | if (r) |
564 | goto err; | |
9f2ade33 | 565 | |
d38ceaf9 | 566 | if (fence) |
f54d1867 CW |
567 | *fence = dma_fence_get(f); |
568 | dma_fence_put(f); | |
cadf97b1 | 569 | return 0; |
d71518b5 | 570 | |
8128765c | 571 | err: |
d71518b5 | 572 | amdgpu_job_free(job); |
d38ceaf9 AD |
573 | return r; |
574 | } | |
575 | ||
23594318 CK |
576 | /** |
577 | * amdgpu_vce_cs_validate_bo - make sure not to cross 4GB boundary | |
578 | * | |
579 | * @p: parser context | |
184b762d | 580 | * @ib_idx: indirect buffer to use |
23594318 CK |
581 | * @lo: address of lower dword |
582 | * @hi: address of higher dword | |
583 | * @size: minimum size | |
584 | * @index: bs/fb index | |
585 | * | |
586 | * Make sure that no BO cross a 4GB boundary. | |
587 | */ | |
588 | static int amdgpu_vce_validate_bo(struct amdgpu_cs_parser *p, uint32_t ib_idx, | |
589 | int lo, int hi, unsigned size, int32_t index) | |
590 | { | |
591 | int64_t offset = ((uint64_t)size) * ((int64_t)index); | |
19be5570 | 592 | struct ttm_operation_ctx ctx = { false, false }; |
23594318 CK |
593 | struct amdgpu_bo_va_mapping *mapping; |
594 | unsigned i, fpfn, lpfn; | |
595 | struct amdgpu_bo *bo; | |
596 | uint64_t addr; | |
597 | int r; | |
598 | ||
599 | addr = ((uint64_t)amdgpu_get_ib_value(p, ib_idx, lo)) | | |
600 | ((uint64_t)amdgpu_get_ib_value(p, ib_idx, hi)) << 32; | |
601 | if (index >= 0) { | |
602 | addr += offset; | |
603 | fpfn = PAGE_ALIGN(offset) >> PAGE_SHIFT; | |
604 | lpfn = 0x100000000ULL >> PAGE_SHIFT; | |
605 | } else { | |
606 | fpfn = 0; | |
607 | lpfn = (0x100000000ULL - PAGE_ALIGN(offset)) >> PAGE_SHIFT; | |
608 | } | |
609 | ||
610 | r = amdgpu_cs_find_mapping(p, addr, &bo, &mapping); | |
611 | if (r) { | |
612 | DRM_ERROR("Can't find BO for addr 0x%010Lx %d %d %d %d\n", | |
613 | addr, lo, hi, size, index); | |
614 | return r; | |
615 | } | |
616 | ||
617 | for (i = 0; i < bo->placement.num_placement; ++i) { | |
618 | bo->placements[i].fpfn = max(bo->placements[i].fpfn, fpfn); | |
4c63abb2 CK |
619 | bo->placements[i].lpfn = bo->placements[i].lpfn ? |
620 | min(bo->placements[i].lpfn, lpfn) : lpfn; | |
23594318 | 621 | } |
19be5570 | 622 | return ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); |
23594318 CK |
623 | } |
624 | ||
625 | ||
d38ceaf9 AD |
626 | /** |
627 | * amdgpu_vce_cs_reloc - command submission relocation | |
628 | * | |
629 | * @p: parser context | |
184b762d | 630 | * @ib_idx: indirect buffer to use |
d38ceaf9 AD |
631 | * @lo: address of lower dword |
632 | * @hi: address of higher dword | |
f1689ec1 | 633 | * @size: minimum size |
184b762d | 634 | * @index: bs/fb index |
d38ceaf9 AD |
635 | * |
636 | * Patch relocation inside command stream with real buffer address | |
637 | */ | |
f1689ec1 | 638 | static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx, |
dc78330a | 639 | int lo, int hi, unsigned size, uint32_t index) |
d38ceaf9 AD |
640 | { |
641 | struct amdgpu_bo_va_mapping *mapping; | |
d38ceaf9 AD |
642 | struct amdgpu_bo *bo; |
643 | uint64_t addr; | |
9cca0b8e | 644 | int r; |
d38ceaf9 | 645 | |
dc78330a CK |
646 | if (index == 0xffffffff) |
647 | index = 0; | |
648 | ||
d38ceaf9 AD |
649 | addr = ((uint64_t)amdgpu_get_ib_value(p, ib_idx, lo)) | |
650 | ((uint64_t)amdgpu_get_ib_value(p, ib_idx, hi)) << 32; | |
dc78330a | 651 | addr += ((uint64_t)size) * ((uint64_t)index); |
d38ceaf9 | 652 | |
9cca0b8e CK |
653 | r = amdgpu_cs_find_mapping(p, addr, &bo, &mapping); |
654 | if (r) { | |
dc78330a CK |
655 | DRM_ERROR("Can't find BO for addr 0x%010Lx %d %d %d %d\n", |
656 | addr, lo, hi, size, index); | |
9cca0b8e | 657 | return r; |
d38ceaf9 AD |
658 | } |
659 | ||
f1689ec1 | 660 | if ((addr + (uint64_t)size) > |
a9f87f64 | 661 | (mapping->last + 1) * AMDGPU_GPU_PAGE_SIZE) { |
b20dcd72 | 662 | DRM_ERROR("BO too small for addr 0x%010Lx %d %d\n", |
f1689ec1 CK |
663 | addr, lo, hi); |
664 | return -EINVAL; | |
665 | } | |
666 | ||
a9f87f64 | 667 | addr -= mapping->start * AMDGPU_GPU_PAGE_SIZE; |
d38ceaf9 | 668 | addr += amdgpu_bo_gpu_offset(bo); |
dc78330a | 669 | addr -= ((uint64_t)size) * ((uint64_t)index); |
d38ceaf9 | 670 | |
7270f839 CK |
671 | amdgpu_set_ib_value(p, ib_idx, lo, lower_32_bits(addr)); |
672 | amdgpu_set_ib_value(p, ib_idx, hi, upper_32_bits(addr)); | |
d38ceaf9 AD |
673 | |
674 | return 0; | |
675 | } | |
676 | ||
f1689ec1 CK |
677 | /** |
678 | * amdgpu_vce_validate_handle - validate stream handle | |
679 | * | |
680 | * @p: parser context | |
681 | * @handle: handle to validate | |
2f4b9368 | 682 | * @allocated: allocated a new handle? |
f1689ec1 CK |
683 | * |
684 | * Validates the handle and return the found session index or -EINVAL | |
685 | * we we don't have another free session index. | |
686 | */ | |
687 | static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p, | |
e5223214 | 688 | uint32_t handle, uint32_t *allocated) |
f1689ec1 CK |
689 | { |
690 | unsigned i; | |
691 | ||
692 | /* validate the handle */ | |
693 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { | |
2f4b9368 CK |
694 | if (atomic_read(&p->adev->vce.handles[i]) == handle) { |
695 | if (p->adev->vce.filp[i] != p->filp) { | |
696 | DRM_ERROR("VCE handle collision detected!\n"); | |
697 | return -EINVAL; | |
698 | } | |
f1689ec1 | 699 | return i; |
2f4b9368 | 700 | } |
f1689ec1 CK |
701 | } |
702 | ||
703 | /* handle not found try to alloc a new one */ | |
704 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) { | |
705 | if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) { | |
706 | p->adev->vce.filp[i] = p->filp; | |
707 | p->adev->vce.img_size[i] = 0; | |
e5223214 | 708 | *allocated |= 1 << i; |
f1689ec1 CK |
709 | return i; |
710 | } | |
711 | } | |
712 | ||
713 | DRM_ERROR("No more free VCE handles!\n"); | |
714 | return -EINVAL; | |
715 | } | |
716 | ||
d38ceaf9 AD |
717 | /** |
718 | * amdgpu_vce_cs_parse - parse and validate the command stream | |
719 | * | |
720 | * @p: parser context | |
184b762d | 721 | * @ib_idx: indirect buffer to use |
d38ceaf9 AD |
722 | */ |
723 | int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx) | |
724 | { | |
50838c8c | 725 | struct amdgpu_ib *ib = &p->job->ibs[ib_idx]; |
dc78330a | 726 | unsigned fb_idx = 0, bs_idx = 0; |
f1689ec1 | 727 | int session_idx = -1; |
e5223214 CK |
728 | uint32_t destroyed = 0; |
729 | uint32_t created = 0; | |
730 | uint32_t allocated = 0; | |
f1689ec1 CK |
731 | uint32_t tmp, handle = 0; |
732 | uint32_t *size = &tmp; | |
23594318 CK |
733 | unsigned idx; |
734 | int i, r = 0; | |
c855e250 | 735 | |
45088efc CK |
736 | p->job->vm = NULL; |
737 | ib->gpu_addr = amdgpu_sa_bo_gpu_addr(ib->sa_bo); | |
738 | ||
23594318 | 739 | for (idx = 0; idx < ib->length_dw;) { |
d38ceaf9 AD |
740 | uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx); |
741 | uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1); | |
742 | ||
743 | if ((len < 8) || (len & 3)) { | |
744 | DRM_ERROR("invalid VCE command length (%d)!\n", len); | |
2f4b9368 CK |
745 | r = -EINVAL; |
746 | goto out; | |
d38ceaf9 AD |
747 | } |
748 | ||
23594318 CK |
749 | switch (cmd) { |
750 | case 0x00000002: /* task info */ | |
751 | fb_idx = amdgpu_get_ib_value(p, ib_idx, idx + 6); | |
752 | bs_idx = amdgpu_get_ib_value(p, ib_idx, idx + 7); | |
753 | break; | |
754 | ||
755 | case 0x03000001: /* encode */ | |
756 | r = amdgpu_vce_validate_bo(p, ib_idx, idx + 10, | |
757 | idx + 9, 0, 0); | |
758 | if (r) | |
759 | goto out; | |
760 | ||
761 | r = amdgpu_vce_validate_bo(p, ib_idx, idx + 12, | |
762 | idx + 11, 0, 0); | |
763 | if (r) | |
764 | goto out; | |
765 | break; | |
766 | ||
767 | case 0x05000001: /* context buffer */ | |
768 | r = amdgpu_vce_validate_bo(p, ib_idx, idx + 3, | |
769 | idx + 2, 0, 0); | |
770 | if (r) | |
771 | goto out; | |
772 | break; | |
773 | ||
774 | case 0x05000004: /* video bitstream buffer */ | |
775 | tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4); | |
776 | r = amdgpu_vce_validate_bo(p, ib_idx, idx + 3, idx + 2, | |
777 | tmp, bs_idx); | |
778 | if (r) | |
779 | goto out; | |
780 | break; | |
781 | ||
782 | case 0x05000005: /* feedback buffer */ | |
783 | r = amdgpu_vce_validate_bo(p, ib_idx, idx + 3, idx + 2, | |
784 | 4096, fb_idx); | |
785 | if (r) | |
786 | goto out; | |
787 | break; | |
1eb1547f JZ |
788 | |
789 | case 0x0500000d: /* MV buffer */ | |
790 | r = amdgpu_vce_validate_bo(p, ib_idx, idx + 3, | |
791 | idx + 2, 0, 0); | |
792 | if (r) | |
793 | goto out; | |
794 | ||
795 | r = amdgpu_vce_validate_bo(p, ib_idx, idx + 8, | |
796 | idx + 7, 0, 0); | |
797 | if (r) | |
798 | goto out; | |
799 | break; | |
23594318 CK |
800 | } |
801 | ||
802 | idx += len / 4; | |
803 | } | |
804 | ||
805 | for (idx = 0; idx < ib->length_dw;) { | |
806 | uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx); | |
807 | uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1); | |
808 | ||
d38ceaf9 | 809 | switch (cmd) { |
182830a1 | 810 | case 0x00000001: /* session */ |
d38ceaf9 | 811 | handle = amdgpu_get_ib_value(p, ib_idx, idx + 2); |
2f4b9368 CK |
812 | session_idx = amdgpu_vce_validate_handle(p, handle, |
813 | &allocated); | |
e5223214 CK |
814 | if (session_idx < 0) { |
815 | r = session_idx; | |
816 | goto out; | |
817 | } | |
f1689ec1 | 818 | size = &p->adev->vce.img_size[session_idx]; |
d38ceaf9 AD |
819 | break; |
820 | ||
182830a1 | 821 | case 0x00000002: /* task info */ |
dc78330a CK |
822 | fb_idx = amdgpu_get_ib_value(p, ib_idx, idx + 6); |
823 | bs_idx = amdgpu_get_ib_value(p, ib_idx, idx + 7); | |
f1689ec1 CK |
824 | break; |
825 | ||
182830a1 | 826 | case 0x01000001: /* create */ |
e5223214 CK |
827 | created |= 1 << session_idx; |
828 | if (destroyed & (1 << session_idx)) { | |
829 | destroyed &= ~(1 << session_idx); | |
830 | allocated |= 1 << session_idx; | |
831 | ||
832 | } else if (!(allocated & (1 << session_idx))) { | |
2f4b9368 CK |
833 | DRM_ERROR("Handle already in use!\n"); |
834 | r = -EINVAL; | |
835 | goto out; | |
836 | } | |
837 | ||
f1689ec1 CK |
838 | *size = amdgpu_get_ib_value(p, ib_idx, idx + 8) * |
839 | amdgpu_get_ib_value(p, ib_idx, idx + 10) * | |
840 | 8 * 3 / 2; | |
841 | break; | |
842 | ||
182830a1 CK |
843 | case 0x04000001: /* config extension */ |
844 | case 0x04000002: /* pic control */ | |
845 | case 0x04000005: /* rate control */ | |
846 | case 0x04000007: /* motion estimation */ | |
847 | case 0x04000008: /* rdo */ | |
848 | case 0x04000009: /* vui */ | |
849 | case 0x05000002: /* auxiliary buffer */ | |
4f827785 | 850 | case 0x05000009: /* clock table */ |
d38ceaf9 AD |
851 | break; |
852 | ||
5eeda8a4 AD |
853 | case 0x0500000c: /* hw config */ |
854 | switch (p->adev->asic_type) { | |
855 | #ifdef CONFIG_DRM_AMDGPU_CIK | |
856 | case CHIP_KAVERI: | |
857 | case CHIP_MULLINS: | |
858 | #endif | |
859 | case CHIP_CARRIZO: | |
860 | break; | |
861 | default: | |
862 | r = -EINVAL; | |
863 | goto out; | |
864 | } | |
865 | break; | |
866 | ||
182830a1 | 867 | case 0x03000001: /* encode */ |
f1689ec1 | 868 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9, |
dc78330a | 869 | *size, 0); |
d38ceaf9 | 870 | if (r) |
2f4b9368 | 871 | goto out; |
d38ceaf9 | 872 | |
f1689ec1 | 873 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11, |
dc78330a | 874 | *size / 3, 0); |
d38ceaf9 | 875 | if (r) |
2f4b9368 | 876 | goto out; |
d38ceaf9 AD |
877 | break; |
878 | ||
182830a1 | 879 | case 0x02000001: /* destroy */ |
e5223214 | 880 | destroyed |= 1 << session_idx; |
d38ceaf9 AD |
881 | break; |
882 | ||
182830a1 | 883 | case 0x05000001: /* context buffer */ |
f1689ec1 | 884 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, |
dc78330a | 885 | *size * 2, 0); |
f1689ec1 | 886 | if (r) |
2f4b9368 | 887 | goto out; |
f1689ec1 CK |
888 | break; |
889 | ||
182830a1 | 890 | case 0x05000004: /* video bitstream buffer */ |
f1689ec1 CK |
891 | tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4); |
892 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, | |
dc78330a | 893 | tmp, bs_idx); |
f1689ec1 | 894 | if (r) |
2f4b9368 | 895 | goto out; |
f1689ec1 CK |
896 | break; |
897 | ||
182830a1 | 898 | case 0x05000005: /* feedback buffer */ |
f1689ec1 | 899 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2, |
dc78330a | 900 | 4096, fb_idx); |
d38ceaf9 | 901 | if (r) |
2f4b9368 | 902 | goto out; |
d38ceaf9 AD |
903 | break; |
904 | ||
1eb1547f JZ |
905 | case 0x0500000d: /* MV buffer */ |
906 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, | |
907 | idx + 2, *size, 0); | |
908 | if (r) | |
909 | goto out; | |
910 | ||
911 | r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 8, | |
912 | idx + 7, *size / 12, 0); | |
913 | if (r) | |
914 | goto out; | |
915 | break; | |
916 | ||
d38ceaf9 AD |
917 | default: |
918 | DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); | |
2f4b9368 CK |
919 | r = -EINVAL; |
920 | goto out; | |
d38ceaf9 AD |
921 | } |
922 | ||
f1689ec1 CK |
923 | if (session_idx == -1) { |
924 | DRM_ERROR("no session command at start of IB\n"); | |
2f4b9368 CK |
925 | r = -EINVAL; |
926 | goto out; | |
f1689ec1 CK |
927 | } |
928 | ||
d38ceaf9 AD |
929 | idx += len / 4; |
930 | } | |
931 | ||
e5223214 | 932 | if (allocated & ~created) { |
2f4b9368 CK |
933 | DRM_ERROR("New session without create command!\n"); |
934 | r = -ENOENT; | |
935 | } | |
936 | ||
937 | out: | |
e5223214 CK |
938 | if (!r) { |
939 | /* No error, free all destroyed handle slots */ | |
940 | tmp = destroyed; | |
941 | } else { | |
942 | /* Error during parsing, free all allocated handle slots */ | |
943 | tmp = allocated; | |
d38ceaf9 AD |
944 | } |
945 | ||
e5223214 CK |
946 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) |
947 | if (tmp & (1 << i)) | |
948 | atomic_set(&p->adev->vce.handles[i], 0); | |
949 | ||
2f4b9368 | 950 | return r; |
d38ceaf9 AD |
951 | } |
952 | ||
98614701 CK |
953 | /** |
954 | * amdgpu_vce_cs_parse_vm - parse the command stream in VM mode | |
955 | * | |
956 | * @p: parser context | |
184b762d | 957 | * @ib_idx: indirect buffer to use |
98614701 CK |
958 | */ |
959 | int amdgpu_vce_ring_parse_cs_vm(struct amdgpu_cs_parser *p, uint32_t ib_idx) | |
960 | { | |
961 | struct amdgpu_ib *ib = &p->job->ibs[ib_idx]; | |
962 | int session_idx = -1; | |
963 | uint32_t destroyed = 0; | |
964 | uint32_t created = 0; | |
965 | uint32_t allocated = 0; | |
966 | uint32_t tmp, handle = 0; | |
967 | int i, r = 0, idx = 0; | |
968 | ||
969 | while (idx < ib->length_dw) { | |
970 | uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx); | |
971 | uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1); | |
972 | ||
973 | if ((len < 8) || (len & 3)) { | |
974 | DRM_ERROR("invalid VCE command length (%d)!\n", len); | |
975 | r = -EINVAL; | |
976 | goto out; | |
977 | } | |
978 | ||
979 | switch (cmd) { | |
980 | case 0x00000001: /* session */ | |
981 | handle = amdgpu_get_ib_value(p, ib_idx, idx + 2); | |
982 | session_idx = amdgpu_vce_validate_handle(p, handle, | |
983 | &allocated); | |
984 | if (session_idx < 0) { | |
985 | r = session_idx; | |
986 | goto out; | |
987 | } | |
988 | break; | |
989 | ||
990 | case 0x01000001: /* create */ | |
991 | created |= 1 << session_idx; | |
992 | if (destroyed & (1 << session_idx)) { | |
993 | destroyed &= ~(1 << session_idx); | |
994 | allocated |= 1 << session_idx; | |
995 | ||
996 | } else if (!(allocated & (1 << session_idx))) { | |
997 | DRM_ERROR("Handle already in use!\n"); | |
998 | r = -EINVAL; | |
999 | goto out; | |
1000 | } | |
1001 | ||
1002 | break; | |
1003 | ||
1004 | case 0x02000001: /* destroy */ | |
1005 | destroyed |= 1 << session_idx; | |
1006 | break; | |
1007 | ||
1008 | default: | |
1009 | break; | |
1010 | } | |
1011 | ||
1012 | if (session_idx == -1) { | |
1013 | DRM_ERROR("no session command at start of IB\n"); | |
1014 | r = -EINVAL; | |
1015 | goto out; | |
1016 | } | |
1017 | ||
1018 | idx += len / 4; | |
1019 | } | |
1020 | ||
1021 | if (allocated & ~created) { | |
1022 | DRM_ERROR("New session without create command!\n"); | |
1023 | r = -ENOENT; | |
1024 | } | |
1025 | ||
1026 | out: | |
1027 | if (!r) { | |
1028 | /* No error, free all destroyed handle slots */ | |
1029 | tmp = destroyed; | |
1030 | amdgpu_ib_free(p->adev, ib, NULL); | |
1031 | } else { | |
1032 | /* Error during parsing, free all allocated handle slots */ | |
1033 | tmp = allocated; | |
1034 | } | |
1035 | ||
1036 | for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) | |
1037 | if (tmp & (1 << i)) | |
1038 | atomic_set(&p->adev->vce.handles[i], 0); | |
1039 | ||
1040 | return r; | |
1041 | } | |
1042 | ||
d38ceaf9 AD |
1043 | /** |
1044 | * amdgpu_vce_ring_emit_ib - execute indirect buffer | |
1045 | * | |
1046 | * @ring: engine to use | |
184b762d | 1047 | * @job: job to retrieve vmid from |
d38ceaf9 | 1048 | * @ib: the IB to execute |
184b762d | 1049 | * @flags: unused |
d38ceaf9 AD |
1050 | * |
1051 | */ | |
34955e03 RZ |
1052 | void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, |
1053 | struct amdgpu_job *job, | |
1054 | struct amdgpu_ib *ib, | |
c4c905ec | 1055 | uint32_t flags) |
d38ceaf9 AD |
1056 | { |
1057 | amdgpu_ring_write(ring, VCE_CMD_IB); | |
1058 | amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr)); | |
1059 | amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr)); | |
1060 | amdgpu_ring_write(ring, ib->length_dw); | |
1061 | } | |
1062 | ||
1063 | /** | |
1064 | * amdgpu_vce_ring_emit_fence - add a fence command to the ring | |
1065 | * | |
1066 | * @ring: engine to use | |
184b762d LJ |
1067 | * @addr: address |
1068 | * @seq: sequence number | |
1069 | * @flags: fence related flags | |
d38ceaf9 AD |
1070 | * |
1071 | */ | |
1072 | void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq, | |
890ee23f | 1073 | unsigned flags) |
d38ceaf9 | 1074 | { |
890ee23f | 1075 | WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT); |
d38ceaf9 AD |
1076 | |
1077 | amdgpu_ring_write(ring, VCE_CMD_FENCE); | |
1078 | amdgpu_ring_write(ring, addr); | |
1079 | amdgpu_ring_write(ring, upper_32_bits(addr)); | |
1080 | amdgpu_ring_write(ring, seq); | |
1081 | amdgpu_ring_write(ring, VCE_CMD_TRAP); | |
1082 | amdgpu_ring_write(ring, VCE_CMD_END); | |
1083 | } | |
1084 | ||
1085 | /** | |
1086 | * amdgpu_vce_ring_test_ring - test if VCE ring is working | |
1087 | * | |
1088 | * @ring: the engine to test on | |
1089 | * | |
1090 | */ | |
1091 | int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring) | |
1092 | { | |
1093 | struct amdgpu_device *adev = ring->adev; | |
ce0e22f5 | 1094 | uint32_t rptr; |
d38ceaf9 | 1095 | unsigned i; |
a2f537e0 XY |
1096 | int r, timeout = adev->usec_timeout; |
1097 | ||
a1b9022a | 1098 | /* skip ring test for sriov*/ |
a2f537e0 | 1099 | if (amdgpu_sriov_vf(adev)) |
a1b9022a | 1100 | return 0; |
d38ceaf9 | 1101 | |
a27de35c | 1102 | r = amdgpu_ring_alloc(ring, 16); |
dc9eeff8 | 1103 | if (r) |
d38ceaf9 | 1104 | return r; |
dc9eeff8 | 1105 | |
ce0e22f5 LL |
1106 | rptr = amdgpu_ring_get_rptr(ring); |
1107 | ||
d38ceaf9 | 1108 | amdgpu_ring_write(ring, VCE_CMD_END); |
a27de35c | 1109 | amdgpu_ring_commit(ring); |
d38ceaf9 | 1110 | |
a2f537e0 | 1111 | for (i = 0; i < timeout; i++) { |
d38ceaf9 AD |
1112 | if (amdgpu_ring_get_rptr(ring) != rptr) |
1113 | break; | |
c366be54 | 1114 | udelay(1); |
d38ceaf9 AD |
1115 | } |
1116 | ||
dc9eeff8 | 1117 | if (i >= timeout) |
d38ceaf9 | 1118 | r = -ETIMEDOUT; |
d38ceaf9 AD |
1119 | |
1120 | return r; | |
1121 | } | |
1122 | ||
1123 | /** | |
1124 | * amdgpu_vce_ring_test_ib - test if VCE IBs are working | |
1125 | * | |
1126 | * @ring: the engine to test on | |
184b762d | 1127 | * @timeout: timeout value in jiffies, or MAX_SCHEDULE_TIMEOUT |
d38ceaf9 AD |
1128 | * |
1129 | */ | |
bbec97aa | 1130 | int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring, long timeout) |
d38ceaf9 | 1131 | { |
f54d1867 | 1132 | struct dma_fence *fence = NULL; |
569557e5 | 1133 | struct amdgpu_bo *bo = NULL; |
bbec97aa | 1134 | long r; |
d38ceaf9 | 1135 | |
6f0359ff AD |
1136 | /* skip vce ring1/2 ib test for now, since it's not reliable */ |
1137 | if (ring != &ring->adev->vce.ring[0]) | |
898e50d4 LL |
1138 | return 0; |
1139 | ||
569557e5 AD |
1140 | r = amdgpu_bo_create_reserved(ring->adev, 512, PAGE_SIZE, |
1141 | AMDGPU_GEM_DOMAIN_VRAM, | |
1142 | &bo, NULL, NULL); | |
1143 | if (r) | |
1144 | return r; | |
1145 | ||
1146 | r = amdgpu_vce_get_create_msg(ring, 1, bo, NULL); | |
98079389 | 1147 | if (r) |
d38ceaf9 | 1148 | goto error; |
d38ceaf9 | 1149 | |
9f2ade33 | 1150 | r = amdgpu_vce_get_destroy_msg(ring, 1, true, &fence); |
98079389 | 1151 | if (r) |
d38ceaf9 | 1152 | goto error; |
d38ceaf9 | 1153 | |
f54d1867 | 1154 | r = dma_fence_wait_timeout(fence, false, timeout); |
98079389 | 1155 | if (r == 0) |
bbec97aa | 1156 | r = -ETIMEDOUT; |
98079389 | 1157 | else if (r > 0) |
bbec97aa | 1158 | r = 0; |
98079389 | 1159 | |
d38ceaf9 | 1160 | error: |
f54d1867 | 1161 | dma_fence_put(fence); |
569557e5 | 1162 | amdgpu_bo_unreserve(bo); |
e18d9a2b | 1163 | amdgpu_bo_free_kernel(&bo, NULL, NULL); |
d38ceaf9 AD |
1164 | return r; |
1165 | } |