xref: /linux/drivers/crypto/tegra/tegra-se-main.c (revision d2c9a99135da931377240942d44f3dea104cedb8)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 /*
4  * Crypto driver for NVIDIA Security Engine in Tegra Chips
5  */
6 
7 #include <linux/clk.h>
8 #include <linux/dma-mapping.h>
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 
12 #include <crypto/engine.h>
13 
14 #include "tegra-se.h"
15 
tegra_se_cmdbuf_get(struct host1x_bo * host_bo)16 static struct host1x_bo *tegra_se_cmdbuf_get(struct host1x_bo *host_bo)
17 {
18 	struct tegra_se_cmdbuf *cmdbuf = container_of(host_bo, struct tegra_se_cmdbuf, bo);
19 
20 	kref_get(&cmdbuf->ref);
21 
22 	return host_bo;
23 }
24 
tegra_se_cmdbuf_release(struct kref * ref)25 static void tegra_se_cmdbuf_release(struct kref *ref)
26 {
27 	struct tegra_se_cmdbuf *cmdbuf = container_of(ref, struct tegra_se_cmdbuf, ref);
28 
29 	dma_free_attrs(cmdbuf->dev, cmdbuf->size, cmdbuf->addr,
30 		       cmdbuf->iova, 0);
31 
32 	kfree(cmdbuf);
33 }
34 
tegra_se_cmdbuf_put(struct host1x_bo * host_bo)35 static void tegra_se_cmdbuf_put(struct host1x_bo *host_bo)
36 {
37 	struct tegra_se_cmdbuf *cmdbuf = container_of(host_bo, struct tegra_se_cmdbuf, bo);
38 
39 	kref_put(&cmdbuf->ref, tegra_se_cmdbuf_release);
40 }
41 
42 static struct host1x_bo_mapping *
tegra_se_cmdbuf_pin(struct device * dev,struct host1x_bo * bo,enum dma_data_direction direction)43 tegra_se_cmdbuf_pin(struct device *dev, struct host1x_bo *bo, enum dma_data_direction direction)
44 {
45 	struct tegra_se_cmdbuf *cmdbuf = container_of(bo, struct tegra_se_cmdbuf, bo);
46 	struct host1x_bo_mapping *map;
47 	int err;
48 
49 	map = kzalloc_obj(*map);
50 	if (!map)
51 		return ERR_PTR(-ENOMEM);
52 
53 	kref_init(&map->ref);
54 	map->bo = bo;
55 	map->direction = direction;
56 	map->dev = dev;
57 
58 	map->sgt = kzalloc_obj(*map->sgt);
59 	if (!map->sgt) {
60 		err = -ENOMEM;
61 		goto free;
62 	}
63 
64 	err = dma_get_sgtable(dev, map->sgt, cmdbuf->addr,
65 			      cmdbuf->iova, cmdbuf->words * 4);
66 	if (err)
67 		goto free_sgt;
68 
69 	err = dma_map_sgtable(dev, map->sgt, direction, 0);
70 	if (err)
71 		goto free_sgt;
72 
73 	map->phys = sg_dma_address(map->sgt->sgl);
74 	map->size = cmdbuf->words * 4;
75 	map->chunks = err;
76 
77 	return map;
78 
79 free_sgt:
80 	sg_free_table(map->sgt);
81 	kfree(map->sgt);
82 free:
83 	kfree(map);
84 	return ERR_PTR(err);
85 }
86 
tegra_se_cmdbuf_unpin(struct host1x_bo_mapping * map)87 static void tegra_se_cmdbuf_unpin(struct host1x_bo_mapping *map)
88 {
89 	if (!map)
90 		return;
91 
92 	dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0);
93 	sg_free_table(map->sgt);
94 	kfree(map->sgt);
95 
96 	kfree(map);
97 }
98 
tegra_se_cmdbuf_mmap(struct host1x_bo * host_bo)99 static void *tegra_se_cmdbuf_mmap(struct host1x_bo *host_bo)
100 {
101 	struct tegra_se_cmdbuf *cmdbuf = container_of(host_bo, struct tegra_se_cmdbuf, bo);
102 
103 	return cmdbuf->addr;
104 }
105 
tegra_se_cmdbuf_munmap(struct host1x_bo * host_bo,void * addr)106 static void tegra_se_cmdbuf_munmap(struct host1x_bo *host_bo, void *addr)
107 {
108 }
109 
110 static const struct host1x_bo_ops tegra_se_cmdbuf_ops = {
111 	.get = tegra_se_cmdbuf_get,
112 	.put = tegra_se_cmdbuf_put,
113 	.pin = tegra_se_cmdbuf_pin,
114 	.unpin = tegra_se_cmdbuf_unpin,
115 	.mmap = tegra_se_cmdbuf_mmap,
116 	.munmap = tegra_se_cmdbuf_munmap,
117 };
118 
tegra_se_host1x_bo_alloc(struct tegra_se * se,ssize_t size)119 static struct tegra_se_cmdbuf *tegra_se_host1x_bo_alloc(struct tegra_se *se, ssize_t size)
120 {
121 	struct tegra_se_cmdbuf *cmdbuf;
122 	struct device *dev = se->dev->parent;
123 
124 	cmdbuf = kzalloc_obj(*cmdbuf);
125 	if (!cmdbuf)
126 		return NULL;
127 
128 	cmdbuf->addr = dma_alloc_attrs(dev, size, &cmdbuf->iova,
129 				       GFP_KERNEL, 0);
130 	if (!cmdbuf->addr)
131 		return NULL;
132 
133 	cmdbuf->size = size;
134 	cmdbuf->dev  = dev;
135 
136 	host1x_bo_init(&cmdbuf->bo, &tegra_se_cmdbuf_ops);
137 	kref_init(&cmdbuf->ref);
138 
139 	return cmdbuf;
140 }
141 
tegra_se_host1x_submit(struct tegra_se * se,struct tegra_se_cmdbuf * cmdbuf,u32 size)142 int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf, u32 size)
143 {
144 	struct host1x_job *job;
145 	int ret;
146 
147 	job = host1x_job_alloc(se->channel, 1, 0, true);
148 	if (!job) {
149 		dev_err(se->dev, "failed to allocate host1x job\n");
150 		return -ENOMEM;
151 	}
152 
153 	job->syncpt = host1x_syncpt_get(se->syncpt);
154 	job->syncpt_incrs = 1;
155 	job->client = &se->client;
156 	job->class = se->client.class;
157 	job->serialize = true;
158 	job->engine_fallback_streamid = se->stream_id;
159 	job->engine_streamid_offset = SE_STREAM_ID;
160 
161 	cmdbuf->words = size;
162 
163 	host1x_job_add_gather(job, &cmdbuf->bo, size, 0);
164 
165 	ret = host1x_job_pin(job, se->dev);
166 	if (ret) {
167 		dev_err(se->dev, "failed to pin host1x job\n");
168 		goto job_put;
169 	}
170 
171 	ret = host1x_job_submit(job);
172 	if (ret) {
173 		dev_err(se->dev, "failed to submit host1x job\n");
174 		goto job_unpin;
175 	}
176 
177 	ret = host1x_syncpt_wait(job->syncpt, job->syncpt_end,
178 				 MAX_SCHEDULE_TIMEOUT, NULL);
179 	if (ret) {
180 		dev_err(se->dev, "host1x job timed out\n");
181 		goto job_put;
182 	}
183 
184 	host1x_job_put(job);
185 	return 0;
186 
187 job_unpin:
188 	host1x_job_unpin(job);
189 job_put:
190 	host1x_job_put(job);
191 
192 	return ret;
193 }
194 
tegra_se_client_init(struct host1x_client * client)195 static int tegra_se_client_init(struct host1x_client *client)
196 {
197 	struct tegra_se *se = container_of(client, struct tegra_se, client);
198 	int ret;
199 
200 	se->channel = host1x_channel_request(&se->client);
201 	if (!se->channel) {
202 		dev_err(se->dev, "host1x channel map failed\n");
203 		return -ENODEV;
204 	}
205 
206 	se->syncpt = host1x_syncpt_request(&se->client, 0);
207 	if (!se->syncpt) {
208 		dev_err(se->dev, "host1x syncpt allocation failed\n");
209 		ret = -EINVAL;
210 		goto channel_put;
211 	}
212 
213 	se->syncpt_id =  host1x_syncpt_id(se->syncpt);
214 
215 	se->cmdbuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
216 	if (!se->cmdbuf) {
217 		ret = -ENOMEM;
218 		goto syncpt_put;
219 	}
220 
221 	se->keybuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
222 	if (!se->keybuf) {
223 		ret = -ENOMEM;
224 		goto cmdbuf_put;
225 	}
226 
227 	ret = se->hw->init_alg(se);
228 	if (ret) {
229 		dev_err(se->dev, "failed to register algorithms\n");
230 		goto keybuf_put;
231 	}
232 
233 	return 0;
234 
235 keybuf_put:
236 	tegra_se_cmdbuf_put(&se->keybuf->bo);
237 cmdbuf_put:
238 	tegra_se_cmdbuf_put(&se->cmdbuf->bo);
239 syncpt_put:
240 	host1x_syncpt_put(se->syncpt);
241 channel_put:
242 	host1x_channel_put(se->channel);
243 
244 	return ret;
245 }
246 
tegra_se_client_deinit(struct host1x_client * client)247 static int tegra_se_client_deinit(struct host1x_client *client)
248 {
249 	struct tegra_se *se = container_of(client, struct tegra_se, client);
250 
251 	se->hw->deinit_alg(se);
252 	tegra_se_cmdbuf_put(&se->cmdbuf->bo);
253 	host1x_syncpt_put(se->syncpt);
254 	host1x_channel_put(se->channel);
255 
256 	return 0;
257 }
258 
259 static const struct host1x_client_ops tegra_se_client_ops = {
260 	.init = tegra_se_client_init,
261 	.exit = tegra_se_client_deinit,
262 };
263 
tegra_se_host1x_register(struct tegra_se * se)264 static int tegra_se_host1x_register(struct tegra_se *se)
265 {
266 	INIT_LIST_HEAD(&se->client.list);
267 	se->client.dev = se->dev;
268 	se->client.ops = &tegra_se_client_ops;
269 	se->client.class = se->hw->host1x_class;
270 	se->client.num_syncpts = 1;
271 
272 	host1x_client_register(&se->client);
273 
274 	return 0;
275 }
276 
tegra_se_probe(struct platform_device * pdev)277 static int tegra_se_probe(struct platform_device *pdev)
278 {
279 	struct device *dev = &pdev->dev;
280 	struct tegra_se *se;
281 	int ret;
282 
283 	se = devm_kzalloc(dev, sizeof(*se), GFP_KERNEL);
284 	if (!se)
285 		return -ENOMEM;
286 
287 	se->dev = dev;
288 	se->owner = TEGRA_GPSE_ID;
289 	se->hw = device_get_match_data(&pdev->dev);
290 
291 	se->base = devm_platform_ioremap_resource(pdev, 0);
292 	if (IS_ERR(se->base))
293 		return PTR_ERR(se->base);
294 
295 	dma_set_mask_and_coherent(dev, DMA_BIT_MASK(39));
296 	platform_set_drvdata(pdev, se);
297 
298 	se->clk = devm_clk_get_enabled(se->dev, NULL);
299 	if (IS_ERR(se->clk))
300 		return dev_err_probe(dev, PTR_ERR(se->clk),
301 				"failed to enable clocks\n");
302 
303 	if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id))
304 		return dev_err_probe(dev, -ENODEV,
305 				"failed to get IOMMU stream ID\n");
306 
307 	writel(se->stream_id, se->base + SE_STREAM_ID);
308 
309 	se->engine = crypto_engine_alloc_init(dev, 0);
310 	if (!se->engine)
311 		return -ENOMEM;
312 
313 	ret = crypto_engine_start(se->engine);
314 	if (ret) {
315 		crypto_engine_exit(se->engine);
316 		return dev_err_probe(dev, ret, "failed to start crypto engine\n");
317 	}
318 
319 	ret = tegra_se_host1x_register(se);
320 	if (ret) {
321 		crypto_engine_exit(se->engine);
322 		return dev_err_probe(dev, ret, "failed to init host1x params\n");
323 	}
324 
325 	return 0;
326 }
327 
tegra_se_remove(struct platform_device * pdev)328 static void tegra_se_remove(struct platform_device *pdev)
329 {
330 	struct tegra_se *se = platform_get_drvdata(pdev);
331 
332 	crypto_engine_exit(se->engine);
333 	host1x_client_unregister(&se->client);
334 }
335 
336 static const struct tegra_se_regs tegra234_aes1_regs = {
337 	.config = SE_AES1_CFG,
338 	.op = SE_AES1_OPERATION,
339 	.last_blk = SE_AES1_LAST_BLOCK,
340 	.linear_ctr = SE_AES1_LINEAR_CTR,
341 	.aad_len = SE_AES1_AAD_LEN,
342 	.cryp_msg_len = SE_AES1_CRYPTO_MSG_LEN,
343 	.manifest = SE_AES1_KEYMANIFEST,
344 	.key_addr = SE_AES1_KEY_ADDR,
345 	.key_data = SE_AES1_KEY_DATA,
346 	.key_dst = SE_AES1_KEY_DST,
347 	.result = SE_AES1_CMAC_RESULT,
348 };
349 
350 static const struct tegra_se_regs tegra234_hash_regs = {
351 	.config = SE_SHA_CFG,
352 	.op = SE_SHA_OPERATION,
353 	.manifest = SE_SHA_KEYMANIFEST,
354 	.key_addr = SE_SHA_KEY_ADDR,
355 	.key_data = SE_SHA_KEY_DATA,
356 	.key_dst = SE_SHA_KEY_DST,
357 	.result = SE_SHA_HASH_RESULT,
358 };
359 
360 static const struct tegra_se_hw tegra234_aes_hw = {
361 	.regs = &tegra234_aes1_regs,
362 	.kac_ver = 1,
363 	.host1x_class = 0x3b,
364 	.init_alg = tegra_init_aes,
365 	.deinit_alg = tegra_deinit_aes,
366 };
367 
368 static const struct tegra_se_hw tegra234_hash_hw = {
369 	.regs = &tegra234_hash_regs,
370 	.kac_ver = 1,
371 	.host1x_class = 0x3d,
372 	.init_alg = tegra_init_hash,
373 	.deinit_alg = tegra_deinit_hash,
374 };
375 
376 static const struct of_device_id tegra_se_of_match[] = {
377 	{
378 		.compatible = "nvidia,tegra234-se-aes",
379 		.data = &tegra234_aes_hw
380 	}, {
381 		.compatible = "nvidia,tegra234-se-hash",
382 		.data = &tegra234_hash_hw,
383 	},
384 	{ },
385 };
386 MODULE_DEVICE_TABLE(of, tegra_se_of_match);
387 
388 static struct platform_driver tegra_se_driver = {
389 	.driver = {
390 		.name	= "tegra-se",
391 		.of_match_table = tegra_se_of_match,
392 	},
393 	.probe		= tegra_se_probe,
394 	.remove		= tegra_se_remove,
395 };
396 
tegra_se_host1x_probe(struct host1x_device * dev)397 static int tegra_se_host1x_probe(struct host1x_device *dev)
398 {
399 	return host1x_device_init(dev);
400 }
401 
tegra_se_host1x_remove(struct host1x_device * dev)402 static void tegra_se_host1x_remove(struct host1x_device *dev)
403 {
404 	host1x_device_exit(dev);
405 }
406 
407 static struct host1x_driver tegra_se_host1x_driver = {
408 	.driver = {
409 		.name = "tegra-se-host1x",
410 	},
411 	.probe = tegra_se_host1x_probe,
412 	.remove = tegra_se_host1x_remove,
413 	.subdevs = tegra_se_of_match,
414 };
415 
tegra_se_module_init(void)416 static int __init tegra_se_module_init(void)
417 {
418 	int ret;
419 
420 	ret = host1x_driver_register(&tegra_se_host1x_driver);
421 	if (ret)
422 		return ret;
423 
424 	return platform_driver_register(&tegra_se_driver);
425 }
426 
tegra_se_module_exit(void)427 static void __exit tegra_se_module_exit(void)
428 {
429 	host1x_driver_unregister(&tegra_se_host1x_driver);
430 	platform_driver_unregister(&tegra_se_driver);
431 }
432 
433 module_init(tegra_se_module_init);
434 module_exit(tegra_se_module_exit);
435 
436 MODULE_DESCRIPTION("NVIDIA Tegra Security Engine Driver");
437 MODULE_AUTHOR("Akhil R <akhilrajeev@nvidia.com>");
438 MODULE_LICENSE("GPL");
439