1 // SPDX-License-Identifier: GPL-2.0
2
3 /*
4 * Copyright 2016-2019 HabanaLabs, Ltd.
5 * All Rights Reserved.
6 */
7
8 #include "habanalabs.h"
9
10 #include <linux/slab.h>
11
hl_ctx_fini(struct hl_ctx * ctx)12 static void hl_ctx_fini(struct hl_ctx *ctx)
13 {
14 struct hl_device *hdev = ctx->hdev;
15 u64 idle_mask = 0;
16 int i;
17
18 /*
19 * If we arrived here, there are no jobs waiting for this context
20 * on its queues so we can safely remove it.
21 * This is because for each CS, we increment the ref count and for
22 * every CS that was finished we decrement it and we won't arrive
23 * to this function unless the ref count is 0
24 */
25
26 for (i = 0 ; i < hdev->asic_prop.max_pending_cs ; i++)
27 hl_fence_put(ctx->cs_pending[i]);
28
29 kfree(ctx->cs_pending);
30
31 if (ctx->asid != HL_KERNEL_ASID_ID) {
32 dev_dbg(hdev->dev, "closing user context %d\n", ctx->asid);
33
34 /* The engines are stopped as there is no executing CS, but the
35 * Coresight might be still working by accessing addresses
36 * related to the stopped engines. Hence stop it explicitly.
37 * Stop only if this is the compute context, as there can be
38 * only one compute context
39 */
40 if ((hdev->in_debug) && (hdev->compute_ctx == ctx))
41 hl_device_set_debug_mode(hdev, false);
42
43 hl_cb_va_pool_fini(ctx);
44 hl_vm_ctx_fini(ctx);
45 hl_asid_free(hdev, ctx->asid);
46
47 if ((!hdev->pldm) && (hdev->pdev) &&
48 (!hdev->asic_funcs->is_device_idle(hdev,
49 &idle_mask, NULL)))
50 dev_notice(hdev->dev,
51 "device not idle after user context is closed (0x%llx)\n",
52 idle_mask);
53 } else {
54 dev_dbg(hdev->dev, "closing kernel context\n");
55 hl_mmu_ctx_fini(ctx);
56 }
57 }
58
hl_ctx_do_release(struct kref * ref)59 void hl_ctx_do_release(struct kref *ref)
60 {
61 struct hl_ctx *ctx;
62
63 ctx = container_of(ref, struct hl_ctx, refcount);
64
65 hl_ctx_fini(ctx);
66
67 if (ctx->hpriv)
68 hl_hpriv_put(ctx->hpriv);
69
70 kfree(ctx);
71 }
72
hl_ctx_create(struct hl_device * hdev,struct hl_fpriv * hpriv)73 int hl_ctx_create(struct hl_device *hdev, struct hl_fpriv *hpriv)
74 {
75 struct hl_ctx_mgr *mgr = &hpriv->ctx_mgr;
76 struct hl_ctx *ctx;
77 int rc;
78
79 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
80 if (!ctx) {
81 rc = -ENOMEM;
82 goto out_err;
83 }
84
85 mutex_lock(&mgr->ctx_lock);
86 rc = idr_alloc(&mgr->ctx_handles, ctx, 1, 0, GFP_KERNEL);
87 mutex_unlock(&mgr->ctx_lock);
88
89 if (rc < 0) {
90 dev_err(hdev->dev, "Failed to allocate IDR for a new CTX\n");
91 goto free_ctx;
92 }
93
94 ctx->handle = rc;
95
96 rc = hl_ctx_init(hdev, ctx, false);
97 if (rc)
98 goto remove_from_idr;
99
100 hl_hpriv_get(hpriv);
101 ctx->hpriv = hpriv;
102
103 /* TODO: remove for multiple contexts per process */
104 hpriv->ctx = ctx;
105
106 /* TODO: remove the following line for multiple process support */
107 hdev->compute_ctx = ctx;
108
109 return 0;
110
111 remove_from_idr:
112 mutex_lock(&mgr->ctx_lock);
113 idr_remove(&mgr->ctx_handles, ctx->handle);
114 mutex_unlock(&mgr->ctx_lock);
115 free_ctx:
116 kfree(ctx);
117 out_err:
118 return rc;
119 }
120
hl_ctx_free(struct hl_device * hdev,struct hl_ctx * ctx)121 void hl_ctx_free(struct hl_device *hdev, struct hl_ctx *ctx)
122 {
123 if (kref_put(&ctx->refcount, hl_ctx_do_release) == 1)
124 return;
125
126 dev_warn(hdev->dev,
127 "user process released device but its command submissions are still executing\n");
128 }
129
hl_ctx_init(struct hl_device * hdev,struct hl_ctx * ctx,bool is_kernel_ctx)130 int hl_ctx_init(struct hl_device *hdev, struct hl_ctx *ctx, bool is_kernel_ctx)
131 {
132 int rc = 0;
133
134 ctx->hdev = hdev;
135
136 kref_init(&ctx->refcount);
137
138 ctx->cs_sequence = 1;
139 spin_lock_init(&ctx->cs_lock);
140 atomic_set(&ctx->thread_ctx_switch_token, 1);
141 ctx->thread_ctx_switch_wait_token = 0;
142 ctx->cs_pending = kcalloc(hdev->asic_prop.max_pending_cs,
143 sizeof(struct hl_fence *),
144 GFP_KERNEL);
145 if (!ctx->cs_pending)
146 return -ENOMEM;
147
148 if (is_kernel_ctx) {
149 ctx->asid = HL_KERNEL_ASID_ID; /* Kernel driver gets ASID 0 */
150 rc = hl_mmu_ctx_init(ctx);
151 if (rc) {
152 dev_err(hdev->dev, "Failed to init mmu ctx module\n");
153 goto err_free_cs_pending;
154 }
155 } else {
156 ctx->asid = hl_asid_alloc(hdev);
157 if (!ctx->asid) {
158 dev_err(hdev->dev, "No free ASID, failed to create context\n");
159 rc = -ENOMEM;
160 goto err_free_cs_pending;
161 }
162
163 rc = hl_vm_ctx_init(ctx);
164 if (rc) {
165 dev_err(hdev->dev, "Failed to init mem ctx module\n");
166 rc = -ENOMEM;
167 goto err_asid_free;
168 }
169
170 rc = hl_cb_va_pool_init(ctx);
171 if (rc) {
172 dev_err(hdev->dev,
173 "Failed to init VA pool for mapped CB\n");
174 goto err_vm_ctx_fini;
175 }
176
177 rc = hdev->asic_funcs->ctx_init(ctx);
178 if (rc) {
179 dev_err(hdev->dev, "ctx_init failed\n");
180 goto err_cb_va_pool_fini;
181 }
182
183 dev_dbg(hdev->dev, "create user context %d\n", ctx->asid);
184 }
185
186 return 0;
187
188 err_cb_va_pool_fini:
189 hl_cb_va_pool_fini(ctx);
190 err_vm_ctx_fini:
191 hl_vm_ctx_fini(ctx);
192 err_asid_free:
193 hl_asid_free(hdev, ctx->asid);
194 err_free_cs_pending:
195 kfree(ctx->cs_pending);
196
197 return rc;
198 }
199
hl_ctx_get(struct hl_device * hdev,struct hl_ctx * ctx)200 void hl_ctx_get(struct hl_device *hdev, struct hl_ctx *ctx)
201 {
202 kref_get(&ctx->refcount);
203 }
204
hl_ctx_put(struct hl_ctx * ctx)205 int hl_ctx_put(struct hl_ctx *ctx)
206 {
207 return kref_put(&ctx->refcount, hl_ctx_do_release);
208 }
209
hl_ctx_get_fence(struct hl_ctx * ctx,u64 seq)210 struct hl_fence *hl_ctx_get_fence(struct hl_ctx *ctx, u64 seq)
211 {
212 struct asic_fixed_properties *asic_prop = &ctx->hdev->asic_prop;
213 struct hl_fence *fence;
214
215 spin_lock(&ctx->cs_lock);
216
217 if (seq >= ctx->cs_sequence) {
218 spin_unlock(&ctx->cs_lock);
219 return ERR_PTR(-EINVAL);
220 }
221
222 if (seq + asic_prop->max_pending_cs < ctx->cs_sequence) {
223 spin_unlock(&ctx->cs_lock);
224 return NULL;
225 }
226
227 fence = ctx->cs_pending[seq & (asic_prop->max_pending_cs - 1)];
228 hl_fence_get(fence);
229
230 spin_unlock(&ctx->cs_lock);
231
232 return fence;
233 }
234
235 /*
236 * hl_ctx_mgr_init - initialize the context manager
237 *
238 * @mgr: pointer to context manager structure
239 *
240 * This manager is an object inside the hpriv object of the user process.
241 * The function is called when a user process opens the FD.
242 */
hl_ctx_mgr_init(struct hl_ctx_mgr * mgr)243 void hl_ctx_mgr_init(struct hl_ctx_mgr *mgr)
244 {
245 mutex_init(&mgr->ctx_lock);
246 idr_init(&mgr->ctx_handles);
247 }
248
249 /*
250 * hl_ctx_mgr_fini - finalize the context manager
251 *
252 * @hdev: pointer to device structure
253 * @mgr: pointer to context manager structure
254 *
255 * This function goes over all the contexts in the manager and frees them.
256 * It is called when a process closes the FD.
257 */
hl_ctx_mgr_fini(struct hl_device * hdev,struct hl_ctx_mgr * mgr)258 void hl_ctx_mgr_fini(struct hl_device *hdev, struct hl_ctx_mgr *mgr)
259 {
260 struct hl_ctx *ctx;
261 struct idr *idp;
262 u32 id;
263
264 idp = &mgr->ctx_handles;
265
266 idr_for_each_entry(idp, ctx, id)
267 hl_ctx_free(hdev, ctx);
268
269 idr_destroy(&mgr->ctx_handles);
270 mutex_destroy(&mgr->ctx_lock);
271 }
272