File: | dev/pci/drm/radeon/radeon_vce.c |
Warning: | line 645, column 8 4th function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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> | |||
30 | ||||
31 | #include <drm/drm.h> | |||
32 | ||||
33 | #include "radeon.h" | |||
34 | #include "radeon_asic.h" | |||
35 | #include "sid.h" | |||
36 | ||||
37 | /* 1 second timeout */ | |||
38 | #define VCE_IDLE_TIMEOUT_MS1000 1000 | |||
39 | ||||
40 | /* Firmware Names */ | |||
41 | #define FIRMWARE_TAHITI"radeon/TAHITI_vce.bin" "radeon/TAHITI_vce.bin" | |||
42 | #define FIRMWARE_BONAIRE"radeon/BONAIRE_vce.bin" "radeon/BONAIRE_vce.bin" | |||
43 | ||||
44 | MODULE_FIRMWARE(FIRMWARE_TAHITI); | |||
45 | MODULE_FIRMWARE(FIRMWARE_BONAIRE); | |||
46 | ||||
47 | static void radeon_vce_idle_work_handler(struct work_struct *work); | |||
48 | ||||
49 | /** | |||
50 | * radeon_vce_init - allocate memory, load vce firmware | |||
51 | * | |||
52 | * @rdev: radeon_device pointer | |||
53 | * | |||
54 | * First step to get VCE online, allocate memory and load the firmware | |||
55 | */ | |||
56 | int radeon_vce_init(struct radeon_device *rdev) | |||
57 | { | |||
58 | static const char *fw_version = "[ATI LIB=VCEFW,"; | |||
59 | static const char *fb_version = "[ATI LIB=VCEFWSTATS,"; | |||
60 | unsigned long size; | |||
61 | const char *fw_name, *c; | |||
62 | uint8_t start, mid, end; | |||
63 | int i, r; | |||
64 | ||||
65 | INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler); | |||
66 | ||||
67 | switch (rdev->family) { | |||
68 | case CHIP_TAHITI: | |||
69 | case CHIP_PITCAIRN: | |||
70 | case CHIP_VERDE: | |||
71 | case CHIP_ARUBA: | |||
72 | fw_name = FIRMWARE_TAHITI"radeon/TAHITI_vce.bin"; | |||
73 | break; | |||
74 | ||||
75 | case CHIP_BONAIRE: | |||
76 | case CHIP_KAVERI: | |||
77 | case CHIP_KABINI: | |||
78 | case CHIP_HAWAII: | |||
79 | case CHIP_MULLINS: | |||
80 | fw_name = FIRMWARE_BONAIRE"radeon/BONAIRE_vce.bin"; | |||
81 | break; | |||
82 | ||||
83 | default: | |||
84 | return -EINVAL22; | |||
85 | } | |||
86 | ||||
87 | r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev); | |||
88 | if (r) { | |||
89 | dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n",printf("drm:pid%d:%s *ERROR* " "radeon_vce: Can't load firmware \"%s\"\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , fw_name ) | |||
90 | fw_name)printf("drm:pid%d:%s *ERROR* " "radeon_vce: Can't load firmware \"%s\"\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , fw_name ); | |||
91 | return r; | |||
92 | } | |||
93 | ||||
94 | /* search for firmware version */ | |||
95 | ||||
96 | size = rdev->vce_fw->size - strlen(fw_version) - 9; | |||
97 | c = rdev->vce_fw->data; | |||
98 | for (;size > 0; --size, ++c) | |||
99 | if (strncmp(c, fw_version, strlen(fw_version)) == 0) | |||
100 | break; | |||
101 | ||||
102 | if (size == 0) | |||
103 | return -EINVAL22; | |||
104 | ||||
105 | c += strlen(fw_version); | |||
106 | #ifdef notyet | |||
107 | if (sscanf(c, "%2hhd.%2hhd.%2hhd]", &start, &mid, &end) != 3) | |||
108 | return -EINVAL22; | |||
109 | #else | |||
110 | if (c[2] != '.') { | |||
111 | printf("%s %s bad start value\n", rdev->self.dv_xname, __func__); | |||
112 | return -EINVAL22; | |||
113 | } | |||
114 | start = (10 * (c[0] - '0')) + (c[1] - '0'); | |||
115 | c += 3; | |||
116 | ||||
117 | if (c[1] != '.') { | |||
118 | printf("%s %s bad mid value\n", rdev->self.dv_xname, __func__); | |||
119 | return -EINVAL22; | |||
120 | } | |||
121 | mid = c[0] - '0'; | |||
122 | c += 2; | |||
123 | ||||
124 | if (c[1] != ']') { | |||
125 | printf("%s %s bad end value\n", rdev->self.dv_xname, __func__); | |||
126 | return -EINVAL22; | |||
127 | } | |||
128 | end = c[0] - '0'; | |||
129 | #endif | |||
130 | ||||
131 | /* search for feedback version */ | |||
132 | ||||
133 | size = rdev->vce_fw->size - strlen(fb_version) - 3; | |||
134 | c = rdev->vce_fw->data; | |||
135 | for (;size > 0; --size, ++c) | |||
136 | if (strncmp(c, fb_version, strlen(fb_version)) == 0) | |||
137 | break; | |||
138 | ||||
139 | if (size == 0) | |||
140 | return -EINVAL22; | |||
141 | ||||
142 | c += strlen(fb_version); | |||
143 | #ifdef notyet | |||
144 | if (sscanf(c, "%2u]", &rdev->vce.fb_version) != 1) | |||
145 | return -EINVAL22; | |||
146 | #else | |||
147 | if (c[2] != ']') { | |||
148 | printf("%s %s bad fb_version value\n", rdev->self.dv_xname, __func__); | |||
149 | return -EINVAL22; | |||
150 | } | |||
151 | rdev->vce.fb_version = (10 * (c[0] - '0')) + (c[1] - '0'); | |||
152 | #endif | |||
153 | ||||
154 | DRM_INFO("Found VCE firmware/feedback version %d.%d.%d / %d!\n",printk("\0016" "[" "drm" "] " "Found VCE firmware/feedback version %d.%d.%d / %d!\n" , start, mid, end, rdev->vce.fb_version) | |||
155 | start, mid, end, rdev->vce.fb_version)printk("\0016" "[" "drm" "] " "Found VCE firmware/feedback version %d.%d.%d / %d!\n" , start, mid, end, rdev->vce.fb_version); | |||
156 | ||||
157 | rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8); | |||
158 | ||||
159 | /* we can only work with this fw version for now */ | |||
160 | if ((rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8))) && | |||
161 | (rdev->vce.fw_version != ((50 << 24) | (0 << 16) | (1 << 8))) && | |||
162 | (rdev->vce.fw_version != ((50 << 24) | (1 << 16) | (2 << 8)))) | |||
163 | return -EINVAL22; | |||
164 | ||||
165 | /* allocate firmware, stack and heap BO */ | |||
166 | ||||
167 | if (rdev->family < CHIP_BONAIRE) | |||
168 | size = vce_v1_0_bo_size(rdev); | |||
169 | else | |||
170 | size = vce_v2_0_bo_size(rdev); | |||
171 | r = radeon_bo_create(rdev, size, PAGE_SIZE(1 << 12), true1, | |||
172 | RADEON_GEM_DOMAIN_VRAM0x4, 0, NULL((void *)0), NULL((void *)0), | |||
173 | &rdev->vce.vcpu_bo); | |||
174 | if (r) { | |||
175 | dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r)printf("drm:pid%d:%s *ERROR* " "(%d) failed to allocate VCE bo\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , r); | |||
176 | return r; | |||
177 | } | |||
178 | ||||
179 | r = radeon_bo_reserve(rdev->vce.vcpu_bo, false0); | |||
180 | if (r) { | |||
181 | radeon_bo_unref(&rdev->vce.vcpu_bo); | |||
182 | dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r)printf("drm:pid%d:%s *ERROR* " "(%d) failed to reserve VCE bo\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , r); | |||
183 | return r; | |||
184 | } | |||
185 | ||||
186 | r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM0x4, | |||
187 | &rdev->vce.gpu_addr); | |||
188 | radeon_bo_unreserve(rdev->vce.vcpu_bo); | |||
189 | if (r) { | |||
190 | radeon_bo_unref(&rdev->vce.vcpu_bo); | |||
191 | dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r)printf("drm:pid%d:%s *ERROR* " "(%d) VCE bo pin failed\n", ({ struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , r); | |||
192 | return r; | |||
193 | } | |||
194 | ||||
195 | for (i = 0; i < RADEON_MAX_VCE_HANDLES16; ++i) { | |||
196 | atomic_set(&rdev->vce.handles[i], 0)({ typeof(*(&rdev->vce.handles[i])) __tmp = ((0)); *(volatile typeof(*(&rdev->vce.handles[i])) *)&(*(&rdev-> vce.handles[i])) = __tmp; __tmp; }); | |||
197 | rdev->vce.filp[i] = NULL((void *)0); | |||
198 | } | |||
199 | ||||
200 | return 0; | |||
201 | } | |||
202 | ||||
203 | /** | |||
204 | * radeon_vce_fini - free memory | |||
205 | * | |||
206 | * @rdev: radeon_device pointer | |||
207 | * | |||
208 | * Last step on VCE teardown, free firmware memory | |||
209 | */ | |||
210 | void radeon_vce_fini(struct radeon_device *rdev) | |||
211 | { | |||
212 | if (rdev->vce.vcpu_bo == NULL((void *)0)) | |||
213 | return; | |||
214 | ||||
215 | radeon_bo_unref(&rdev->vce.vcpu_bo); | |||
216 | ||||
217 | release_firmware(rdev->vce_fw); | |||
218 | } | |||
219 | ||||
220 | /** | |||
221 | * radeon_vce_suspend - unpin VCE fw memory | |||
222 | * | |||
223 | * @rdev: radeon_device pointer | |||
224 | * | |||
225 | */ | |||
226 | int radeon_vce_suspend(struct radeon_device *rdev) | |||
227 | { | |||
228 | int i; | |||
229 | ||||
230 | if (rdev->vce.vcpu_bo == NULL((void *)0)) | |||
231 | return 0; | |||
232 | ||||
233 | for (i = 0; i < RADEON_MAX_VCE_HANDLES16; ++i) | |||
234 | if (atomic_read(&rdev->vce.handles[i])({ typeof(*(&rdev->vce.handles[i])) __tmp = *(volatile typeof(*(&rdev->vce.handles[i])) *)&(*(&rdev-> vce.handles[i])); membar_datadep_consumer(); __tmp; })) | |||
235 | break; | |||
236 | ||||
237 | if (i == RADEON_MAX_VCE_HANDLES16) | |||
238 | return 0; | |||
239 | ||||
240 | /* TODO: suspending running encoding sessions isn't supported */ | |||
241 | return -EINVAL22; | |||
242 | } | |||
243 | ||||
244 | /** | |||
245 | * radeon_vce_resume - pin VCE fw memory | |||
246 | * | |||
247 | * @rdev: radeon_device pointer | |||
248 | * | |||
249 | */ | |||
250 | int radeon_vce_resume(struct radeon_device *rdev) | |||
251 | { | |||
252 | void *cpu_addr; | |||
253 | int r; | |||
254 | ||||
255 | if (rdev->vce.vcpu_bo == NULL((void *)0)) | |||
256 | return -EINVAL22; | |||
257 | ||||
258 | r = radeon_bo_reserve(rdev->vce.vcpu_bo, false0); | |||
259 | if (r) { | |||
260 | dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r)printf("drm:pid%d:%s *ERROR* " "(%d) failed to reserve VCE bo\n" , ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_curproc->p_p->ps_pid, __func__ , r); | |||
261 | return r; | |||
262 | } | |||
263 | ||||
264 | r = radeon_bo_kmap(rdev->vce.vcpu_bo, &cpu_addr); | |||
265 | if (r) { | |||
266 | radeon_bo_unreserve(rdev->vce.vcpu_bo); | |||
267 | dev_err(rdev->dev, "(%d) VCE map failed\n", r)printf("drm:pid%d:%s *ERROR* " "(%d) VCE map failed\n", ({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci ) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci; })->ci_curproc->p_p->ps_pid, __func__ , r); | |||
268 | return r; | |||
269 | } | |||
270 | ||||
271 | memset(cpu_addr, 0, radeon_bo_size(rdev->vce.vcpu_bo))__builtin_memset((cpu_addr), (0), (radeon_bo_size(rdev->vce .vcpu_bo))); | |||
272 | if (rdev->family < CHIP_BONAIRE) | |||
273 | r = vce_v1_0_load_fw(rdev, cpu_addr); | |||
274 | else | |||
275 | memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size)__builtin_memcpy((cpu_addr), (rdev->vce_fw->data), (rdev ->vce_fw->size)); | |||
276 | ||||
277 | radeon_bo_kunmap(rdev->vce.vcpu_bo); | |||
278 | ||||
279 | radeon_bo_unreserve(rdev->vce.vcpu_bo); | |||
280 | ||||
281 | return r; | |||
282 | } | |||
283 | ||||
284 | /** | |||
285 | * radeon_vce_idle_work_handler - power off VCE | |||
286 | * | |||
287 | * @work: pointer to work structure | |||
288 | * | |||
289 | * power of VCE when it's not used any more | |||
290 | */ | |||
291 | static void radeon_vce_idle_work_handler(struct work_struct *work) | |||
292 | { | |||
293 | struct radeon_device *rdev = | |||
294 | container_of(work, struct radeon_device, vce.idle_work.work)({ const __typeof( ((struct radeon_device *)0)->vce.idle_work .work ) *__mptr = (work); (struct radeon_device *)( (char *)__mptr - __builtin_offsetof(struct radeon_device, vce.idle_work.work ) );}); | |||
295 | ||||
296 | if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX6) == 0) && | |||
297 | (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX7) == 0)) { | |||
298 | if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { | |||
299 | radeon_dpm_enable_vce(rdev, false0); | |||
300 | } else { | |||
301 | radeon_set_vce_clocks(rdev, 0, 0)(rdev)->asic->pm.set_vce_clocks((rdev), (0), (0)); | |||
302 | } | |||
303 | } else { | |||
304 | schedule_delayed_work(&rdev->vce.idle_work, | |||
305 | msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)(((uint64_t)(1000)) * hz / 1000)); | |||
306 | } | |||
307 | } | |||
308 | ||||
309 | /** | |||
310 | * radeon_vce_note_usage - power up VCE | |||
311 | * | |||
312 | * @rdev: radeon_device pointer | |||
313 | * | |||
314 | * Make sure VCE is powerd up when we want to use it | |||
315 | */ | |||
316 | void radeon_vce_note_usage(struct radeon_device *rdev) | |||
317 | { | |||
318 | bool_Bool streams_changed = false0; | |||
319 | bool_Bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work); | |||
320 | set_clocks &= schedule_delayed_work(&rdev->vce.idle_work, | |||
321 | msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS)(((uint64_t)(1000)) * hz / 1000)); | |||
322 | ||||
323 | if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { | |||
324 | /* XXX figure out if the streams changed */ | |||
325 | streams_changed = false0; | |||
326 | } | |||
327 | ||||
328 | if (set_clocks || streams_changed) { | |||
329 | if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { | |||
330 | radeon_dpm_enable_vce(rdev, true1); | |||
331 | } else { | |||
332 | radeon_set_vce_clocks(rdev, 53300, 40000)(rdev)->asic->pm.set_vce_clocks((rdev), (53300), (40000 )); | |||
333 | } | |||
334 | } | |||
335 | } | |||
336 | ||||
337 | /** | |||
338 | * radeon_vce_free_handles - free still open VCE handles | |||
339 | * | |||
340 | * @rdev: radeon_device pointer | |||
341 | * @filp: drm file pointer | |||
342 | * | |||
343 | * Close all VCE handles still open by this file pointer | |||
344 | */ | |||
345 | void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) | |||
346 | { | |||
347 | int i, r; | |||
348 | for (i = 0; i < RADEON_MAX_VCE_HANDLES16; ++i) { | |||
349 | uint32_t handle = atomic_read(&rdev->vce.handles[i])({ typeof(*(&rdev->vce.handles[i])) __tmp = *(volatile typeof(*(&rdev->vce.handles[i])) *)&(*(&rdev-> vce.handles[i])); membar_datadep_consumer(); __tmp; }); | |||
350 | if (!handle || rdev->vce.filp[i] != filp) | |||
351 | continue; | |||
352 | ||||
353 | radeon_vce_note_usage(rdev); | |||
354 | ||||
355 | r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX6, | |||
356 | handle, NULL((void *)0)); | |||
357 | if (r) | |||
358 | DRM_ERROR("Error destroying VCE handle (%d)!\n", r)__drm_err("Error destroying VCE handle (%d)!\n", r); | |||
359 | ||||
360 | rdev->vce.filp[i] = NULL((void *)0); | |||
361 | atomic_set(&rdev->vce.handles[i], 0)({ typeof(*(&rdev->vce.handles[i])) __tmp = ((0)); *(volatile typeof(*(&rdev->vce.handles[i])) *)&(*(&rdev-> vce.handles[i])) = __tmp; __tmp; }); | |||
362 | } | |||
363 | } | |||
364 | ||||
365 | /** | |||
366 | * radeon_vce_get_create_msg - generate a VCE create msg | |||
367 | * | |||
368 | * @rdev: radeon_device pointer | |||
369 | * @ring: ring we should submit the msg to | |||
370 | * @handle: VCE session handle to use | |||
371 | * @fence: optional fence to return | |||
372 | * | |||
373 | * Open up a stream for HW test | |||
374 | */ | |||
375 | int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, | |||
376 | uint32_t handle, struct radeon_fence **fence) | |||
377 | { | |||
378 | const unsigned ib_size_dw = 1024; | |||
379 | struct radeon_ib ib; | |||
380 | uint64_t dummy; | |||
381 | int i, r; | |||
382 | ||||
383 | r = radeon_ib_get(rdev, ring, &ib, NULL((void *)0), ib_size_dw * 4); | |||
384 | if (r) { | |||
385 | DRM_ERROR("radeon: failed to get ib (%d).\n", r)__drm_err("radeon: failed to get ib (%d).\n", r); | |||
386 | return r; | |||
387 | } | |||
388 | ||||
389 | dummy = ib.gpu_addr + 1024; | |||
390 | ||||
391 | /* stitch together an VCE create msg */ | |||
392 | ib.length_dw = 0; | |||
393 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c)((__uint32_t)(0x0000000c)); /* len */ | |||
394 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001)((__uint32_t)(0x00000001)); /* session cmd */ | |||
395 | ib.ptr[ib.length_dw++] = cpu_to_le32(handle)((__uint32_t)(handle)); | |||
396 | ||||
397 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000030)((__uint32_t)(0x00000030)); /* len */ | |||
398 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x01000001)((__uint32_t)(0x01000001)); /* create cmd */ | |||
399 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000)((__uint32_t)(0x00000000)); | |||
400 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000042)((__uint32_t)(0x00000042)); | |||
401 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000a)((__uint32_t)(0x0000000a)); | |||
402 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001)((__uint32_t)(0x00000001)); | |||
403 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000080)((__uint32_t)(0x00000080)); | |||
404 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000060)((__uint32_t)(0x00000060)); | |||
405 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100)((__uint32_t)(0x00000100)); | |||
406 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100)((__uint32_t)(0x00000100)); | |||
407 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c)((__uint32_t)(0x0000000c)); | |||
408 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000)((__uint32_t)(0x00000000)); | |||
409 | ||||
410 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014)((__uint32_t)(0x00000014)); /* len */ | |||
411 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005)((__uint32_t)(0x05000005)); /* feedback buffer */ | |||
412 | ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy))((__uint32_t)(((u32)(((dummy) >> 16) >> 16)))); | |||
413 | ib.ptr[ib.length_dw++] = cpu_to_le32(dummy)((__uint32_t)(dummy)); | |||
414 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001)((__uint32_t)(0x00000001)); | |||
415 | ||||
416 | for (i = ib.length_dw; i < ib_size_dw; ++i) | |||
417 | ib.ptr[i] = cpu_to_le32(0x0)((__uint32_t)(0x0)); | |||
418 | ||||
419 | r = radeon_ib_schedule(rdev, &ib, NULL((void *)0), false0); | |||
420 | if (r) | |||
421 | DRM_ERROR("radeon: failed to schedule ib (%d).\n", r)__drm_err("radeon: failed to schedule ib (%d).\n", r); | |||
422 | ||||
423 | ||||
424 | if (fence) | |||
425 | *fence = radeon_fence_ref(ib.fence); | |||
426 | ||||
427 | radeon_ib_free(rdev, &ib); | |||
428 | ||||
429 | return r; | |||
430 | } | |||
431 | ||||
432 | /** | |||
433 | * radeon_vce_get_destroy_msg - generate a VCE destroy msg | |||
434 | * | |||
435 | * @rdev: radeon_device pointer | |||
436 | * @ring: ring we should submit the msg to | |||
437 | * @handle: VCE session handle to use | |||
438 | * @fence: optional fence to return | |||
439 | * | |||
440 | * Close up a stream for HW test or if userspace failed to do so | |||
441 | */ | |||
442 | int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, | |||
443 | uint32_t handle, struct radeon_fence **fence) | |||
444 | { | |||
445 | const unsigned ib_size_dw = 1024; | |||
446 | struct radeon_ib ib; | |||
447 | uint64_t dummy; | |||
448 | int i, r; | |||
449 | ||||
450 | r = radeon_ib_get(rdev, ring, &ib, NULL((void *)0), ib_size_dw * 4); | |||
451 | if (r) { | |||
452 | DRM_ERROR("radeon: failed to get ib (%d).\n", r)__drm_err("radeon: failed to get ib (%d).\n", r); | |||
453 | return r; | |||
454 | } | |||
455 | ||||
456 | dummy = ib.gpu_addr + 1024; | |||
457 | ||||
458 | /* stitch together an VCE destroy msg */ | |||
459 | ib.length_dw = 0; | |||
460 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c)((__uint32_t)(0x0000000c)); /* len */ | |||
461 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001)((__uint32_t)(0x00000001)); /* session cmd */ | |||
462 | ib.ptr[ib.length_dw++] = cpu_to_le32(handle)((__uint32_t)(handle)); | |||
463 | ||||
464 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014)((__uint32_t)(0x00000014)); /* len */ | |||
465 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005)((__uint32_t)(0x05000005)); /* feedback buffer */ | |||
466 | ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy))((__uint32_t)(((u32)(((dummy) >> 16) >> 16)))); | |||
467 | ib.ptr[ib.length_dw++] = cpu_to_le32(dummy)((__uint32_t)(dummy)); | |||
468 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001)((__uint32_t)(0x00000001)); | |||
469 | ||||
470 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008)((__uint32_t)(0x00000008)); /* len */ | |||
471 | ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001)((__uint32_t)(0x02000001)); /* destroy cmd */ | |||
472 | ||||
473 | for (i = ib.length_dw; i < ib_size_dw; ++i) | |||
474 | ib.ptr[i] = cpu_to_le32(0x0)((__uint32_t)(0x0)); | |||
475 | ||||
476 | r = radeon_ib_schedule(rdev, &ib, NULL((void *)0), false0); | |||
477 | if (r) { | |||
478 | DRM_ERROR("radeon: failed to schedule ib (%d).\n", r)__drm_err("radeon: failed to schedule ib (%d).\n", r); | |||
479 | } | |||
480 | ||||
481 | if (fence) | |||
482 | *fence = radeon_fence_ref(ib.fence); | |||
483 | ||||
484 | radeon_ib_free(rdev, &ib); | |||
485 | ||||
486 | return r; | |||
487 | } | |||
488 | ||||
489 | /** | |||
490 | * radeon_vce_cs_reloc - command submission relocation | |||
491 | * | |||
492 | * @p: parser context | |||
493 | * @lo: address of lower dword | |||
494 | * @hi: address of higher dword | |||
495 | * @size: size of checker for relocation buffer | |||
496 | * | |||
497 | * Patch relocation inside command stream with real buffer address | |||
498 | */ | |||
499 | int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi, | |||
500 | unsigned size) | |||
501 | { | |||
502 | struct radeon_cs_chunk *relocs_chunk; | |||
503 | struct radeon_bo_list *reloc; | |||
504 | uint64_t start, end, offset; | |||
505 | unsigned idx; | |||
506 | ||||
507 | relocs_chunk = p->chunk_relocs; | |||
508 | offset = radeon_get_ib_value(p, lo); | |||
509 | idx = radeon_get_ib_value(p, hi); | |||
510 | ||||
511 | if (idx >= relocs_chunk->length_dw) { | |||
512 | DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",__drm_err("Relocs at %d after relocations chunk end %d !\n", idx , relocs_chunk->length_dw) | |||
513 | idx, relocs_chunk->length_dw)__drm_err("Relocs at %d after relocations chunk end %d !\n", idx , relocs_chunk->length_dw); | |||
514 | return -EINVAL22; | |||
515 | } | |||
516 | ||||
517 | reloc = &p->relocs[(idx / 4)]; | |||
518 | start = reloc->gpu_offset; | |||
519 | end = start + radeon_bo_size(reloc->robj); | |||
520 | start += offset; | |||
521 | ||||
522 | p->ib.ptr[lo] = start & 0xFFFFFFFF; | |||
523 | p->ib.ptr[hi] = start >> 32; | |||
524 | ||||
525 | if (end <= start) { | |||
526 | DRM_ERROR("invalid reloc offset %llX!\n", offset)__drm_err("invalid reloc offset %llX!\n", offset); | |||
527 | return -EINVAL22; | |||
528 | } | |||
529 | if ((end - start) < size) { | |||
530 | DRM_ERROR("buffer to small (%d / %d)!\n",__drm_err("buffer to small (%d / %d)!\n", (unsigned)(end - start ), size) | |||
531 | (unsigned)(end - start), size)__drm_err("buffer to small (%d / %d)!\n", (unsigned)(end - start ), size); | |||
532 | return -EINVAL22; | |||
533 | } | |||
534 | ||||
535 | return 0; | |||
536 | } | |||
537 | ||||
538 | /** | |||
539 | * radeon_vce_validate_handle - validate stream handle | |||
540 | * | |||
541 | * @p: parser context | |||
542 | * @handle: handle to validate | |||
543 | * @allocated: allocated a new handle? | |||
544 | * | |||
545 | * Validates the handle and return the found session index or -EINVAL | |||
546 | * we don't have another free session index. | |||
547 | */ | |||
548 | static int radeon_vce_validate_handle(struct radeon_cs_parser *p, | |||
549 | uint32_t handle, bool_Bool *allocated) | |||
550 | { | |||
551 | unsigned i; | |||
552 | ||||
553 | *allocated = false0; | |||
554 | ||||
555 | /* validate the handle */ | |||
556 | for (i = 0; i < RADEON_MAX_VCE_HANDLES16; ++i) { | |||
557 | if (atomic_read(&p->rdev->vce.handles[i])({ typeof(*(&p->rdev->vce.handles[i])) __tmp = *(volatile typeof(*(&p->rdev->vce.handles[i])) *)&(*(& p->rdev->vce.handles[i])); membar_datadep_consumer(); __tmp ; }) == handle) { | |||
558 | if (p->rdev->vce.filp[i] != p->filp) { | |||
559 | DRM_ERROR("VCE handle collision detected!\n")__drm_err("VCE handle collision detected!\n"); | |||
560 | return -EINVAL22; | |||
561 | } | |||
562 | return i; | |||
563 | } | |||
564 | } | |||
565 | ||||
566 | /* handle not found try to alloc a new one */ | |||
567 | for (i = 0; i < RADEON_MAX_VCE_HANDLES16; ++i) { | |||
568 | if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)__sync_val_compare_and_swap(&p->rdev->vce.handles[i ], 0, handle)) { | |||
569 | p->rdev->vce.filp[i] = p->filp; | |||
570 | p->rdev->vce.img_size[i] = 0; | |||
571 | *allocated = true1; | |||
572 | return i; | |||
573 | } | |||
574 | } | |||
575 | ||||
576 | DRM_ERROR("No more free VCE handles!\n")__drm_err("No more free VCE handles!\n"); | |||
577 | return -EINVAL22; | |||
578 | } | |||
579 | ||||
580 | /** | |||
581 | * radeon_vce_cs_parse - parse and validate the command stream | |||
582 | * | |||
583 | * @p: parser context | |||
584 | * | |||
585 | */ | |||
586 | int radeon_vce_cs_parse(struct radeon_cs_parser *p) | |||
587 | { | |||
588 | int session_idx = -1; | |||
589 | bool_Bool destroyed = false0, created = false0, allocated = false0; | |||
590 | uint32_t tmp, handle = 0; | |||
| ||||
591 | uint32_t *size = &tmp; | |||
592 | int i, r = 0; | |||
593 | ||||
594 | while (p->idx < p->chunk_ib->length_dw) { | |||
595 | uint32_t len = radeon_get_ib_value(p, p->idx); | |||
596 | uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); | |||
597 | ||||
598 | if ((len < 8) || (len & 3)) { | |||
599 | DRM_ERROR("invalid VCE command length (%d)!\n", len)__drm_err("invalid VCE command length (%d)!\n", len); | |||
600 | r = -EINVAL22; | |||
601 | goto out; | |||
602 | } | |||
603 | ||||
604 | if (destroyed
| |||
605 | DRM_ERROR("No other command allowed after destroy!\n")__drm_err("No other command allowed after destroy!\n"); | |||
606 | r = -EINVAL22; | |||
607 | goto out; | |||
608 | } | |||
609 | ||||
610 | switch (cmd) { | |||
611 | case 0x00000001: // session | |||
612 | handle = radeon_get_ib_value(p, p->idx + 2); | |||
613 | session_idx = radeon_vce_validate_handle(p, handle, | |||
614 | &allocated); | |||
615 | if (session_idx < 0) | |||
616 | return session_idx; | |||
617 | size = &p->rdev->vce.img_size[session_idx]; | |||
618 | break; | |||
619 | ||||
620 | case 0x00000002: // task info | |||
621 | break; | |||
622 | ||||
623 | case 0x01000001: // create | |||
624 | created = true1; | |||
625 | if (!allocated) { | |||
626 | DRM_ERROR("Handle already in use!\n")__drm_err("Handle already in use!\n"); | |||
627 | r = -EINVAL22; | |||
628 | goto out; | |||
629 | } | |||
630 | ||||
631 | *size = radeon_get_ib_value(p, p->idx + 8) * | |||
632 | radeon_get_ib_value(p, p->idx + 10) * | |||
633 | 8 * 3 / 2; | |||
634 | break; | |||
635 | ||||
636 | case 0x04000001: // config extension | |||
637 | case 0x04000002: // pic control | |||
638 | case 0x04000005: // rate control | |||
639 | case 0x04000007: // motion estimation | |||
640 | case 0x04000008: // rdo | |||
641 | case 0x04000009: // vui | |||
642 | break; | |||
643 | ||||
644 | case 0x03000001: // encode | |||
645 | r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9, | |||
| ||||
646 | *size); | |||
647 | if (r) | |||
648 | goto out; | |||
649 | ||||
650 | r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11, | |||
651 | *size / 3); | |||
652 | if (r) | |||
653 | goto out; | |||
654 | break; | |||
655 | ||||
656 | case 0x02000001: // destroy | |||
657 | destroyed = true1; | |||
658 | break; | |||
659 | ||||
660 | case 0x05000001: // context buffer | |||
661 | r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, | |||
662 | *size * 2); | |||
663 | if (r) | |||
664 | goto out; | |||
665 | break; | |||
666 | ||||
667 | case 0x05000004: // video bitstream buffer | |||
668 | tmp = radeon_get_ib_value(p, p->idx + 4); | |||
669 | r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, | |||
670 | tmp); | |||
671 | if (r) | |||
672 | goto out; | |||
673 | break; | |||
674 | ||||
675 | case 0x05000005: // feedback buffer | |||
676 | r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2, | |||
677 | 4096); | |||
678 | if (r) | |||
679 | goto out; | |||
680 | break; | |||
681 | ||||
682 | default: | |||
683 | DRM_ERROR("invalid VCE command (0x%x)!\n", cmd)__drm_err("invalid VCE command (0x%x)!\n", cmd); | |||
684 | r = -EINVAL22; | |||
685 | goto out; | |||
686 | } | |||
687 | ||||
688 | if (session_idx == -1) { | |||
689 | DRM_ERROR("no session command at start of IB\n")__drm_err("no session command at start of IB\n"); | |||
690 | r = -EINVAL22; | |||
691 | goto out; | |||
692 | } | |||
693 | ||||
694 | p->idx += len / 4; | |||
695 | } | |||
696 | ||||
697 | if (allocated && !created) { | |||
698 | DRM_ERROR("New session without create command!\n")__drm_err("New session without create command!\n"); | |||
699 | r = -ENOENT2; | |||
700 | } | |||
701 | ||||
702 | out: | |||
703 | if ((!r && destroyed) || (r && allocated)) { | |||
704 | /* | |||
705 | * IB contains a destroy msg or we have allocated an | |||
706 | * handle and got an error, anyway free the handle | |||
707 | */ | |||
708 | for (i = 0; i < RADEON_MAX_VCE_HANDLES16; ++i) | |||
709 | atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0)__sync_val_compare_and_swap(&p->rdev->vce.handles[i ], handle, 0); | |||
710 | } | |||
711 | ||||
712 | return r; | |||
713 | } | |||
714 | ||||
715 | /** | |||
716 | * radeon_vce_semaphore_emit - emit a semaphore command | |||
717 | * | |||
718 | * @rdev: radeon_device pointer | |||
719 | * @ring: engine to use | |||
720 | * @semaphore: address of semaphore | |||
721 | * @emit_wait: true=emit wait, false=emit signal | |||
722 | * | |||
723 | */ | |||
724 | bool_Bool radeon_vce_semaphore_emit(struct radeon_device *rdev, | |||
725 | struct radeon_ring *ring, | |||
726 | struct radeon_semaphore *semaphore, | |||
727 | bool_Bool emit_wait) | |||
728 | { | |||
729 | uint64_t addr = semaphore->gpu_addr; | |||
730 | ||||
731 | radeon_ring_write(ring, cpu_to_le32(VCE_CMD_SEMAPHORE)((__uint32_t)(0x00000006))); | |||
732 | radeon_ring_write(ring, cpu_to_le32((addr >> 3) & 0x000FFFFF)((__uint32_t)((addr >> 3) & 0x000FFFFF))); | |||
733 | radeon_ring_write(ring, cpu_to_le32((addr >> 23) & 0x000FFFFF)((__uint32_t)((addr >> 23) & 0x000FFFFF))); | |||
734 | radeon_ring_write(ring, cpu_to_le32(0x01003000 | (emit_wait ? 1 : 0))((__uint32_t)(0x01003000 | (emit_wait ? 1 : 0)))); | |||
735 | if (!emit_wait) | |||
736 | radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)((__uint32_t)(0x00000001))); | |||
737 | ||||
738 | return true1; | |||
739 | } | |||
740 | ||||
741 | /** | |||
742 | * radeon_vce_ib_execute - execute indirect buffer | |||
743 | * | |||
744 | * @rdev: radeon_device pointer | |||
745 | * @ib: the IB to execute | |||
746 | * | |||
747 | */ | |||
748 | void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) | |||
749 | { | |||
750 | struct radeon_ring *ring = &rdev->ring[ib->ring]; | |||
751 | radeon_ring_write(ring, cpu_to_le32(VCE_CMD_IB)((__uint32_t)(0x00000002))); | |||
752 | radeon_ring_write(ring, cpu_to_le32(ib->gpu_addr)((__uint32_t)(ib->gpu_addr))); | |||
753 | radeon_ring_write(ring, cpu_to_le32(upper_32_bits(ib->gpu_addr))((__uint32_t)(((u32)(((ib->gpu_addr) >> 16) >> 16))))); | |||
754 | radeon_ring_write(ring, cpu_to_le32(ib->length_dw)((__uint32_t)(ib->length_dw))); | |||
755 | } | |||
756 | ||||
757 | /** | |||
758 | * radeon_vce_fence_emit - add a fence command to the ring | |||
759 | * | |||
760 | * @rdev: radeon_device pointer | |||
761 | * @fence: the fence | |||
762 | * | |||
763 | */ | |||
764 | void radeon_vce_fence_emit(struct radeon_device *rdev, | |||
765 | struct radeon_fence *fence) | |||
766 | { | |||
767 | struct radeon_ring *ring = &rdev->ring[fence->ring]; | |||
768 | uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr; | |||
769 | ||||
770 | radeon_ring_write(ring, cpu_to_le32(VCE_CMD_FENCE)((__uint32_t)(0x00000003))); | |||
771 | radeon_ring_write(ring, cpu_to_le32(addr)((__uint32_t)(addr))); | |||
772 | radeon_ring_write(ring, cpu_to_le32(upper_32_bits(addr))((__uint32_t)(((u32)(((addr) >> 16) >> 16))))); | |||
773 | radeon_ring_write(ring, cpu_to_le32(fence->seq)((__uint32_t)(fence->seq))); | |||
774 | radeon_ring_write(ring, cpu_to_le32(VCE_CMD_TRAP)((__uint32_t)(0x00000004))); | |||
775 | radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)((__uint32_t)(0x00000001))); | |||
776 | } | |||
777 | ||||
778 | /** | |||
779 | * radeon_vce_ring_test - test if VCE ring is working | |||
780 | * | |||
781 | * @rdev: radeon_device pointer | |||
782 | * @ring: the engine to test on | |||
783 | * | |||
784 | */ | |||
785 | int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) | |||
786 | { | |||
787 | uint32_t rptr = vce_v1_0_get_rptr(rdev, ring); | |||
788 | unsigned i; | |||
789 | int r; | |||
790 | ||||
791 | r = radeon_ring_lock(rdev, ring, 16); | |||
792 | if (r) { | |||
793 | DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n",__drm_err("radeon: vce failed to lock ring %d (%d).\n", ring-> idx, r) | |||
794 | ring->idx, r)__drm_err("radeon: vce failed to lock ring %d (%d).\n", ring-> idx, r); | |||
795 | return r; | |||
796 | } | |||
797 | radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END)((__uint32_t)(0x00000001))); | |||
798 | radeon_ring_unlock_commit(rdev, ring, false0); | |||
799 | ||||
800 | for (i = 0; i < rdev->usec_timeout; i++) { | |||
801 | if (vce_v1_0_get_rptr(rdev, ring) != rptr) | |||
802 | break; | |||
803 | udelay(1); | |||
804 | } | |||
805 | ||||
806 | if (i < rdev->usec_timeout) { | |||
807 | DRM_INFO("ring test on %d succeeded in %d usecs\n",printk("\0016" "[" "drm" "] " "ring test on %d succeeded in %d usecs\n" , ring->idx, i) | |||
808 | ring->idx, i)printk("\0016" "[" "drm" "] " "ring test on %d succeeded in %d usecs\n" , ring->idx, i); | |||
809 | } else { | |||
810 | DRM_ERROR("radeon: ring %d test failed\n",__drm_err("radeon: ring %d test failed\n", ring->idx) | |||
811 | ring->idx)__drm_err("radeon: ring %d test failed\n", ring->idx); | |||
812 | r = -ETIMEDOUT60; | |||
813 | } | |||
814 | ||||
815 | return r; | |||
816 | } | |||
817 | ||||
818 | /** | |||
819 | * radeon_vce_ib_test - test if VCE IBs are working | |||
820 | * | |||
821 | * @rdev: radeon_device pointer | |||
822 | * @ring: the engine to test on | |||
823 | * | |||
824 | */ | |||
825 | int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) | |||
826 | { | |||
827 | struct radeon_fence *fence = NULL((void *)0); | |||
828 | int r; | |||
829 | ||||
830 | r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL((void *)0)); | |||
831 | if (r) { | |||
832 | DRM_ERROR("radeon: failed to get create msg (%d).\n", r)__drm_err("radeon: failed to get create msg (%d).\n", r); | |||
833 | goto error; | |||
834 | } | |||
835 | ||||
836 | r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence); | |||
837 | if (r) { | |||
838 | DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r)__drm_err("radeon: failed to get destroy ib (%d).\n", r); | |||
839 | goto error; | |||
840 | } | |||
841 | ||||
842 | r = radeon_fence_wait_timeout(fence, false0, usecs_to_jiffies((((uint64_t)(1000000)) * hz / 1000000) | |||
843 | RADEON_USEC_IB_TEST_TIMEOUT)(((uint64_t)(1000000)) * hz / 1000000)); | |||
844 | if (r < 0) { | |||
845 | DRM_ERROR("radeon: fence wait failed (%d).\n", r)__drm_err("radeon: fence wait failed (%d).\n", r); | |||
846 | } else if (r == 0) { | |||
847 | DRM_ERROR("radeon: fence wait timed out.\n")__drm_err("radeon: fence wait timed out.\n"); | |||
848 | r = -ETIMEDOUT60; | |||
849 | } else { | |||
850 | DRM_INFO("ib test on ring %d succeeded\n", ring->idx)printk("\0016" "[" "drm" "] " "ib test on ring %d succeeded\n" , ring->idx); | |||
851 | r = 0; | |||
852 | } | |||
853 | error: | |||
854 | radeon_fence_unref(&fence); | |||
855 | return r; | |||
856 | } |