]> Git Repo - linux.git/blob - drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
drm/amdgpu: introduce AMDGPU_CTX_PRIORITY_UNSET
[linux.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_ctx.c
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 <[email protected]>
23  */
24
25 #include <drm/drmP.h>
26 #include <drm/drm_auth.h>
27 #include "amdgpu.h"
28
29 static int amdgpu_ctx_priority_permit(struct drm_file *filp,
30                                       enum amd_sched_priority priority)
31 {
32         /* NORMAL and below are accessible by everyone */
33         if (priority <= AMD_SCHED_PRIORITY_NORMAL)
34                 return 0;
35
36         if (capable(CAP_SYS_NICE))
37                 return 0;
38
39         if (drm_is_current_master(filp))
40                 return 0;
41
42         return -EACCES;
43 }
44
45 static int amdgpu_ctx_init(struct amdgpu_device *adev,
46                            enum amd_sched_priority priority,
47                            struct drm_file *filp,
48                            struct amdgpu_ctx *ctx)
49 {
50         unsigned i, j;
51         int r;
52
53         if (priority < 0 || priority >= AMD_SCHED_PRIORITY_MAX)
54                 return -EINVAL;
55
56         r = amdgpu_ctx_priority_permit(filp, priority);
57         if (r)
58                 return r;
59
60         memset(ctx, 0, sizeof(*ctx));
61         ctx->adev = adev;
62         kref_init(&ctx->refcount);
63         spin_lock_init(&ctx->ring_lock);
64         ctx->fences = kcalloc(amdgpu_sched_jobs * AMDGPU_MAX_RINGS,
65                               sizeof(struct dma_fence*), GFP_KERNEL);
66         if (!ctx->fences)
67                 return -ENOMEM;
68
69         for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
70                 ctx->rings[i].sequence = 1;
71                 ctx->rings[i].fences = &ctx->fences[amdgpu_sched_jobs * i];
72         }
73
74         ctx->reset_counter = atomic_read(&adev->gpu_reset_counter);
75
76         /* create context entity for each ring */
77         for (i = 0; i < adev->num_rings; i++) {
78                 struct amdgpu_ring *ring = adev->rings[i];
79                 struct amd_sched_rq *rq;
80
81                 rq = &ring->sched.sched_rq[priority];
82
83                 if (ring == &adev->gfx.kiq.ring)
84                         continue;
85
86                 r = amd_sched_entity_init(&ring->sched, &ctx->rings[i].entity,
87                                           rq, amdgpu_sched_jobs);
88                 if (r)
89                         goto failed;
90         }
91
92         r = amdgpu_queue_mgr_init(adev, &ctx->queue_mgr);
93         if (r)
94                 goto failed;
95
96         return 0;
97
98 failed:
99         for (j = 0; j < i; j++)
100                 amd_sched_entity_fini(&adev->rings[j]->sched,
101                                       &ctx->rings[j].entity);
102         kfree(ctx->fences);
103         ctx->fences = NULL;
104         return r;
105 }
106
107 static void amdgpu_ctx_fini(struct amdgpu_ctx *ctx)
108 {
109         struct amdgpu_device *adev = ctx->adev;
110         unsigned i, j;
111
112         if (!adev)
113                 return;
114
115         for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
116                 for (j = 0; j < amdgpu_sched_jobs; ++j)
117                         dma_fence_put(ctx->rings[i].fences[j]);
118         kfree(ctx->fences);
119         ctx->fences = NULL;
120
121         for (i = 0; i < adev->num_rings; i++)
122                 amd_sched_entity_fini(&adev->rings[i]->sched,
123                                       &ctx->rings[i].entity);
124
125         amdgpu_queue_mgr_fini(adev, &ctx->queue_mgr);
126 }
127
128 static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
129                             struct amdgpu_fpriv *fpriv,
130                             struct drm_file *filp,
131                             enum amd_sched_priority priority,
132                             uint32_t *id)
133 {
134         struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
135         struct amdgpu_ctx *ctx;
136         int r;
137
138         ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
139         if (!ctx)
140                 return -ENOMEM;
141
142         mutex_lock(&mgr->lock);
143         r = idr_alloc(&mgr->ctx_handles, ctx, 1, 0, GFP_KERNEL);
144         if (r < 0) {
145                 mutex_unlock(&mgr->lock);
146                 kfree(ctx);
147                 return r;
148         }
149
150         *id = (uint32_t)r;
151         r = amdgpu_ctx_init(adev, priority, filp, ctx);
152         if (r) {
153                 idr_remove(&mgr->ctx_handles, *id);
154                 *id = 0;
155                 kfree(ctx);
156         }
157         mutex_unlock(&mgr->lock);
158         return r;
159 }
160
161 static void amdgpu_ctx_do_release(struct kref *ref)
162 {
163         struct amdgpu_ctx *ctx;
164
165         ctx = container_of(ref, struct amdgpu_ctx, refcount);
166
167         amdgpu_ctx_fini(ctx);
168
169         kfree(ctx);
170 }
171
172 static int amdgpu_ctx_free(struct amdgpu_fpriv *fpriv, uint32_t id)
173 {
174         struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
175         struct amdgpu_ctx *ctx;
176
177         mutex_lock(&mgr->lock);
178         ctx = idr_remove(&mgr->ctx_handles, id);
179         if (ctx)
180                 kref_put(&ctx->refcount, amdgpu_ctx_do_release);
181         mutex_unlock(&mgr->lock);
182         return ctx ? 0 : -EINVAL;
183 }
184
185 static int amdgpu_ctx_query(struct amdgpu_device *adev,
186                             struct amdgpu_fpriv *fpriv, uint32_t id,
187                             union drm_amdgpu_ctx_out *out)
188 {
189         struct amdgpu_ctx *ctx;
190         struct amdgpu_ctx_mgr *mgr;
191         unsigned reset_counter;
192
193         if (!fpriv)
194                 return -EINVAL;
195
196         mgr = &fpriv->ctx_mgr;
197         mutex_lock(&mgr->lock);
198         ctx = idr_find(&mgr->ctx_handles, id);
199         if (!ctx) {
200                 mutex_unlock(&mgr->lock);
201                 return -EINVAL;
202         }
203
204         /* TODO: these two are always zero */
205         out->state.flags = 0x0;
206         out->state.hangs = 0x0;
207
208         /* determine if a GPU reset has occured since the last call */
209         reset_counter = atomic_read(&adev->gpu_reset_counter);
210         /* TODO: this should ideally return NO, GUILTY, or INNOCENT. */
211         if (ctx->reset_counter == reset_counter)
212                 out->state.reset_status = AMDGPU_CTX_NO_RESET;
213         else
214                 out->state.reset_status = AMDGPU_CTX_UNKNOWN_RESET;
215         ctx->reset_counter = reset_counter;
216
217         mutex_unlock(&mgr->lock);
218         return 0;
219 }
220
221 static enum amd_sched_priority amdgpu_to_sched_priority(int amdgpu_priority)
222 {
223         switch (amdgpu_priority) {
224         case AMDGPU_CTX_PRIORITY_HIGH_HW:
225                 return AMD_SCHED_PRIORITY_HIGH_HW;
226         case AMDGPU_CTX_PRIORITY_HIGH_SW:
227                 return AMD_SCHED_PRIORITY_HIGH_SW;
228         case AMDGPU_CTX_PRIORITY_NORMAL:
229                 return AMD_SCHED_PRIORITY_NORMAL;
230         case AMDGPU_CTX_PRIORITY_LOW_SW:
231         case AMDGPU_CTX_PRIORITY_LOW_HW:
232                 return AMD_SCHED_PRIORITY_LOW;
233         case AMDGPU_CTX_PRIORITY_UNSET:
234                 return AMD_SCHED_PRIORITY_UNSET;
235         default:
236                 WARN(1, "Invalid context priority %d\n", amdgpu_priority);
237                 return AMD_SCHED_PRIORITY_INVALID;
238         }
239 }
240
241 int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
242                      struct drm_file *filp)
243 {
244         int r;
245         uint32_t id;
246         enum amd_sched_priority priority;
247
248         union drm_amdgpu_ctx *args = data;
249         struct amdgpu_device *adev = dev->dev_private;
250         struct amdgpu_fpriv *fpriv = filp->driver_priv;
251
252         r = 0;
253         id = args->in.ctx_id;
254         priority = amdgpu_to_sched_priority(args->in.priority);
255
256         /* For backwards compatibility reasons, we need to accept
257          * ioctls with garbage in the priority field */
258         if (priority == AMD_SCHED_PRIORITY_INVALID)
259                 priority = AMD_SCHED_PRIORITY_NORMAL;
260
261         switch (args->in.op) {
262         case AMDGPU_CTX_OP_ALLOC_CTX:
263                 r = amdgpu_ctx_alloc(adev, fpriv, filp, priority, &id);
264                 args->out.alloc.ctx_id = id;
265                 break;
266         case AMDGPU_CTX_OP_FREE_CTX:
267                 r = amdgpu_ctx_free(fpriv, id);
268                 break;
269         case AMDGPU_CTX_OP_QUERY_STATE:
270                 r = amdgpu_ctx_query(adev, fpriv, id, &args->out);
271                 break;
272         default:
273                 return -EINVAL;
274         }
275
276         return r;
277 }
278
279 struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id)
280 {
281         struct amdgpu_ctx *ctx;
282         struct amdgpu_ctx_mgr *mgr;
283
284         if (!fpriv)
285                 return NULL;
286
287         mgr = &fpriv->ctx_mgr;
288
289         mutex_lock(&mgr->lock);
290         ctx = idr_find(&mgr->ctx_handles, id);
291         if (ctx)
292                 kref_get(&ctx->refcount);
293         mutex_unlock(&mgr->lock);
294         return ctx;
295 }
296
297 int amdgpu_ctx_put(struct amdgpu_ctx *ctx)
298 {
299         if (ctx == NULL)
300                 return -EINVAL;
301
302         kref_put(&ctx->refcount, amdgpu_ctx_do_release);
303         return 0;
304 }
305
306 int amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring,
307                               struct dma_fence *fence, uint64_t* handler)
308 {
309         struct amdgpu_ctx_ring *cring = & ctx->rings[ring->idx];
310         uint64_t seq = cring->sequence;
311         unsigned idx = 0;
312         struct dma_fence *other = NULL;
313
314         idx = seq & (amdgpu_sched_jobs - 1);
315         other = cring->fences[idx];
316         if (other) {
317                 signed long r;
318                 r = dma_fence_wait_timeout(other, true, MAX_SCHEDULE_TIMEOUT);
319                 if (r < 0)
320                         return r;
321         }
322
323         dma_fence_get(fence);
324
325         spin_lock(&ctx->ring_lock);
326         cring->fences[idx] = fence;
327         cring->sequence++;
328         spin_unlock(&ctx->ring_lock);
329
330         dma_fence_put(other);
331         if (handler)
332                 *handler = seq;
333
334         return 0;
335 }
336
337 struct dma_fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx,
338                                        struct amdgpu_ring *ring, uint64_t seq)
339 {
340         struct amdgpu_ctx_ring *cring = & ctx->rings[ring->idx];
341         struct dma_fence *fence;
342
343         spin_lock(&ctx->ring_lock);
344
345         if (seq == ~0ull)
346                 seq = ctx->rings[ring->idx].sequence - 1;
347
348         if (seq >= cring->sequence) {
349                 spin_unlock(&ctx->ring_lock);
350                 return ERR_PTR(-EINVAL);
351         }
352
353
354         if (seq + amdgpu_sched_jobs < cring->sequence) {
355                 spin_unlock(&ctx->ring_lock);
356                 return NULL;
357         }
358
359         fence = dma_fence_get(cring->fences[seq & (amdgpu_sched_jobs - 1)]);
360         spin_unlock(&ctx->ring_lock);
361
362         return fence;
363 }
364
365 void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr)
366 {
367         mutex_init(&mgr->lock);
368         idr_init(&mgr->ctx_handles);
369 }
370
371 void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr)
372 {
373         struct amdgpu_ctx *ctx;
374         struct idr *idp;
375         uint32_t id;
376
377         idp = &mgr->ctx_handles;
378
379         idr_for_each_entry(idp, ctx, id) {
380                 if (kref_put(&ctx->refcount, amdgpu_ctx_do_release) != 1)
381                         DRM_ERROR("ctx %p is still alive\n", ctx);
382         }
383
384         idr_destroy(&mgr->ctx_handles);
385         mutex_destroy(&mgr->lock);
386 }
This page took 0.061226 seconds and 4 git commands to generate.