cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

amlogic-gxl-core.c (7797B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * amlgoic-core.c - hardware cryptographic offloader for Amlogic GXL SoC
      4 *
      5 * Copyright (C) 2018-2019 Corentin Labbe <clabbe@baylibre.com>
      6 *
      7 * Core file which registers crypto algorithms supported by the hardware.
      8 */
      9#include <linux/clk.h>
     10#include <linux/crypto.h>
     11#include <linux/io.h>
     12#include <linux/interrupt.h>
     13#include <linux/irq.h>
     14#include <linux/module.h>
     15#include <linux/of.h>
     16#include <linux/of_device.h>
     17#include <linux/platform_device.h>
     18#include <crypto/internal/skcipher.h>
     19#include <linux/dma-mapping.h>
     20
     21#include "amlogic-gxl.h"
     22
     23static irqreturn_t meson_irq_handler(int irq, void *data)
     24{
     25	struct meson_dev *mc = (struct meson_dev *)data;
     26	int flow;
     27	u32 p;
     28
     29	for (flow = 0; flow < MAXFLOW; flow++) {
     30		if (mc->irqs[flow] == irq) {
     31			p = readl(mc->base + ((0x04 + flow) << 2));
     32			if (p) {
     33				writel_relaxed(0xF, mc->base + ((0x4 + flow) << 2));
     34				mc->chanlist[flow].status = 1;
     35				complete(&mc->chanlist[flow].complete);
     36				return IRQ_HANDLED;
     37			}
     38			dev_err(mc->dev, "%s %d Got irq for flow %d but ctrl is empty\n", __func__, irq, flow);
     39		}
     40	}
     41
     42	dev_err(mc->dev, "%s %d from unknown irq\n", __func__, irq);
     43	return IRQ_HANDLED;
     44}
     45
     46static struct meson_alg_template mc_algs[] = {
     47{
     48	.type = CRYPTO_ALG_TYPE_SKCIPHER,
     49	.blockmode = MESON_OPMODE_CBC,
     50	.alg.skcipher = {
     51		.base = {
     52			.cra_name = "cbc(aes)",
     53			.cra_driver_name = "cbc-aes-gxl",
     54			.cra_priority = 400,
     55			.cra_blocksize = AES_BLOCK_SIZE,
     56			.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
     57				CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
     58				CRYPTO_ALG_NEED_FALLBACK,
     59			.cra_ctxsize = sizeof(struct meson_cipher_tfm_ctx),
     60			.cra_module = THIS_MODULE,
     61			.cra_alignmask = 0xf,
     62			.cra_init = meson_cipher_init,
     63			.cra_exit = meson_cipher_exit,
     64		},
     65		.min_keysize	= AES_MIN_KEY_SIZE,
     66		.max_keysize	= AES_MAX_KEY_SIZE,
     67		.ivsize		= AES_BLOCK_SIZE,
     68		.setkey		= meson_aes_setkey,
     69		.encrypt	= meson_skencrypt,
     70		.decrypt	= meson_skdecrypt,
     71	}
     72},
     73{
     74	.type = CRYPTO_ALG_TYPE_SKCIPHER,
     75	.blockmode = MESON_OPMODE_ECB,
     76	.alg.skcipher = {
     77		.base = {
     78			.cra_name = "ecb(aes)",
     79			.cra_driver_name = "ecb-aes-gxl",
     80			.cra_priority = 400,
     81			.cra_blocksize = AES_BLOCK_SIZE,
     82			.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
     83				CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
     84				CRYPTO_ALG_NEED_FALLBACK,
     85			.cra_ctxsize = sizeof(struct meson_cipher_tfm_ctx),
     86			.cra_module = THIS_MODULE,
     87			.cra_alignmask = 0xf,
     88			.cra_init = meson_cipher_init,
     89			.cra_exit = meson_cipher_exit,
     90		},
     91		.min_keysize	= AES_MIN_KEY_SIZE,
     92		.max_keysize	= AES_MAX_KEY_SIZE,
     93		.setkey		= meson_aes_setkey,
     94		.encrypt	= meson_skencrypt,
     95		.decrypt	= meson_skdecrypt,
     96	}
     97},
     98};
     99
    100#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
    101static int meson_debugfs_show(struct seq_file *seq, void *v)
    102{
    103	struct meson_dev *mc = seq->private;
    104	int i;
    105
    106	for (i = 0; i < MAXFLOW; i++)
    107		seq_printf(seq, "Channel %d: nreq %lu\n", i, mc->chanlist[i].stat_req);
    108
    109	for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
    110		switch (mc_algs[i].type) {
    111		case CRYPTO_ALG_TYPE_SKCIPHER:
    112			seq_printf(seq, "%s %s %lu %lu\n",
    113				   mc_algs[i].alg.skcipher.base.cra_driver_name,
    114				   mc_algs[i].alg.skcipher.base.cra_name,
    115				   mc_algs[i].stat_req, mc_algs[i].stat_fb);
    116			break;
    117		}
    118	}
    119	return 0;
    120}
    121DEFINE_SHOW_ATTRIBUTE(meson_debugfs);
    122#endif
    123
    124static void meson_free_chanlist(struct meson_dev *mc, int i)
    125{
    126	while (i >= 0) {
    127		crypto_engine_exit(mc->chanlist[i].engine);
    128		if (mc->chanlist[i].tl)
    129			dma_free_coherent(mc->dev, sizeof(struct meson_desc) * MAXDESC,
    130					  mc->chanlist[i].tl,
    131					  mc->chanlist[i].t_phy);
    132		i--;
    133	}
    134}
    135
    136/*
    137 * Allocate the channel list structure
    138 */
    139static int meson_allocate_chanlist(struct meson_dev *mc)
    140{
    141	int i, err;
    142
    143	mc->chanlist = devm_kcalloc(mc->dev, MAXFLOW,
    144				    sizeof(struct meson_flow), GFP_KERNEL);
    145	if (!mc->chanlist)
    146		return -ENOMEM;
    147
    148	for (i = 0; i < MAXFLOW; i++) {
    149		init_completion(&mc->chanlist[i].complete);
    150
    151		mc->chanlist[i].engine = crypto_engine_alloc_init(mc->dev, true);
    152		if (!mc->chanlist[i].engine) {
    153			dev_err(mc->dev, "Cannot allocate engine\n");
    154			i--;
    155			err = -ENOMEM;
    156			goto error_engine;
    157		}
    158		err = crypto_engine_start(mc->chanlist[i].engine);
    159		if (err) {
    160			dev_err(mc->dev, "Cannot start engine\n");
    161			goto error_engine;
    162		}
    163		mc->chanlist[i].tl = dma_alloc_coherent(mc->dev,
    164							sizeof(struct meson_desc) * MAXDESC,
    165							&mc->chanlist[i].t_phy,
    166							GFP_KERNEL);
    167		if (!mc->chanlist[i].tl) {
    168			err = -ENOMEM;
    169			goto error_engine;
    170		}
    171	}
    172	return 0;
    173error_engine:
    174	meson_free_chanlist(mc, i);
    175	return err;
    176}
    177
    178static int meson_register_algs(struct meson_dev *mc)
    179{
    180	int err, i;
    181
    182	for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
    183		mc_algs[i].mc = mc;
    184		switch (mc_algs[i].type) {
    185		case CRYPTO_ALG_TYPE_SKCIPHER:
    186			err = crypto_register_skcipher(&mc_algs[i].alg.skcipher);
    187			if (err) {
    188				dev_err(mc->dev, "Fail to register %s\n",
    189					mc_algs[i].alg.skcipher.base.cra_name);
    190				mc_algs[i].mc = NULL;
    191				return err;
    192			}
    193			break;
    194		}
    195	}
    196
    197	return 0;
    198}
    199
    200static void meson_unregister_algs(struct meson_dev *mc)
    201{
    202	int i;
    203
    204	for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
    205		if (!mc_algs[i].mc)
    206			continue;
    207		switch (mc_algs[i].type) {
    208		case CRYPTO_ALG_TYPE_SKCIPHER:
    209			crypto_unregister_skcipher(&mc_algs[i].alg.skcipher);
    210			break;
    211		}
    212	}
    213}
    214
    215static int meson_crypto_probe(struct platform_device *pdev)
    216{
    217	struct meson_dev *mc;
    218	int err, i;
    219
    220	mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
    221	if (!mc)
    222		return -ENOMEM;
    223
    224	mc->dev = &pdev->dev;
    225	platform_set_drvdata(pdev, mc);
    226
    227	mc->base = devm_platform_ioremap_resource(pdev, 0);
    228	if (IS_ERR(mc->base)) {
    229		err = PTR_ERR(mc->base);
    230		dev_err(&pdev->dev, "Cannot request MMIO err=%d\n", err);
    231		return err;
    232	}
    233	mc->busclk = devm_clk_get(&pdev->dev, "blkmv");
    234	if (IS_ERR(mc->busclk)) {
    235		err = PTR_ERR(mc->busclk);
    236		dev_err(&pdev->dev, "Cannot get core clock err=%d\n", err);
    237		return err;
    238	}
    239
    240	mc->irqs = devm_kcalloc(mc->dev, MAXFLOW, sizeof(int), GFP_KERNEL);
    241	for (i = 0; i < MAXFLOW; i++) {
    242		mc->irqs[i] = platform_get_irq(pdev, i);
    243		if (mc->irqs[i] < 0)
    244			return mc->irqs[i];
    245
    246		err = devm_request_irq(&pdev->dev, mc->irqs[i], meson_irq_handler, 0,
    247				       "gxl-crypto", mc);
    248		if (err < 0) {
    249			dev_err(mc->dev, "Cannot request IRQ for flow %d\n", i);
    250			return err;
    251		}
    252	}
    253
    254	err = clk_prepare_enable(mc->busclk);
    255	if (err != 0) {
    256		dev_err(&pdev->dev, "Cannot prepare_enable busclk\n");
    257		return err;
    258	}
    259
    260	err = meson_allocate_chanlist(mc);
    261	if (err)
    262		goto error_flow;
    263
    264	err = meson_register_algs(mc);
    265	if (err)
    266		goto error_alg;
    267
    268#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
    269	mc->dbgfs_dir = debugfs_create_dir("gxl-crypto", NULL);
    270	debugfs_create_file("stats", 0444, mc->dbgfs_dir, mc, &meson_debugfs_fops);
    271#endif
    272
    273	return 0;
    274error_alg:
    275	meson_unregister_algs(mc);
    276error_flow:
    277	meson_free_chanlist(mc, MAXFLOW - 1);
    278	clk_disable_unprepare(mc->busclk);
    279	return err;
    280}
    281
    282static int meson_crypto_remove(struct platform_device *pdev)
    283{
    284	struct meson_dev *mc = platform_get_drvdata(pdev);
    285
    286#ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
    287	debugfs_remove_recursive(mc->dbgfs_dir);
    288#endif
    289
    290	meson_unregister_algs(mc);
    291
    292	meson_free_chanlist(mc, MAXFLOW - 1);
    293
    294	clk_disable_unprepare(mc->busclk);
    295	return 0;
    296}
    297
    298static const struct of_device_id meson_crypto_of_match_table[] = {
    299	{ .compatible = "amlogic,gxl-crypto", },
    300	{}
    301};
    302MODULE_DEVICE_TABLE(of, meson_crypto_of_match_table);
    303
    304static struct platform_driver meson_crypto_driver = {
    305	.probe		 = meson_crypto_probe,
    306	.remove		 = meson_crypto_remove,
    307	.driver		 = {
    308		.name		   = "gxl-crypto",
    309		.of_match_table	= meson_crypto_of_match_table,
    310	},
    311};
    312
    313module_platform_driver(meson_crypto_driver);
    314
    315MODULE_DESCRIPTION("Amlogic GXL cryptographic offloader");
    316MODULE_LICENSE("GPL");
    317MODULE_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");