drm/scheduler: Rename cleanup functions v2.
[linux-2.6-block.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_ctx.c
CommitLineData
d38ceaf9
AD
1/*
2 * Copyright 2015 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: monk liu <monk.liu@amd.com>
23 */
24
25#include <drm/drmP.h>
c2636dc5 26#include <drm/drm_auth.h>
d38ceaf9 27#include "amdgpu.h"
52c6a62c 28#include "amdgpu_sched.h"
d38ceaf9 29
c2636dc5 30static int amdgpu_ctx_priority_permit(struct drm_file *filp,
1b1f42d8 31 enum drm_sched_priority priority)
c2636dc5
AR
32{
33 /* NORMAL and below are accessible by everyone */
1b1f42d8 34 if (priority <= DRM_SCHED_PRIORITY_NORMAL)
c2636dc5
AR
35 return 0;
36
37 if (capable(CAP_SYS_NICE))
38 return 0;
39
40 if (drm_is_current_master(filp))
41 return 0;
42
43 return -EACCES;
44}
45
46static int amdgpu_ctx_init(struct amdgpu_device *adev,
1b1f42d8 47 enum drm_sched_priority priority,
c2636dc5
AR
48 struct drm_file *filp,
49 struct amdgpu_ctx *ctx)
d38ceaf9 50{
21c16bf6 51 unsigned i, j;
47f38501 52 int r;
d38ceaf9 53
1b1f42d8 54 if (priority < 0 || priority >= DRM_SCHED_PRIORITY_MAX)
c2636dc5
AR
55 return -EINVAL;
56
57 r = amdgpu_ctx_priority_permit(filp, priority);
58 if (r)
59 return r;
60
23ca0e4e
CZ
61 memset(ctx, 0, sizeof(*ctx));
62 ctx->adev = adev;
63 kref_init(&ctx->refcount);
64 spin_lock_init(&ctx->ring_lock);
a750b47e 65 ctx->fences = kcalloc(amdgpu_sched_jobs * AMDGPU_MAX_RINGS,
f54d1867 66 sizeof(struct dma_fence*), GFP_KERNEL);
37cd0ca2
CZ
67 if (!ctx->fences)
68 return -ENOMEM;
d38ceaf9 69
0ae94444
AG
70 mutex_init(&ctx->lock);
71
37cd0ca2
CZ
72 for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
73 ctx->rings[i].sequence = 1;
a750b47e 74 ctx->rings[i].fences = &ctx->fences[amdgpu_sched_jobs * i];
37cd0ca2 75 }
ce199ad6
NH
76
77 ctx->reset_counter = atomic_read(&adev->gpu_reset_counter);
668ca1b4 78 ctx->reset_counter_query = ctx->reset_counter;
e55f2b64 79 ctx->vram_lost_counter = atomic_read(&adev->vram_lost_counter);
c23be4ae 80 ctx->init_priority = priority;
1b1f42d8 81 ctx->override_priority = DRM_SCHED_PRIORITY_UNSET;
ce199ad6 82
cadf97b1
CZ
83 /* create context entity for each ring */
84 for (i = 0; i < adev->num_rings; i++) {
20874179 85 struct amdgpu_ring *ring = adev->rings[i];
1b1f42d8 86 struct drm_sched_rq *rq;
20874179 87
c2636dc5 88 rq = &ring->sched.sched_rq[priority];
75fbed20
ML
89
90 if (ring == &adev->gfx.kiq.ring)
91 continue;
92
1b1f42d8 93 r = drm_sched_entity_init(&ring->sched, &ctx->rings[i].entity,
8344c53f 94 rq, &ctx->guilty);
cadf97b1 95 if (r)
8ed8147a 96 goto failed;
cadf97b1
CZ
97 }
98
effd924d
AR
99 r = amdgpu_queue_mgr_init(adev, &ctx->queue_mgr);
100 if (r)
101 goto failed;
102
d38ceaf9 103 return 0;
8ed8147a
HR
104
105failed:
106 for (j = 0; j < i; j++)
180fc134 107 drm_sched_entity_destroy(&adev->rings[j]->sched,
8ed8147a
HR
108 &ctx->rings[j].entity);
109 kfree(ctx->fences);
110 ctx->fences = NULL;
111 return r;
d38ceaf9
AD
112}
113
8ee3a52e 114static void amdgpu_ctx_fini(struct kref *ref)
d38ceaf9 115{
8ee3a52e 116 struct amdgpu_ctx *ctx = container_of(ref, struct amdgpu_ctx, refcount);
47f38501
CK
117 struct amdgpu_device *adev = ctx->adev;
118 unsigned i, j;
119
fe295b27
DA
120 if (!adev)
121 return;
122
47f38501 123 for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
37cd0ca2 124 for (j = 0; j < amdgpu_sched_jobs; ++j)
f54d1867 125 dma_fence_put(ctx->rings[i].fences[j]);
37cd0ca2 126 kfree(ctx->fences);
54ddf3a6 127 ctx->fences = NULL;
47f38501 128
effd924d 129 amdgpu_queue_mgr_fini(adev, &ctx->queue_mgr);
0ae94444
AG
130
131 mutex_destroy(&ctx->lock);
8ee3a52e
ED
132
133 kfree(ctx);
47f38501
CK
134}
135
136static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
137 struct amdgpu_fpriv *fpriv,
c2636dc5 138 struct drm_file *filp,
1b1f42d8 139 enum drm_sched_priority priority,
47f38501
CK
140 uint32_t *id)
141{
142 struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
d38ceaf9 143 struct amdgpu_ctx *ctx;
47f38501 144 int r;
d38ceaf9 145
47f38501
CK
146 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
147 if (!ctx)
148 return -ENOMEM;
149
150 mutex_lock(&mgr->lock);
151 r = idr_alloc(&mgr->ctx_handles, ctx, 1, 0, GFP_KERNEL);
152 if (r < 0) {
0147ee0f 153 mutex_unlock(&mgr->lock);
47f38501
CK
154 kfree(ctx);
155 return r;
156 }
c2636dc5 157
47f38501 158 *id = (uint32_t)r;
c2636dc5 159 r = amdgpu_ctx_init(adev, priority, filp, ctx);
c648ed7c
CZ
160 if (r) {
161 idr_remove(&mgr->ctx_handles, *id);
162 *id = 0;
163 kfree(ctx);
164 }
47f38501 165 mutex_unlock(&mgr->lock);
47f38501
CK
166 return r;
167}
168
169static void amdgpu_ctx_do_release(struct kref *ref)
170{
171 struct amdgpu_ctx *ctx;
8ee3a52e 172 u32 i;
47f38501
CK
173
174 ctx = container_of(ref, struct amdgpu_ctx, refcount);
175
20b6b788
AG
176 for (i = 0; i < ctx->adev->num_rings; i++) {
177
178 if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring)
179 continue;
180
180fc134 181 drm_sched_entity_destroy(&ctx->adev->rings[i]->sched,
8ee3a52e 182 &ctx->rings[i].entity);
20b6b788 183 }
47f38501 184
8ee3a52e 185 amdgpu_ctx_fini(ref);
47f38501
CK
186}
187
188static int amdgpu_ctx_free(struct amdgpu_fpriv *fpriv, uint32_t id)
189{
190 struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
191 struct amdgpu_ctx *ctx;
192
193 mutex_lock(&mgr->lock);
d3e709e6
MW
194 ctx = idr_remove(&mgr->ctx_handles, id);
195 if (ctx)
23ca0e4e 196 kref_put(&ctx->refcount, amdgpu_ctx_do_release);
47f38501 197 mutex_unlock(&mgr->lock);
d3e709e6 198 return ctx ? 0 : -EINVAL;
d38ceaf9
AD
199}
200
d94aed5a
MO
201static int amdgpu_ctx_query(struct amdgpu_device *adev,
202 struct amdgpu_fpriv *fpriv, uint32_t id,
203 union drm_amdgpu_ctx_out *out)
d38ceaf9
AD
204{
205 struct amdgpu_ctx *ctx;
23ca0e4e 206 struct amdgpu_ctx_mgr *mgr;
d94aed5a 207 unsigned reset_counter;
d38ceaf9 208
23ca0e4e
CZ
209 if (!fpriv)
210 return -EINVAL;
211
212 mgr = &fpriv->ctx_mgr;
0147ee0f 213 mutex_lock(&mgr->lock);
d38ceaf9 214 ctx = idr_find(&mgr->ctx_handles, id);
d94aed5a 215 if (!ctx) {
0147ee0f 216 mutex_unlock(&mgr->lock);
d94aed5a 217 return -EINVAL;
d38ceaf9 218 }
d94aed5a
MO
219
220 /* TODO: these two are always zero */
0b492a4c
AD
221 out->state.flags = 0x0;
222 out->state.hangs = 0x0;
d94aed5a
MO
223
224 /* determine if a GPU reset has occured since the last call */
225 reset_counter = atomic_read(&adev->gpu_reset_counter);
226 /* TODO: this should ideally return NO, GUILTY, or INNOCENT. */
668ca1b4 227 if (ctx->reset_counter_query == reset_counter)
d94aed5a
MO
228 out->state.reset_status = AMDGPU_CTX_NO_RESET;
229 else
230 out->state.reset_status = AMDGPU_CTX_UNKNOWN_RESET;
668ca1b4 231 ctx->reset_counter_query = reset_counter;
d94aed5a 232
0147ee0f 233 mutex_unlock(&mgr->lock);
d94aed5a 234 return 0;
d38ceaf9
AD
235}
236
bc1b1bf6
ML
237static int amdgpu_ctx_query2(struct amdgpu_device *adev,
238 struct amdgpu_fpriv *fpriv, uint32_t id,
239 union drm_amdgpu_ctx_out *out)
240{
241 struct amdgpu_ctx *ctx;
242 struct amdgpu_ctx_mgr *mgr;
243
244 if (!fpriv)
245 return -EINVAL;
246
247 mgr = &fpriv->ctx_mgr;
248 mutex_lock(&mgr->lock);
249 ctx = idr_find(&mgr->ctx_handles, id);
250 if (!ctx) {
251 mutex_unlock(&mgr->lock);
252 return -EINVAL;
253 }
254
255 out->state.flags = 0x0;
256 out->state.hangs = 0x0;
257
258 if (ctx->reset_counter != atomic_read(&adev->gpu_reset_counter))
259 out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RESET;
260
261 if (ctx->vram_lost_counter != atomic_read(&adev->vram_lost_counter))
262 out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_VRAMLOST;
263
264 if (atomic_read(&ctx->guilty))
265 out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_GUILTY;
266
267 mutex_unlock(&mgr->lock);
268 return 0;
269}
270
d38ceaf9 271int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
d94aed5a 272 struct drm_file *filp)
d38ceaf9
AD
273{
274 int r;
275 uint32_t id;
1b1f42d8 276 enum drm_sched_priority priority;
d38ceaf9
AD
277
278 union drm_amdgpu_ctx *args = data;
279 struct amdgpu_device *adev = dev->dev_private;
280 struct amdgpu_fpriv *fpriv = filp->driver_priv;
281
282 r = 0;
283 id = args->in.ctx_id;
c2636dc5
AR
284 priority = amdgpu_to_sched_priority(args->in.priority);
285
b6d8a439
AR
286 /* For backwards compatibility reasons, we need to accept
287 * ioctls with garbage in the priority field */
1b1f42d8
LS
288 if (priority == DRM_SCHED_PRIORITY_INVALID)
289 priority = DRM_SCHED_PRIORITY_NORMAL;
d38ceaf9
AD
290
291 switch (args->in.op) {
a750b47e 292 case AMDGPU_CTX_OP_ALLOC_CTX:
c2636dc5 293 r = amdgpu_ctx_alloc(adev, fpriv, filp, priority, &id);
a750b47e
CK
294 args->out.alloc.ctx_id = id;
295 break;
296 case AMDGPU_CTX_OP_FREE_CTX:
297 r = amdgpu_ctx_free(fpriv, id);
298 break;
299 case AMDGPU_CTX_OP_QUERY_STATE:
300 r = amdgpu_ctx_query(adev, fpriv, id, &args->out);
301 break;
bc1b1bf6
ML
302 case AMDGPU_CTX_OP_QUERY_STATE2:
303 r = amdgpu_ctx_query2(adev, fpriv, id, &args->out);
304 break;
a750b47e
CK
305 default:
306 return -EINVAL;
d38ceaf9
AD
307 }
308
309 return r;
310}
66b3cf2a
JZ
311
312struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id)
313{
314 struct amdgpu_ctx *ctx;
23ca0e4e
CZ
315 struct amdgpu_ctx_mgr *mgr;
316
317 if (!fpriv)
318 return NULL;
319
320 mgr = &fpriv->ctx_mgr;
66b3cf2a
JZ
321
322 mutex_lock(&mgr->lock);
323 ctx = idr_find(&mgr->ctx_handles, id);
324 if (ctx)
325 kref_get(&ctx->refcount);
326 mutex_unlock(&mgr->lock);
327 return ctx;
328}
329
330int amdgpu_ctx_put(struct amdgpu_ctx *ctx)
331{
66b3cf2a
JZ
332 if (ctx == NULL)
333 return -EINVAL;
334
66b3cf2a 335 kref_put(&ctx->refcount, amdgpu_ctx_do_release);
66b3cf2a
JZ
336 return 0;
337}
21c16bf6 338
eb01abc7
ML
339int amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring,
340 struct dma_fence *fence, uint64_t* handler)
21c16bf6
CK
341{
342 struct amdgpu_ctx_ring *cring = & ctx->rings[ring->idx];
ce882e6d 343 uint64_t seq = cring->sequence;
b43a9a7e 344 unsigned idx = 0;
f54d1867 345 struct dma_fence *other = NULL;
21c16bf6 346
5b011235 347 idx = seq & (amdgpu_sched_jobs - 1);
b43a9a7e 348 other = cring->fences[idx];
0ae94444
AG
349 if (other)
350 BUG_ON(!dma_fence_is_signaled(other));
21c16bf6 351
f54d1867 352 dma_fence_get(fence);
21c16bf6
CK
353
354 spin_lock(&ctx->ring_lock);
355 cring->fences[idx] = fence;
ce882e6d 356 cring->sequence++;
21c16bf6
CK
357 spin_unlock(&ctx->ring_lock);
358
f54d1867 359 dma_fence_put(other);
eb01abc7
ML
360 if (handler)
361 *handler = seq;
21c16bf6 362
eb01abc7 363 return 0;
21c16bf6
CK
364}
365
f54d1867
CW
366struct dma_fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx,
367 struct amdgpu_ring *ring, uint64_t seq)
21c16bf6
CK
368{
369 struct amdgpu_ctx_ring *cring = & ctx->rings[ring->idx];
f54d1867 370 struct dma_fence *fence;
21c16bf6
CK
371
372 spin_lock(&ctx->ring_lock);
b43a9a7e 373
d7b1eeb2
ML
374 if (seq == ~0ull)
375 seq = ctx->rings[ring->idx].sequence - 1;
376
ce882e6d 377 if (seq >= cring->sequence) {
21c16bf6
CK
378 spin_unlock(&ctx->ring_lock);
379 return ERR_PTR(-EINVAL);
380 }
381
b43a9a7e 382
37cd0ca2 383 if (seq + amdgpu_sched_jobs < cring->sequence) {
21c16bf6
CK
384 spin_unlock(&ctx->ring_lock);
385 return NULL;
386 }
387
f54d1867 388 fence = dma_fence_get(cring->fences[seq & (amdgpu_sched_jobs - 1)]);
21c16bf6
CK
389 spin_unlock(&ctx->ring_lock);
390
391 return fence;
392}
efd4ccb5 393
c23be4ae 394void amdgpu_ctx_priority_override(struct amdgpu_ctx *ctx,
1b1f42d8 395 enum drm_sched_priority priority)
c23be4ae
AR
396{
397 int i;
398 struct amdgpu_device *adev = ctx->adev;
1b1f42d8
LS
399 struct drm_sched_rq *rq;
400 struct drm_sched_entity *entity;
c23be4ae 401 struct amdgpu_ring *ring;
1b1f42d8 402 enum drm_sched_priority ctx_prio;
c23be4ae
AR
403
404 ctx->override_priority = priority;
405
1b1f42d8 406 ctx_prio = (ctx->override_priority == DRM_SCHED_PRIORITY_UNSET) ?
c23be4ae
AR
407 ctx->init_priority : ctx->override_priority;
408
409 for (i = 0; i < adev->num_rings; i++) {
410 ring = adev->rings[i];
411 entity = &ctx->rings[i].entity;
412 rq = &ring->sched.sched_rq[ctx_prio];
413
414 if (ring->funcs->type == AMDGPU_RING_TYPE_KIQ)
415 continue;
416
1b1f42d8 417 drm_sched_entity_set_rq(entity, rq);
c23be4ae
AR
418 }
419}
420
0ae94444
AG
421int amdgpu_ctx_wait_prev_fence(struct amdgpu_ctx *ctx, unsigned ring_id)
422{
423 struct amdgpu_ctx_ring *cring = &ctx->rings[ring_id];
424 unsigned idx = cring->sequence & (amdgpu_sched_jobs - 1);
425 struct dma_fence *other = cring->fences[idx];
426
427 if (other) {
428 signed long r;
719a39a1 429 r = dma_fence_wait(other, true);
0ae94444 430 if (r < 0) {
719a39a1
AG
431 if (r != -ERESTARTSYS)
432 DRM_ERROR("Error (%ld) waiting for fence!\n", r);
433
0ae94444
AG
434 return r;
435 }
436 }
437
438 return 0;
439}
440
efd4ccb5
CK
441void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr)
442{
443 mutex_init(&mgr->lock);
444 idr_init(&mgr->ctx_handles);
445}
446
8ee3a52e
ED
447void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr)
448{
449 struct amdgpu_ctx *ctx;
450 struct idr *idp;
451 uint32_t id, i;
48ad368a 452 long max_wait = MAX_WAIT_SCHED_ENTITY_Q_EMPTY;
8ee3a52e
ED
453
454 idp = &mgr->ctx_handles;
455
48ad368a 456 mutex_lock(&mgr->lock);
8ee3a52e
ED
457 idr_for_each_entry(idp, ctx, id) {
458
48ad368a
AG
459 if (!ctx->adev) {
460 mutex_unlock(&mgr->lock);
8ee3a52e 461 return;
48ad368a 462 }
8ee3a52e 463
20b6b788
AG
464 for (i = 0; i < ctx->adev->num_rings; i++) {
465
466 if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring)
467 continue;
468
180fc134 469 max_wait = drm_sched_entity_flush(&ctx->adev->rings[i]->sched,
48ad368a 470 &ctx->rings[i].entity, max_wait);
20b6b788 471 }
8ee3a52e 472 }
48ad368a 473 mutex_unlock(&mgr->lock);
8ee3a52e
ED
474}
475
476void amdgpu_ctx_mgr_entity_cleanup(struct amdgpu_ctx_mgr *mgr)
477{
478 struct amdgpu_ctx *ctx;
479 struct idr *idp;
480 uint32_t id, i;
481
482 idp = &mgr->ctx_handles;
483
484 idr_for_each_entry(idp, ctx, id) {
485
486 if (!ctx->adev)
487 return;
488
20b6b788
AG
489 for (i = 0; i < ctx->adev->num_rings; i++) {
490
491 if (ctx->adev->rings[i] == &ctx->adev->gfx.kiq.ring)
492 continue;
493
8ee3a52e 494 if (kref_read(&ctx->refcount) == 1)
180fc134 495 drm_sched_entity_fini(&ctx->adev->rings[i]->sched,
8ee3a52e
ED
496 &ctx->rings[i].entity);
497 else
498 DRM_ERROR("ctx %p is still alive\n", ctx);
20b6b788 499 }
8ee3a52e
ED
500 }
501}
502
efd4ccb5
CK
503void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr)
504{
505 struct amdgpu_ctx *ctx;
506 struct idr *idp;
507 uint32_t id;
508
8ee3a52e
ED
509 amdgpu_ctx_mgr_entity_cleanup(mgr);
510
efd4ccb5
CK
511 idp = &mgr->ctx_handles;
512
513 idr_for_each_entry(idp, ctx, id) {
8ee3a52e 514 if (kref_put(&ctx->refcount, amdgpu_ctx_fini) != 1)
efd4ccb5
CK
515 DRM_ERROR("ctx %p is still alive\n", ctx);
516 }
517
518 idr_destroy(&mgr->ctx_handles);
519 mutex_destroy(&mgr->lock);
520}