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