brintos

brintos / linux-shallow public Read only

0
0
Text · 9.7 KiB · f94c033 Raw
437 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.3/*4 * Crypto driver for NVIDIA Security Engine in Tegra Chips5 */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 17static 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 26static 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 36static 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 43static struct host1x_bo_mapping *44tegra_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 80free_sgt:81	sg_free_table(map->sgt);82	kfree(map->sgt);83free:84	kfree(map);85	return ERR_PTR(err);86}87 88static 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 101static 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 108static void tegra_se_cmdbuf_munmap(struct host1x_bo *host_bo, void *addr)109{110}111 112static 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 121static 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 144int 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 189job_unpin:190	host1x_job_unpin(job);191job_put:192	host1x_job_put(job);193 194	return ret;195}196 197static 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 231cmdbuf_put:232	tegra_se_cmdbuf_put(&se->cmdbuf->bo);233syncpt_put:234	host1x_syncpt_put(se->syncpt);235channel_put:236	host1x_channel_put(se->channel);237 238	return ret;239}240 241static 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 253static const struct host1x_client_ops tegra_se_client_ops = {254	.init = tegra_se_client_init,255	.exit = tegra_se_client_deinit,256};257 258static 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 271static 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 323static 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 332static 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 346static 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 356static 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 364static 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 372static const struct of_device_id tegra_se_of_match[] = {373	{374		.compatible = "nvidia,tegra234-se-aes",375		.data = &tegra234_aes_hw376	}, {377		.compatible = "nvidia,tegra234-se-hash",378		.data = &tegra234_hash_hw,379	},380	{ },381};382MODULE_DEVICE_TABLE(of, tegra_se_of_match);383 384static 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 393static int tegra_se_host1x_probe(struct host1x_device *dev)394{395	return host1x_device_init(dev);396}397 398static int tegra_se_host1x_remove(struct host1x_device *dev)399{400	host1x_device_exit(dev);401 402	return 0;403}404 405static 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 414static 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 425static 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 431module_init(tegra_se_module_init);432module_exit(tegra_se_module_exit);433 434MODULE_DESCRIPTION("NVIDIA Tegra Security Engine Driver");435MODULE_AUTHOR("Akhil R <akhilrajeev@nvidia.com>");436MODULE_LICENSE("GPL");437