]> Git Repo - linux.git/blob - drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
drm/amdgpu: add context entity init
[linux.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_vce.c
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 <[email protected]>
26  */
27
28 #include <linux/firmware.h>
29 #include <linux/module.h>
30 #include <drm/drmP.h>
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 */
39 #define VCE_IDLE_TIMEOUT_MS     1000
40
41 /* Firmware Names */
42 #ifdef CONFIG_DRM_AMDGPU_CIK
43 #define FIRMWARE_BONAIRE        "radeon/bonaire_vce.bin"
44 #define FIRMWARE_KABINI         "radeon/kabini_vce.bin"
45 #define FIRMWARE_KAVERI         "radeon/kaveri_vce.bin"
46 #define FIRMWARE_HAWAII         "radeon/hawaii_vce.bin"
47 #define FIRMWARE_MULLINS        "radeon/mullins_vce.bin"
48 #endif
49 #define FIRMWARE_TONGA          "amdgpu/tonga_vce.bin"
50 #define FIRMWARE_CARRIZO        "amdgpu/carrizo_vce.bin"
51 #define FIRMWARE_FIJI           "amdgpu/fiji_vce.bin"
52
53 #ifdef CONFIG_DRM_AMDGPU_CIK
54 MODULE_FIRMWARE(FIRMWARE_BONAIRE);
55 MODULE_FIRMWARE(FIRMWARE_KABINI);
56 MODULE_FIRMWARE(FIRMWARE_KAVERI);
57 MODULE_FIRMWARE(FIRMWARE_HAWAII);
58 MODULE_FIRMWARE(FIRMWARE_MULLINS);
59 #endif
60 MODULE_FIRMWARE(FIRMWARE_TONGA);
61 MODULE_FIRMWARE(FIRMWARE_CARRIZO);
62 MODULE_FIRMWARE(FIRMWARE_FIJI);
63
64 static void amdgpu_vce_idle_work_handler(struct work_struct *work);
65
66 /**
67  * amdgpu_vce_init - allocate memory, load vce firmware
68  *
69  * @adev: amdgpu_device pointer
70  *
71  * First step to get VCE online, allocate memory and load the firmware
72  */
73 int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size)
74 {
75         const char *fw_name;
76         const struct common_firmware_header *hdr;
77         unsigned ucode_version, version_major, version_minor, binary_id;
78         int i, r;
79
80         INIT_DELAYED_WORK(&adev->vce.idle_work, amdgpu_vce_idle_work_handler);
81
82         switch (adev->asic_type) {
83 #ifdef CONFIG_DRM_AMDGPU_CIK
84         case CHIP_BONAIRE:
85                 fw_name = FIRMWARE_BONAIRE;
86                 break;
87         case CHIP_KAVERI:
88                 fw_name = FIRMWARE_KAVERI;
89                 break;
90         case CHIP_KABINI:
91                 fw_name = FIRMWARE_KABINI;
92                 break;
93         case CHIP_HAWAII:
94                 fw_name = FIRMWARE_HAWAII;
95                 break;
96         case CHIP_MULLINS:
97                 fw_name = FIRMWARE_MULLINS;
98                 break;
99 #endif
100         case CHIP_TONGA:
101                 fw_name = FIRMWARE_TONGA;
102                 break;
103         case CHIP_CARRIZO:
104                 fw_name = FIRMWARE_CARRIZO;
105                 break;
106         case CHIP_FIJI:
107                 fw_name = FIRMWARE_FIJI;
108                 break;
109
110         default:
111                 return -EINVAL;
112         }
113
114         r = request_firmware(&adev->vce.fw, fw_name, adev->dev);
115         if (r) {
116                 dev_err(adev->dev, "amdgpu_vce: Can't load firmware \"%s\"\n",
117                         fw_name);
118                 return r;
119         }
120
121         r = amdgpu_ucode_validate(adev->vce.fw);
122         if (r) {
123                 dev_err(adev->dev, "amdgpu_vce: Can't validate firmware \"%s\"\n",
124                         fw_name);
125                 release_firmware(adev->vce.fw);
126                 adev->vce.fw = NULL;
127                 return r;
128         }
129
130         hdr = (const struct common_firmware_header *)adev->vce.fw->data;
131
132         ucode_version = le32_to_cpu(hdr->ucode_version);
133         version_major = (ucode_version >> 20) & 0xfff;
134         version_minor = (ucode_version >> 8) & 0xfff;
135         binary_id = ucode_version & 0xff;
136         DRM_INFO("Found VCE firmware Version: %hhd.%hhd Binary ID: %hhd\n",
137                 version_major, version_minor, binary_id);
138         adev->vce.fw_version = ((version_major << 24) | (version_minor << 16) |
139                                 (binary_id << 8));
140
141         /* allocate firmware, stack and heap BO */
142
143         r = amdgpu_bo_create(adev, size, PAGE_SIZE, true,
144                              AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->vce.vcpu_bo);
145         if (r) {
146                 dev_err(adev->dev, "(%d) failed to allocate VCE bo\n", r);
147                 return r;
148         }
149
150         r = amdgpu_bo_reserve(adev->vce.vcpu_bo, false);
151         if (r) {
152                 amdgpu_bo_unref(&adev->vce.vcpu_bo);
153                 dev_err(adev->dev, "(%d) failed to reserve VCE bo\n", r);
154                 return r;
155         }
156
157         r = amdgpu_bo_pin(adev->vce.vcpu_bo, AMDGPU_GEM_DOMAIN_VRAM,
158                           &adev->vce.gpu_addr);
159         amdgpu_bo_unreserve(adev->vce.vcpu_bo);
160         if (r) {
161                 amdgpu_bo_unref(&adev->vce.vcpu_bo);
162                 dev_err(adev->dev, "(%d) VCE bo pin failed\n", r);
163                 return r;
164         }
165
166         for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
167                 atomic_set(&adev->vce.handles[i], 0);
168                 adev->vce.filp[i] = NULL;
169         }
170
171         return 0;
172 }
173
174 /**
175  * amdgpu_vce_fini - free memory
176  *
177  * @adev: amdgpu_device pointer
178  *
179  * Last step on VCE teardown, free firmware memory
180  */
181 int amdgpu_vce_sw_fini(struct amdgpu_device *adev)
182 {
183         if (adev->vce.vcpu_bo == NULL)
184                 return 0;
185
186         amdgpu_bo_unref(&adev->vce.vcpu_bo);
187
188         amdgpu_ring_fini(&adev->vce.ring[0]);
189         amdgpu_ring_fini(&adev->vce.ring[1]);
190
191         release_firmware(adev->vce.fw);
192
193         return 0;
194 }
195
196 /**
197  * amdgpu_vce_suspend - unpin VCE fw memory
198  *
199  * @adev: amdgpu_device pointer
200  *
201  */
202 int amdgpu_vce_suspend(struct amdgpu_device *adev)
203 {
204         int i;
205
206         if (adev->vce.vcpu_bo == NULL)
207                 return 0;
208
209         for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
210                 if (atomic_read(&adev->vce.handles[i]))
211                         break;
212
213         if (i == AMDGPU_MAX_VCE_HANDLES)
214                 return 0;
215
216         /* TODO: suspending running encoding sessions isn't supported */
217         return -EINVAL;
218 }
219
220 /**
221  * amdgpu_vce_resume - pin VCE fw memory
222  *
223  * @adev: amdgpu_device pointer
224  *
225  */
226 int amdgpu_vce_resume(struct amdgpu_device *adev)
227 {
228         void *cpu_addr;
229         const struct common_firmware_header *hdr;
230         unsigned offset;
231         int r;
232
233         if (adev->vce.vcpu_bo == NULL)
234                 return -EINVAL;
235
236         r = amdgpu_bo_reserve(adev->vce.vcpu_bo, false);
237         if (r) {
238                 dev_err(adev->dev, "(%d) failed to reserve VCE bo\n", r);
239                 return r;
240         }
241
242         r = amdgpu_bo_kmap(adev->vce.vcpu_bo, &cpu_addr);
243         if (r) {
244                 amdgpu_bo_unreserve(adev->vce.vcpu_bo);
245                 dev_err(adev->dev, "(%d) VCE map failed\n", r);
246                 return r;
247         }
248
249         hdr = (const struct common_firmware_header *)adev->vce.fw->data;
250         offset = le32_to_cpu(hdr->ucode_array_offset_bytes);
251         memcpy(cpu_addr, (adev->vce.fw->data) + offset,
252                 (adev->vce.fw->size) - offset);
253
254         amdgpu_bo_kunmap(adev->vce.vcpu_bo);
255
256         amdgpu_bo_unreserve(adev->vce.vcpu_bo);
257
258         return 0;
259 }
260
261 /**
262  * amdgpu_vce_idle_work_handler - power off VCE
263  *
264  * @work: pointer to work structure
265  *
266  * power of VCE when it's not used any more
267  */
268 static void amdgpu_vce_idle_work_handler(struct work_struct *work)
269 {
270         struct amdgpu_device *adev =
271                 container_of(work, struct amdgpu_device, vce.idle_work.work);
272
273         if ((amdgpu_fence_count_emitted(&adev->vce.ring[0]) == 0) &&
274             (amdgpu_fence_count_emitted(&adev->vce.ring[1]) == 0)) {
275                 if (adev->pm.dpm_enabled) {
276                         amdgpu_dpm_enable_vce(adev, false);
277                 } else {
278                         amdgpu_asic_set_vce_clocks(adev, 0, 0);
279                 }
280         } else {
281                 schedule_delayed_work(&adev->vce.idle_work,
282                                       msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
283         }
284 }
285
286 /**
287  * amdgpu_vce_note_usage - power up VCE
288  *
289  * @adev: amdgpu_device pointer
290  *
291  * Make sure VCE is powerd up when we want to use it
292  */
293 static void amdgpu_vce_note_usage(struct amdgpu_device *adev)
294 {
295         bool streams_changed = false;
296         bool set_clocks = !cancel_delayed_work_sync(&adev->vce.idle_work);
297         set_clocks &= schedule_delayed_work(&adev->vce.idle_work,
298                                             msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
299
300         if (adev->pm.dpm_enabled) {
301                 /* XXX figure out if the streams changed */
302                 streams_changed = false;
303         }
304
305         if (set_clocks || streams_changed) {
306                 if (adev->pm.dpm_enabled) {
307                         amdgpu_dpm_enable_vce(adev, true);
308                 } else {
309                         amdgpu_asic_set_vce_clocks(adev, 53300, 40000);
310                 }
311         }
312 }
313
314 /**
315  * amdgpu_vce_free_handles - free still open VCE handles
316  *
317  * @adev: amdgpu_device pointer
318  * @filp: drm file pointer
319  *
320  * Close all VCE handles still open by this file pointer
321  */
322 void amdgpu_vce_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
323 {
324         struct amdgpu_ring *ring = &adev->vce.ring[0];
325         int i, r;
326         for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
327                 uint32_t handle = atomic_read(&adev->vce.handles[i]);
328                 if (!handle || adev->vce.filp[i] != filp)
329                         continue;
330
331                 amdgpu_vce_note_usage(adev);
332
333                 r = amdgpu_vce_get_destroy_msg(ring, handle, NULL);
334                 if (r)
335                         DRM_ERROR("Error destroying VCE handle (%d)!\n", r);
336
337                 adev->vce.filp[i] = NULL;
338                 atomic_set(&adev->vce.handles[i], 0);
339         }
340 }
341
342 /**
343  * amdgpu_vce_get_create_msg - generate a VCE create msg
344  *
345  * @adev: amdgpu_device pointer
346  * @ring: ring we should submit the msg to
347  * @handle: VCE session handle to use
348  * @fence: optional fence to return
349  *
350  * Open up a stream for HW test
351  */
352 int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
353                               struct amdgpu_fence **fence)
354 {
355         const unsigned ib_size_dw = 1024;
356         struct amdgpu_ib ib;
357         uint64_t dummy;
358         int i, r;
359
360         r = amdgpu_ib_get(ring, NULL, ib_size_dw * 4, &ib);
361         if (r) {
362                 DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
363                 return r;
364         }
365
366         dummy = ib.gpu_addr + 1024;
367
368         /* stitch together an VCE create msg */
369         ib.length_dw = 0;
370         ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
371         ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
372         ib.ptr[ib.length_dw++] = handle;
373
374         ib.ptr[ib.length_dw++] = 0x00000030; /* len */
375         ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */
376         ib.ptr[ib.length_dw++] = 0x00000000;
377         ib.ptr[ib.length_dw++] = 0x00000042;
378         ib.ptr[ib.length_dw++] = 0x0000000a;
379         ib.ptr[ib.length_dw++] = 0x00000001;
380         ib.ptr[ib.length_dw++] = 0x00000080;
381         ib.ptr[ib.length_dw++] = 0x00000060;
382         ib.ptr[ib.length_dw++] = 0x00000100;
383         ib.ptr[ib.length_dw++] = 0x00000100;
384         ib.ptr[ib.length_dw++] = 0x0000000c;
385         ib.ptr[ib.length_dw++] = 0x00000000;
386
387         ib.ptr[ib.length_dw++] = 0x00000014; /* len */
388         ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
389         ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
390         ib.ptr[ib.length_dw++] = dummy;
391         ib.ptr[ib.length_dw++] = 0x00000001;
392
393         for (i = ib.length_dw; i < ib_size_dw; ++i)
394                 ib.ptr[i] = 0x0;
395
396         r = amdgpu_ib_schedule(ring->adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
397         if (r) {
398                 DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
399         }
400
401         if (fence)
402                 *fence = amdgpu_fence_ref(ib.fence);
403
404         amdgpu_ib_free(ring->adev, &ib);
405
406         return r;
407 }
408
409 /**
410  * amdgpu_vce_get_destroy_msg - generate a VCE destroy msg
411  *
412  * @adev: amdgpu_device pointer
413  * @ring: ring we should submit the msg to
414  * @handle: VCE session handle to use
415  * @fence: optional fence to return
416  *
417  * Close up a stream for HW test or if userspace failed to do so
418  */
419 int amdgpu_vce_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle,
420                                struct amdgpu_fence **fence)
421 {
422         const unsigned ib_size_dw = 1024;
423         struct amdgpu_ib ib;
424         uint64_t dummy;
425         int i, r;
426
427         r = amdgpu_ib_get(ring, NULL, ib_size_dw * 4, &ib);
428         if (r) {
429                 DRM_ERROR("amdgpu: failed to get ib (%d).\n", r);
430                 return r;
431         }
432
433         dummy = ib.gpu_addr + 1024;
434
435         /* stitch together an VCE destroy msg */
436         ib.length_dw = 0;
437         ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
438         ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
439         ib.ptr[ib.length_dw++] = handle;
440
441         ib.ptr[ib.length_dw++] = 0x00000014; /* len */
442         ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
443         ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
444         ib.ptr[ib.length_dw++] = dummy;
445         ib.ptr[ib.length_dw++] = 0x00000001;
446
447         ib.ptr[ib.length_dw++] = 0x00000008; /* len */
448         ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */
449
450         for (i = ib.length_dw; i < ib_size_dw; ++i)
451                 ib.ptr[i] = 0x0;
452
453         r = amdgpu_ib_schedule(ring->adev, 1, &ib, AMDGPU_FENCE_OWNER_UNDEFINED);
454         if (r) {
455                 DRM_ERROR("amdgpu: failed to schedule ib (%d).\n", r);
456         }
457
458         if (fence)
459                 *fence = amdgpu_fence_ref(ib.fence);
460
461         amdgpu_ib_free(ring->adev, &ib);
462
463         return r;
464 }
465
466 /**
467  * amdgpu_vce_cs_reloc - command submission relocation
468  *
469  * @p: parser context
470  * @lo: address of lower dword
471  * @hi: address of higher dword
472  * @size: minimum size
473  *
474  * Patch relocation inside command stream with real buffer address
475  */
476 static int amdgpu_vce_cs_reloc(struct amdgpu_cs_parser *p, uint32_t ib_idx,
477                                int lo, int hi, unsigned size, uint32_t index)
478 {
479         struct amdgpu_bo_va_mapping *mapping;
480         struct amdgpu_ib *ib = &p->ibs[ib_idx];
481         struct amdgpu_bo *bo;
482         uint64_t addr;
483
484         if (index == 0xffffffff)
485                 index = 0;
486
487         addr = ((uint64_t)amdgpu_get_ib_value(p, ib_idx, lo)) |
488                ((uint64_t)amdgpu_get_ib_value(p, ib_idx, hi)) << 32;
489         addr += ((uint64_t)size) * ((uint64_t)index);
490
491         mapping = amdgpu_cs_find_mapping(p, addr, &bo);
492         if (mapping == NULL) {
493                 DRM_ERROR("Can't find BO for addr 0x%010Lx %d %d %d %d\n",
494                           addr, lo, hi, size, index);
495                 return -EINVAL;
496         }
497
498         if ((addr + (uint64_t)size) >
499             ((uint64_t)mapping->it.last + 1) * AMDGPU_GPU_PAGE_SIZE) {
500                 DRM_ERROR("BO to small for addr 0x%010Lx %d %d\n",
501                           addr, lo, hi);
502                 return -EINVAL;
503         }
504
505         addr -= ((uint64_t)mapping->it.start) * AMDGPU_GPU_PAGE_SIZE;
506         addr += amdgpu_bo_gpu_offset(bo);
507         addr -= ((uint64_t)size) * ((uint64_t)index);
508
509         ib->ptr[lo] = addr & 0xFFFFFFFF;
510         ib->ptr[hi] = addr >> 32;
511
512         return 0;
513 }
514
515 /**
516  * amdgpu_vce_validate_handle - validate stream handle
517  *
518  * @p: parser context
519  * @handle: handle to validate
520  * @allocated: allocated a new handle?
521  *
522  * Validates the handle and return the found session index or -EINVAL
523  * we we don't have another free session index.
524  */
525 static int amdgpu_vce_validate_handle(struct amdgpu_cs_parser *p,
526                                       uint32_t handle, bool *allocated)
527 {
528         unsigned i;
529
530         *allocated = false;
531
532         /* validate the handle */
533         for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
534                 if (atomic_read(&p->adev->vce.handles[i]) == handle) {
535                         if (p->adev->vce.filp[i] != p->filp) {
536                                 DRM_ERROR("VCE handle collision detected!\n");
537                                 return -EINVAL;
538                         }
539                         return i;
540                 }
541         }
542
543         /* handle not found try to alloc a new one */
544         for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i) {
545                 if (!atomic_cmpxchg(&p->adev->vce.handles[i], 0, handle)) {
546                         p->adev->vce.filp[i] = p->filp;
547                         p->adev->vce.img_size[i] = 0;
548                         *allocated = true;
549                         return i;
550                 }
551         }
552
553         DRM_ERROR("No more free VCE handles!\n");
554         return -EINVAL;
555 }
556
557 /**
558  * amdgpu_vce_cs_parse - parse and validate the command stream
559  *
560  * @p: parser context
561  *
562  */
563 int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, uint32_t ib_idx)
564 {
565         struct amdgpu_ib *ib = &p->ibs[ib_idx];
566         unsigned fb_idx = 0, bs_idx = 0;
567         int session_idx = -1;
568         bool destroyed = false;
569         bool created = false;
570         bool allocated = false;
571         uint32_t tmp, handle = 0;
572         uint32_t *size = &tmp;
573         int i, r = 0, idx = 0;
574
575         amdgpu_vce_note_usage(p->adev);
576
577         while (idx < ib->length_dw) {
578                 uint32_t len = amdgpu_get_ib_value(p, ib_idx, idx);
579                 uint32_t cmd = amdgpu_get_ib_value(p, ib_idx, idx + 1);
580
581                 if ((len < 8) || (len & 3)) {
582                         DRM_ERROR("invalid VCE command length (%d)!\n", len);
583                         r = -EINVAL;
584                         goto out;
585                 }
586
587                 if (destroyed) {
588                         DRM_ERROR("No other command allowed after destroy!\n");
589                         r = -EINVAL;
590                         goto out;
591                 }
592
593                 switch (cmd) {
594                 case 0x00000001: // session
595                         handle = amdgpu_get_ib_value(p, ib_idx, idx + 2);
596                         session_idx = amdgpu_vce_validate_handle(p, handle,
597                                                                  &allocated);
598                         if (session_idx < 0)
599                                 return session_idx;
600                         size = &p->adev->vce.img_size[session_idx];
601                         break;
602
603                 case 0x00000002: // task info
604                         fb_idx = amdgpu_get_ib_value(p, ib_idx, idx + 6);
605                         bs_idx = amdgpu_get_ib_value(p, ib_idx, idx + 7);
606                         break;
607
608                 case 0x01000001: // create
609                         created = true;
610                         if (!allocated) {
611                                 DRM_ERROR("Handle already in use!\n");
612                                 r = -EINVAL;
613                                 goto out;
614                         }
615
616                         *size = amdgpu_get_ib_value(p, ib_idx, idx + 8) *
617                                 amdgpu_get_ib_value(p, ib_idx, idx + 10) *
618                                 8 * 3 / 2;
619                         break;
620
621                 case 0x04000001: // config extension
622                 case 0x04000002: // pic control
623                 case 0x04000005: // rate control
624                 case 0x04000007: // motion estimation
625                 case 0x04000008: // rdo
626                 case 0x04000009: // vui
627                 case 0x05000002: // auxiliary buffer
628                         break;
629
630                 case 0x03000001: // encode
631                         r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 10, idx + 9,
632                                                 *size, 0);
633                         if (r)
634                                 goto out;
635
636                         r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 12, idx + 11,
637                                                 *size / 3, 0);
638                         if (r)
639                                 goto out;
640                         break;
641
642                 case 0x02000001: // destroy
643                         destroyed = true;
644                         break;
645
646                 case 0x05000001: // context buffer
647                         r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
648                                                 *size * 2, 0);
649                         if (r)
650                                 goto out;
651                         break;
652
653                 case 0x05000004: // video bitstream buffer
654                         tmp = amdgpu_get_ib_value(p, ib_idx, idx + 4);
655                         r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
656                                                 tmp, bs_idx);
657                         if (r)
658                                 goto out;
659                         break;
660
661                 case 0x05000005: // feedback buffer
662                         r = amdgpu_vce_cs_reloc(p, ib_idx, idx + 3, idx + 2,
663                                                 4096, fb_idx);
664                         if (r)
665                                 goto out;
666                         break;
667
668                 default:
669                         DRM_ERROR("invalid VCE command (0x%x)!\n", cmd);
670                         r = -EINVAL;
671                         goto out;
672                 }
673
674                 if (session_idx == -1) {
675                         DRM_ERROR("no session command at start of IB\n");
676                         r = -EINVAL;
677                         goto out;
678                 }
679
680                 idx += len / 4;
681         }
682
683         if (allocated && !created) {
684                 DRM_ERROR("New session without create command!\n");
685                 r = -ENOENT;
686         }
687
688 out:
689         if ((!r && destroyed) || (r && allocated)) {
690                 /*
691                  * IB contains a destroy msg or we have allocated an
692                  * handle and got an error, anyway free the handle
693                  */
694                 for (i = 0; i < AMDGPU_MAX_VCE_HANDLES; ++i)
695                         atomic_cmpxchg(&p->adev->vce.handles[i], handle, 0);
696         }
697
698         return r;
699 }
700
701 /**
702  * amdgpu_vce_ring_emit_semaphore - emit a semaphore command
703  *
704  * @ring: engine to use
705  * @semaphore: address of semaphore
706  * @emit_wait: true=emit wait, false=emit signal
707  *
708  */
709 bool amdgpu_vce_ring_emit_semaphore(struct amdgpu_ring *ring,
710                                     struct amdgpu_semaphore *semaphore,
711                                     bool emit_wait)
712 {
713         uint64_t addr = semaphore->gpu_addr;
714
715         amdgpu_ring_write(ring, VCE_CMD_SEMAPHORE);
716         amdgpu_ring_write(ring, (addr >> 3) & 0x000FFFFF);
717         amdgpu_ring_write(ring, (addr >> 23) & 0x000FFFFF);
718         amdgpu_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0));
719         if (!emit_wait)
720                 amdgpu_ring_write(ring, VCE_CMD_END);
721
722         return true;
723 }
724
725 /**
726  * amdgpu_vce_ring_emit_ib - execute indirect buffer
727  *
728  * @ring: engine to use
729  * @ib: the IB to execute
730  *
731  */
732 void amdgpu_vce_ring_emit_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib)
733 {
734         amdgpu_ring_write(ring, VCE_CMD_IB);
735         amdgpu_ring_write(ring, lower_32_bits(ib->gpu_addr));
736         amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
737         amdgpu_ring_write(ring, ib->length_dw);
738 }
739
740 /**
741  * amdgpu_vce_ring_emit_fence - add a fence command to the ring
742  *
743  * @ring: engine to use
744  * @fence: the fence
745  *
746  */
747 void amdgpu_vce_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 seq,
748                                 unsigned flags)
749 {
750         WARN_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
751
752         amdgpu_ring_write(ring, VCE_CMD_FENCE);
753         amdgpu_ring_write(ring, addr);
754         amdgpu_ring_write(ring, upper_32_bits(addr));
755         amdgpu_ring_write(ring, seq);
756         amdgpu_ring_write(ring, VCE_CMD_TRAP);
757         amdgpu_ring_write(ring, VCE_CMD_END);
758 }
759
760 /**
761  * amdgpu_vce_ring_test_ring - test if VCE ring is working
762  *
763  * @ring: the engine to test on
764  *
765  */
766 int amdgpu_vce_ring_test_ring(struct amdgpu_ring *ring)
767 {
768         struct amdgpu_device *adev = ring->adev;
769         uint32_t rptr = amdgpu_ring_get_rptr(ring);
770         unsigned i;
771         int r;
772
773         r = amdgpu_ring_lock(ring, 16);
774         if (r) {
775                 DRM_ERROR("amdgpu: vce failed to lock ring %d (%d).\n",
776                           ring->idx, r);
777                 return r;
778         }
779         amdgpu_ring_write(ring, VCE_CMD_END);
780         amdgpu_ring_unlock_commit(ring);
781
782         for (i = 0; i < adev->usec_timeout; i++) {
783                 if (amdgpu_ring_get_rptr(ring) != rptr)
784                         break;
785                 DRM_UDELAY(1);
786         }
787
788         if (i < adev->usec_timeout) {
789                 DRM_INFO("ring test on %d succeeded in %d usecs\n",
790                          ring->idx, i);
791         } else {
792                 DRM_ERROR("amdgpu: ring %d test failed\n",
793                           ring->idx);
794                 r = -ETIMEDOUT;
795         }
796
797         return r;
798 }
799
800 /**
801  * amdgpu_vce_ring_test_ib - test if VCE IBs are working
802  *
803  * @ring: the engine to test on
804  *
805  */
806 int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring)
807 {
808         struct amdgpu_fence *fence = NULL;
809         int r;
810
811         r = amdgpu_vce_get_create_msg(ring, 1, NULL);
812         if (r) {
813                 DRM_ERROR("amdgpu: failed to get create msg (%d).\n", r);
814                 goto error;
815         }
816
817         r = amdgpu_vce_get_destroy_msg(ring, 1, &fence);
818         if (r) {
819                 DRM_ERROR("amdgpu: failed to get destroy ib (%d).\n", r);
820                 goto error;
821         }
822
823         r = amdgpu_fence_wait(fence, false);
824         if (r) {
825                 DRM_ERROR("amdgpu: fence wait failed (%d).\n", r);
826         } else {
827                 DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
828         }
829 error:
830         amdgpu_fence_unref(&fence);
831         return r;
832 }
This page took 0.080872 seconds and 4 git commands to generate.