• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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