drm/amdgpu: add core driver (v4)
[linux-2.6-block.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 <monk.liu@amd.com>
23  */
24
25 #include <drm/drmP.h>
26 #include "amdgpu.h"
27
28 static void amdgpu_ctx_do_release(struct kref *ref)
29 {
30         struct amdgpu_ctx *ctx;
31         struct amdgpu_ctx_mgr *mgr;
32
33         ctx = container_of(ref, struct amdgpu_ctx, refcount);
34         mgr = &ctx->fpriv->ctx_mgr;
35
36         mutex_lock(&mgr->hlock);
37         idr_remove(&mgr->ctx_handles, ctx->id);
38         mutex_unlock(&mgr->hlock);
39         kfree(ctx);
40 }
41
42 int amdgpu_ctx_alloc(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv, uint32_t *id, uint32_t flags)
43 {
44         int r;
45         struct amdgpu_ctx *ctx;
46         struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
47
48         ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
49         if (!ctx)
50                 return -ENOMEM;
51
52         mutex_lock(&mgr->hlock);
53         r = idr_alloc(&mgr->ctx_handles, ctx, 0, 0, GFP_KERNEL);
54         if (r < 0) {
55                 mutex_unlock(&mgr->hlock);
56                 kfree(ctx);
57                 return r;
58         }
59         mutex_unlock(&mgr->hlock);
60         *id = (uint32_t)r;
61
62         memset(ctx, 0, sizeof(*ctx));
63         ctx->id = *id;
64         ctx->fpriv = fpriv;
65         kref_init(&ctx->refcount);
66
67         return 0;
68 }
69
70 int amdgpu_ctx_free(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv, uint32_t id)
71 {
72         int r;
73         struct amdgpu_ctx *ctx;
74         struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
75
76         rcu_read_lock();
77         ctx = idr_find(&mgr->ctx_handles, id);
78         rcu_read_unlock();
79         if (ctx) {
80                 /* if no task is pending on this context, free it */
81                 r = kref_put(&ctx->refcount, amdgpu_ctx_do_release);
82                 if (r == 1)
83                         return 0;//context is removed successfully
84                 else {
85                         /* context is still in using */
86                         kref_get(&ctx->refcount);
87                         return -ERESTARTSYS;
88                 }
89         }
90         return -EINVAL;
91 }
92
93 int amdgpu_ctx_query(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv, uint32_t id, struct amdgpu_ctx_state *state)
94 {
95         struct amdgpu_ctx *ctx;
96         struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
97
98         rcu_read_lock();
99         ctx = idr_find(&mgr->ctx_handles, id);
100         rcu_read_unlock();
101         if (ctx) {
102                 /* state should alter with CS activity */
103                 *state = ctx->state;
104                 return 0;
105         }
106         return -EINVAL;
107 }
108
109 void amdgpu_ctx_fini(struct amdgpu_fpriv *fpriv)
110 {
111         struct idr *idp;
112         struct amdgpu_ctx *ctx;
113         uint32_t id;
114         struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
115         idp = &mgr->ctx_handles;
116
117         idr_for_each_entry(idp,ctx,id) {
118                 if (kref_put(&ctx->refcount, amdgpu_ctx_do_release) != 1)
119                         DRM_ERROR("ctx (id=%ul) is still alive\n",ctx->id);
120         }
121
122         mutex_destroy(&mgr->hlock);
123 }
124
125 int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
126                                                         struct drm_file *filp)
127 {
128         int r;
129         uint32_t id;
130         uint32_t flags;
131         struct amdgpu_ctx_state state;
132
133         union drm_amdgpu_ctx *args = data;
134         struct amdgpu_device *adev = dev->dev_private;
135         struct amdgpu_fpriv *fpriv = filp->driver_priv;
136
137         r = 0;
138         id = args->in.ctx_id;
139         flags = args->in.flags;
140
141         switch (args->in.op) {
142                 case AMDGPU_CTX_OP_ALLOC_CTX:
143                         r = amdgpu_ctx_alloc(adev, fpriv, &id, flags);
144                         args->out.alloc.ctx_id = id;
145                         break;
146                 case AMDGPU_CTX_OP_FREE_CTX:
147                         r = amdgpu_ctx_free(adev, fpriv, id);
148                         break;
149                 case AMDGPU_CTX_OP_QUERY_STATE:
150                         r = amdgpu_ctx_query(adev, fpriv, id, &state);
151                         if (r == 0) {
152                                 args->out.state.flags = state.flags;
153                                 args->out.state.hangs = state.hangs;
154                         }
155                         break;
156                 default:
157                         return -EINVAL;
158         }
159
160         return r;
161 }