| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- // SPDX-License-Identifier: GPL-2.0-only
- // SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
- /*
- * Crypto driver for NVIDIA Security Engine in Tegra Chips
- */
- #include <linux/clk.h>
- #include <linux/dma-mapping.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/mod_devicetable.h>
- #include <crypto/engine.h>
- #include "tegra-se.h"
- static struct host1x_bo *tegra_se_cmdbuf_get(struct host1x_bo *host_bo)
- {
- struct tegra_se_cmdbuf *cmdbuf = container_of(host_bo, struct tegra_se_cmdbuf, bo);
- kref_get(&cmdbuf->ref);
- return host_bo;
- }
- static void tegra_se_cmdbuf_release(struct kref *ref)
- {
- struct tegra_se_cmdbuf *cmdbuf = container_of(ref, struct tegra_se_cmdbuf, ref);
- dma_free_attrs(cmdbuf->dev, cmdbuf->size, cmdbuf->addr,
- cmdbuf->iova, 0);
- kfree(cmdbuf);
- }
- static void tegra_se_cmdbuf_put(struct host1x_bo *host_bo)
- {
- struct tegra_se_cmdbuf *cmdbuf = container_of(host_bo, struct tegra_se_cmdbuf, bo);
- kref_put(&cmdbuf->ref, tegra_se_cmdbuf_release);
- }
- static struct host1x_bo_mapping *
- tegra_se_cmdbuf_pin(struct device *dev, struct host1x_bo *bo, enum dma_data_direction direction)
- {
- struct tegra_se_cmdbuf *cmdbuf = container_of(bo, struct tegra_se_cmdbuf, bo);
- struct host1x_bo_mapping *map;
- int err;
- map = kzalloc_obj(*map);
- if (!map)
- return ERR_PTR(-ENOMEM);
- kref_init(&map->ref);
- map->bo = host1x_bo_get(bo);
- map->direction = direction;
- map->dev = dev;
- map->sgt = kzalloc_obj(*map->sgt);
- if (!map->sgt) {
- err = -ENOMEM;
- goto free;
- }
- err = dma_get_sgtable(dev, map->sgt, cmdbuf->addr,
- cmdbuf->iova, cmdbuf->words * 4);
- if (err)
- goto free_sgt;
- err = dma_map_sgtable(dev, map->sgt, direction, 0);
- if (err)
- goto free_sgt;
- map->phys = sg_dma_address(map->sgt->sgl);
- map->size = cmdbuf->words * 4;
- map->chunks = err;
- return map;
- free_sgt:
- sg_free_table(map->sgt);
- kfree(map->sgt);
- free:
- kfree(map);
- return ERR_PTR(err);
- }
- static void tegra_se_cmdbuf_unpin(struct host1x_bo_mapping *map)
- {
- if (!map)
- return;
- dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0);
- sg_free_table(map->sgt);
- kfree(map->sgt);
- host1x_bo_put(map->bo);
- kfree(map);
- }
- static void *tegra_se_cmdbuf_mmap(struct host1x_bo *host_bo)
- {
- struct tegra_se_cmdbuf *cmdbuf = container_of(host_bo, struct tegra_se_cmdbuf, bo);
- return cmdbuf->addr;
- }
- static void tegra_se_cmdbuf_munmap(struct host1x_bo *host_bo, void *addr)
- {
- }
- static const struct host1x_bo_ops tegra_se_cmdbuf_ops = {
- .get = tegra_se_cmdbuf_get,
- .put = tegra_se_cmdbuf_put,
- .pin = tegra_se_cmdbuf_pin,
- .unpin = tegra_se_cmdbuf_unpin,
- .mmap = tegra_se_cmdbuf_mmap,
- .munmap = tegra_se_cmdbuf_munmap,
- };
- static struct tegra_se_cmdbuf *tegra_se_host1x_bo_alloc(struct tegra_se *se, ssize_t size)
- {
- struct tegra_se_cmdbuf *cmdbuf;
- struct device *dev = se->dev->parent;
- cmdbuf = kzalloc_obj(*cmdbuf);
- if (!cmdbuf)
- return NULL;
- cmdbuf->addr = dma_alloc_attrs(dev, size, &cmdbuf->iova,
- GFP_KERNEL, 0);
- if (!cmdbuf->addr)
- return NULL;
- cmdbuf->size = size;
- cmdbuf->dev = dev;
- host1x_bo_init(&cmdbuf->bo, &tegra_se_cmdbuf_ops);
- kref_init(&cmdbuf->ref);
- return cmdbuf;
- }
- int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf, u32 size)
- {
- struct host1x_job *job;
- int ret;
- job = host1x_job_alloc(se->channel, 1, 0, true);
- if (!job) {
- dev_err(se->dev, "failed to allocate host1x job\n");
- return -ENOMEM;
- }
- job->syncpt = host1x_syncpt_get(se->syncpt);
- job->syncpt_incrs = 1;
- job->client = &se->client;
- job->class = se->client.class;
- job->serialize = true;
- job->engine_fallback_streamid = se->stream_id;
- job->engine_streamid_offset = SE_STREAM_ID;
- cmdbuf->words = size;
- host1x_job_add_gather(job, &cmdbuf->bo, size, 0);
- ret = host1x_job_pin(job, se->dev);
- if (ret) {
- dev_err(se->dev, "failed to pin host1x job\n");
- goto job_put;
- }
- ret = host1x_job_submit(job);
- if (ret) {
- dev_err(se->dev, "failed to submit host1x job\n");
- goto job_unpin;
- }
- ret = host1x_syncpt_wait(job->syncpt, job->syncpt_end,
- MAX_SCHEDULE_TIMEOUT, NULL);
- if (ret) {
- dev_err(se->dev, "host1x job timed out\n");
- return ret;
- }
- host1x_job_put(job);
- return 0;
- job_unpin:
- host1x_job_unpin(job);
- job_put:
- host1x_job_put(job);
- return ret;
- }
- static int tegra_se_client_init(struct host1x_client *client)
- {
- struct tegra_se *se = container_of(client, struct tegra_se, client);
- int ret;
- se->channel = host1x_channel_request(&se->client);
- if (!se->channel) {
- dev_err(se->dev, "host1x channel map failed\n");
- return -ENODEV;
- }
- se->syncpt = host1x_syncpt_request(&se->client, 0);
- if (!se->syncpt) {
- dev_err(se->dev, "host1x syncpt allocation failed\n");
- ret = -EINVAL;
- goto channel_put;
- }
- se->syncpt_id = host1x_syncpt_id(se->syncpt);
- se->cmdbuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
- if (!se->cmdbuf) {
- ret = -ENOMEM;
- goto syncpt_put;
- }
- se->keybuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
- if (!se->keybuf) {
- ret = -ENOMEM;
- goto cmdbuf_put;
- }
- ret = se->hw->init_alg(se);
- if (ret) {
- dev_err(se->dev, "failed to register algorithms\n");
- goto keybuf_put;
- }
- return 0;
- keybuf_put:
- tegra_se_cmdbuf_put(&se->keybuf->bo);
- cmdbuf_put:
- tegra_se_cmdbuf_put(&se->cmdbuf->bo);
- syncpt_put:
- host1x_syncpt_put(se->syncpt);
- channel_put:
- host1x_channel_put(se->channel);
- return ret;
- }
- static int tegra_se_client_deinit(struct host1x_client *client)
- {
- struct tegra_se *se = container_of(client, struct tegra_se, client);
- se->hw->deinit_alg(se);
- tegra_se_cmdbuf_put(&se->cmdbuf->bo);
- host1x_syncpt_put(se->syncpt);
- host1x_channel_put(se->channel);
- return 0;
- }
- static const struct host1x_client_ops tegra_se_client_ops = {
- .init = tegra_se_client_init,
- .exit = tegra_se_client_deinit,
- };
- static int tegra_se_host1x_register(struct tegra_se *se)
- {
- INIT_LIST_HEAD(&se->client.list);
- se->client.dev = se->dev;
- se->client.ops = &tegra_se_client_ops;
- se->client.class = se->hw->host1x_class;
- se->client.num_syncpts = 1;
- host1x_client_register(&se->client);
- return 0;
- }
- static int tegra_se_probe(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- struct tegra_se *se;
- int ret;
- se = devm_kzalloc(dev, sizeof(*se), GFP_KERNEL);
- if (!se)
- return -ENOMEM;
- se->dev = dev;
- se->owner = TEGRA_GPSE_ID;
- se->hw = device_get_match_data(&pdev->dev);
- se->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(se->base))
- return PTR_ERR(se->base);
- dma_set_mask_and_coherent(dev, DMA_BIT_MASK(39));
- platform_set_drvdata(pdev, se);
- se->clk = devm_clk_get_enabled(se->dev, NULL);
- if (IS_ERR(se->clk))
- return dev_err_probe(dev, PTR_ERR(se->clk),
- "failed to enable clocks\n");
- if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id))
- return dev_err_probe(dev, -ENODEV,
- "failed to get IOMMU stream ID\n");
- writel(se->stream_id, se->base + SE_STREAM_ID);
- se->engine = crypto_engine_alloc_init(dev, 0);
- if (!se->engine)
- return -ENOMEM;
- ret = crypto_engine_start(se->engine);
- if (ret) {
- crypto_engine_exit(se->engine);
- return dev_err_probe(dev, ret, "failed to start crypto engine\n");
- }
- ret = tegra_se_host1x_register(se);
- if (ret) {
- crypto_engine_exit(se->engine);
- return dev_err_probe(dev, ret, "failed to init host1x params\n");
- }
- return 0;
- }
- static void tegra_se_remove(struct platform_device *pdev)
- {
- struct tegra_se *se = platform_get_drvdata(pdev);
- crypto_engine_exit(se->engine);
- host1x_client_unregister(&se->client);
- }
- static const struct tegra_se_regs tegra234_aes1_regs = {
- .config = SE_AES1_CFG,
- .op = SE_AES1_OPERATION,
- .last_blk = SE_AES1_LAST_BLOCK,
- .linear_ctr = SE_AES1_LINEAR_CTR,
- .aad_len = SE_AES1_AAD_LEN,
- .cryp_msg_len = SE_AES1_CRYPTO_MSG_LEN,
- .manifest = SE_AES1_KEYMANIFEST,
- .key_addr = SE_AES1_KEY_ADDR,
- .key_data = SE_AES1_KEY_DATA,
- .key_dst = SE_AES1_KEY_DST,
- .result = SE_AES1_CMAC_RESULT,
- };
- static const struct tegra_se_regs tegra234_hash_regs = {
- .config = SE_SHA_CFG,
- .op = SE_SHA_OPERATION,
- .manifest = SE_SHA_KEYMANIFEST,
- .key_addr = SE_SHA_KEY_ADDR,
- .key_data = SE_SHA_KEY_DATA,
- .key_dst = SE_SHA_KEY_DST,
- .result = SE_SHA_HASH_RESULT,
- };
- static const struct tegra_se_hw tegra234_aes_hw = {
- .regs = &tegra234_aes1_regs,
- .kac_ver = 1,
- .host1x_class = 0x3b,
- .init_alg = tegra_init_aes,
- .deinit_alg = tegra_deinit_aes,
- };
- static const struct tegra_se_hw tegra234_hash_hw = {
- .regs = &tegra234_hash_regs,
- .kac_ver = 1,
- .host1x_class = 0x3d,
- .init_alg = tegra_init_hash,
- .deinit_alg = tegra_deinit_hash,
- };
- static const struct of_device_id tegra_se_of_match[] = {
- {
- .compatible = "nvidia,tegra234-se-aes",
- .data = &tegra234_aes_hw
- }, {
- .compatible = "nvidia,tegra234-se-hash",
- .data = &tegra234_hash_hw,
- },
- { },
- };
- MODULE_DEVICE_TABLE(of, tegra_se_of_match);
- static struct platform_driver tegra_se_driver = {
- .driver = {
- .name = "tegra-se",
- .of_match_table = tegra_se_of_match,
- },
- .probe = tegra_se_probe,
- .remove = tegra_se_remove,
- };
- static int tegra_se_host1x_probe(struct host1x_device *dev)
- {
- return host1x_device_init(dev);
- }
- static void tegra_se_host1x_remove(struct host1x_device *dev)
- {
- host1x_device_exit(dev);
- }
- static struct host1x_driver tegra_se_host1x_driver = {
- .driver = {
- .name = "tegra-se-host1x",
- },
- .probe = tegra_se_host1x_probe,
- .remove = tegra_se_host1x_remove,
- .subdevs = tegra_se_of_match,
- };
- static int __init tegra_se_module_init(void)
- {
- int ret;
- ret = host1x_driver_register(&tegra_se_host1x_driver);
- if (ret)
- return ret;
- return platform_driver_register(&tegra_se_driver);
- }
- static void __exit tegra_se_module_exit(void)
- {
- host1x_driver_unregister(&tegra_se_host1x_driver);
- platform_driver_unregister(&tegra_se_driver);
- }
- module_init(tegra_se_module_init);
- module_exit(tegra_se_module_exit);
- MODULE_DESCRIPTION("NVIDIA Tegra Security Engine Driver");
- MODULE_AUTHOR("Akhil R <akhilrajeev@nvidia.com>");
- MODULE_LICENSE("GPL");
|