blob: a6fee511aab554d98909d027dd5826ec31438003 [file] [log] [blame]
Alex Deucherd38ceaf2015-04-20 16:55:21 -04001/*
2 * Copyright 2014 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 */
26/*
27 * Authors:
28 * Christian König <christian.koenig@amd.com>
29 */
30
31#include <drm/drmP.h>
32#include "amdgpu.h"
33#include "amdgpu_trace.h"
34
Christian Königf91b3a62015-08-20 14:47:40 +080035struct amdgpu_sync_entry {
36 struct hlist_node node;
37 struct fence *fence;
38};
39
Alex Deucherd38ceaf2015-04-20 16:55:21 -040040/**
41 * amdgpu_sync_create - zero init sync object
42 *
43 * @sync: sync object to initialize
44 *
45 * Just clear the sync object for now.
46 */
47void amdgpu_sync_create(struct amdgpu_sync *sync)
48{
49 unsigned i;
50
Alex Deucherd38ceaf2015-04-20 16:55:21 -040051 for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
52 sync->sync_to[i] = NULL;
53
Christian Königf91b3a62015-08-20 14:47:40 +080054 hash_init(sync->fences);
Alex Deucherd38ceaf2015-04-20 16:55:21 -040055 sync->last_vm_update = NULL;
56}
57
Chunming Zhou3c623382015-08-20 18:33:59 +080058static bool amdgpu_sync_same_dev(struct amdgpu_device *adev, struct fence *f)
59{
60 struct amdgpu_fence *a_fence = to_amdgpu_fence(f);
61 struct amd_sched_fence *s_fence = to_amd_sched_fence(f);
62
63 if (a_fence)
64 return a_fence->ring->adev == adev;
Christian König4f839a22015-09-08 20:22:31 +020065
66 if (s_fence) {
67 struct amdgpu_ring *ring;
68
69 ring = container_of(s_fence->sched, struct amdgpu_ring, sched);
70 return ring->adev == adev;
71 }
72
Chunming Zhou3c623382015-08-20 18:33:59 +080073 return false;
74}
75
76static bool amdgpu_sync_test_owner(struct fence *f, void *owner)
77{
78 struct amdgpu_fence *a_fence = to_amdgpu_fence(f);
79 struct amd_sched_fence *s_fence = to_amd_sched_fence(f);
80 if (s_fence)
81 return s_fence->owner == owner;
82 if (a_fence)
83 return a_fence->owner == owner;
84 return false;
85}
86
Christian König24233862015-10-22 10:53:16 +020087static void amdgpu_sync_keep_later(struct fence **keep, struct fence *fence)
88{
89 if (*keep && fence_is_later(*keep, fence))
90 return;
91
92 fence_put(*keep);
93 *keep = fence_get(fence);
94}
95
Alex Deucherd38ceaf2015-04-20 16:55:21 -040096/**
Christian König91e1a522015-07-06 22:06:40 +020097 * amdgpu_sync_fence - remember to sync to this fence
Alex Deucherd38ceaf2015-04-20 16:55:21 -040098 *
99 * @sync: sync object to add fence to
100 * @fence: fence to sync to
101 *
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400102 */
Christian König91e1a522015-07-06 22:06:40 +0200103int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync,
104 struct fence *f)
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400105{
Christian Königf91b3a62015-08-20 14:47:40 +0800106 struct amdgpu_sync_entry *e;
Christian König91e1a522015-07-06 22:06:40 +0200107 struct amdgpu_fence *fence;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400108
Christian König91e1a522015-07-06 22:06:40 +0200109 if (!f)
110 return 0;
111
Chunming Zhou3c623382015-08-20 18:33:59 +0800112 if (amdgpu_sync_same_dev(adev, f) &&
Christian König24233862015-10-22 10:53:16 +0200113 amdgpu_sync_test_owner(f, AMDGPU_FENCE_OWNER_VM))
114 amdgpu_sync_keep_later(&sync->last_vm_update, f);
Chunming Zhou3c623382015-08-20 18:33:59 +0800115
Christian König91e1a522015-07-06 22:06:40 +0200116 fence = to_amdgpu_fence(f);
Christian Königf91b3a62015-08-20 14:47:40 +0800117 if (!fence || fence->ring->adev != adev) {
118 hash_for_each_possible(sync->fences, e, node, f->context) {
Christian Königf91b3a62015-08-20 14:47:40 +0800119 if (unlikely(e->fence->context != f->context))
120 continue;
Christian König24233862015-10-22 10:53:16 +0200121
122 amdgpu_sync_keep_later(&e->fence, f);
Christian Königf91b3a62015-08-20 14:47:40 +0800123 return 0;
124 }
125
126 e = kmalloc(sizeof(struct amdgpu_sync_entry), GFP_KERNEL);
127 if (!e)
128 return -ENOMEM;
129
130 hash_add(sync->fences, &e->node, f->context);
131 e->fence = fence_get(f);
132 return 0;
133 }
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400134
Christian König16545c32015-10-22 15:04:50 +0200135 amdgpu_sync_keep_later(&sync->sync_to[fence->ring->idx], f);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400136
Christian König91e1a522015-07-06 22:06:40 +0200137 return 0;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400138}
139
Chunming Zhou423a9482015-08-24 16:59:54 +0800140static void *amdgpu_sync_get_owner(struct fence *f)
141{
142 struct amdgpu_fence *a_fence = to_amdgpu_fence(f);
143 struct amd_sched_fence *s_fence = to_amd_sched_fence(f);
144
145 if (s_fence)
146 return s_fence->owner;
147 else if (a_fence)
148 return a_fence->owner;
149 return AMDGPU_FENCE_OWNER_UNDEFINED;
150}
151
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400152/**
Chunming Zhou2f4b9402016-01-15 11:05:21 +0800153 * amdgpu_sync_resv - sync to a reservation object
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400154 *
155 * @sync: sync object to add fences from reservation object to
156 * @resv: reservation object with embedded fence
157 * @shared: true if we should only sync to the exclusive fence
158 *
Chunming Zhou2f4b9402016-01-15 11:05:21 +0800159 * Sync to the fence
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400160 */
161int amdgpu_sync_resv(struct amdgpu_device *adev,
162 struct amdgpu_sync *sync,
163 struct reservation_object *resv,
164 void *owner)
165{
166 struct reservation_object_list *flist;
167 struct fence *f;
Chunming Zhou423a9482015-08-24 16:59:54 +0800168 void *fence_owner;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400169 unsigned i;
170 int r = 0;
171
Jammy Zhou4b095302015-05-12 23:17:19 +0800172 if (resv == NULL)
173 return -EINVAL;
174
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400175 /* always sync to the exclusive fence */
176 f = reservation_object_get_excl(resv);
Christian König91e1a522015-07-06 22:06:40 +0200177 r = amdgpu_sync_fence(adev, sync, f);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400178
179 flist = reservation_object_get_list(resv);
180 if (!flist || r)
181 return r;
182
183 for (i = 0; i < flist->shared_count; ++i) {
184 f = rcu_dereference_protected(flist->shared[i],
185 reservation_object_held(resv));
Chunming Zhou423a9482015-08-24 16:59:54 +0800186 if (amdgpu_sync_same_dev(adev, f)) {
Christian König1d3897e2015-07-27 15:40:35 +0200187 /* VM updates are only interesting
188 * for other VM updates and moves.
189 */
Chunming Zhou423a9482015-08-24 16:59:54 +0800190 fence_owner = amdgpu_sync_get_owner(f);
Christian König7a91d6c2015-10-27 17:28:24 +0100191 if ((owner != AMDGPU_FENCE_OWNER_UNDEFINED) &&
192 (fence_owner != AMDGPU_FENCE_OWNER_UNDEFINED) &&
Christian König1d3897e2015-07-27 15:40:35 +0200193 ((owner == AMDGPU_FENCE_OWNER_VM) !=
Chunming Zhou423a9482015-08-24 16:59:54 +0800194 (fence_owner == AMDGPU_FENCE_OWNER_VM)))
Christian König91e1a522015-07-06 22:06:40 +0200195 continue;
196
Christian König1d3897e2015-07-27 15:40:35 +0200197 /* Ignore fence from the same owner as
198 * long as it isn't undefined.
199 */
200 if (owner != AMDGPU_FENCE_OWNER_UNDEFINED &&
Chunming Zhou423a9482015-08-24 16:59:54 +0800201 fence_owner == owner)
Christian König1d3897e2015-07-27 15:40:35 +0200202 continue;
203 }
204
Christian König91e1a522015-07-06 22:06:40 +0200205 r = amdgpu_sync_fence(adev, sync, f);
206 if (r)
207 break;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400208 }
209 return r;
210}
211
Christian Könige61235d2015-08-25 11:05:36 +0200212struct fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync)
213{
214 struct amdgpu_sync_entry *e;
215 struct hlist_node *tmp;
216 struct fence *f;
217 int i;
218
219 hash_for_each_safe(sync->fences, i, tmp, e, node) {
220
221 f = e->fence;
222
223 hash_del(&e->node);
224 kfree(e);
225
226 if (!fence_is_signaled(f))
227 return f;
228
229 fence_put(f);
230 }
231 return NULL;
232}
233
Christian Königf91b3a62015-08-20 14:47:40 +0800234int amdgpu_sync_wait(struct amdgpu_sync *sync)
235{
236 struct amdgpu_sync_entry *e;
237 struct hlist_node *tmp;
238 int i, r;
239
240 hash_for_each_safe(sync->fences, i, tmp, e, node) {
241 r = fence_wait(e->fence, false);
242 if (r)
243 return r;
244
245 hash_del(&e->node);
246 fence_put(e->fence);
247 kfree(e);
248 }
Christian König3daea9e3d2015-09-05 11:12:27 +0200249
Christian König3daea9e3d2015-09-05 11:12:27 +0200250 for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
Christian König16545c32015-10-22 15:04:50 +0200251 struct fence *fence = sync->sync_to[i];
Christian König3daea9e3d2015-09-05 11:12:27 +0200252 if (!fence)
253 continue;
254
Christian König16545c32015-10-22 15:04:50 +0200255 r = fence_wait(fence, false);
Christian König3daea9e3d2015-09-05 11:12:27 +0200256 if (r)
257 return r;
258 }
259
Christian Königf91b3a62015-08-20 14:47:40 +0800260 return 0;
261}
262
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400263/**
264 * amdgpu_sync_rings - sync ring to all registered fences
265 *
266 * @sync: sync object to use
267 * @ring: ring that needs sync
268 *
269 * Ensure that all registered fences are signaled before letting
270 * the ring continue. The caller must hold the ring lock.
271 */
272int amdgpu_sync_rings(struct amdgpu_sync *sync,
273 struct amdgpu_ring *ring)
274{
275 struct amdgpu_device *adev = ring->adev;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400276 int i, r;
277
278 for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400279 struct amdgpu_ring *other = adev->rings[i];
Christian König16545c32015-10-22 15:04:50 +0200280 struct amdgpu_fence *fence;
281
282 if (!sync->sync_to[i])
283 continue;
284
285 fence = to_amdgpu_fence(sync->sync_to[i]);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400286
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400287 /* prevent GPU deadlocks */
288 if (!other->ready) {
289 dev_err(adev->dev, "Syncing to a disabled ring!");
290 return -EINVAL;
291 }
292
Chunming Zhou2f4b9402016-01-15 11:05:21 +0800293 if (amdgpu_enable_scheduler) {
Chunming Zhou888c9e32016-01-13 12:55:18 +0800294 r = fence_wait(sync->sync_to[i], true);
Christian König680513c2015-09-10 15:03:50 +0200295 if (r)
296 return r;
297 continue;
298 }
299
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400300 }
301
302 return 0;
303}
304
305/**
306 * amdgpu_sync_free - free the sync object
307 *
308 * @adev: amdgpu_device pointer
309 * @sync: sync object to use
310 * @fence: fence to use for the free
311 *
Chunming Zhou2f4b9402016-01-15 11:05:21 +0800312 * Free the sync object.
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400313 */
314void amdgpu_sync_free(struct amdgpu_device *adev,
315 struct amdgpu_sync *sync,
Chunming Zhou4ce98912015-08-19 16:41:19 +0800316 struct fence *fence)
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400317{
Christian Königf91b3a62015-08-20 14:47:40 +0800318 struct amdgpu_sync_entry *e;
319 struct hlist_node *tmp;
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400320 unsigned i;
321
Christian Königf91b3a62015-08-20 14:47:40 +0800322 hash_for_each_safe(sync->fences, i, tmp, e, node) {
323 hash_del(&e->node);
324 fence_put(e->fence);
325 kfree(e);
326 }
327
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400328 for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
Christian König16545c32015-10-22 15:04:50 +0200329 fence_put(sync->sync_to[i]);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400330
Chunming Zhou3c623382015-08-20 18:33:59 +0800331 fence_put(sync->last_vm_update);
Alex Deucherd38ceaf2015-04-20 16:55:21 -0400332}