Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * amlgoic-core.c - hardware cryptographic offloader for Amlogic GXL SoC
0004  *
0005  * Copyright (C) 2018-2019 Corentin Labbe <clabbe@baylibre.com>
0006  *
0007  * Core file which registers crypto algorithms supported by the hardware.
0008  */
0009 #include <linux/clk.h>
0010 #include <linux/crypto.h>
0011 #include <linux/io.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/irq.h>
0014 #include <linux/module.h>
0015 #include <linux/of.h>
0016 #include <linux/of_device.h>
0017 #include <linux/platform_device.h>
0018 #include <crypto/internal/skcipher.h>
0019 #include <linux/dma-mapping.h>
0020 
0021 #include "amlogic-gxl.h"
0022 
0023 static irqreturn_t meson_irq_handler(int irq, void *data)
0024 {
0025     struct meson_dev *mc = (struct meson_dev *)data;
0026     int flow;
0027     u32 p;
0028 
0029     for (flow = 0; flow < MAXFLOW; flow++) {
0030         if (mc->irqs[flow] == irq) {
0031             p = readl(mc->base + ((0x04 + flow) << 2));
0032             if (p) {
0033                 writel_relaxed(0xF, mc->base + ((0x4 + flow) << 2));
0034                 mc->chanlist[flow].status = 1;
0035                 complete(&mc->chanlist[flow].complete);
0036                 return IRQ_HANDLED;
0037             }
0038             dev_err(mc->dev, "%s %d Got irq for flow %d but ctrl is empty\n", __func__, irq, flow);
0039         }
0040     }
0041 
0042     dev_err(mc->dev, "%s %d from unknown irq\n", __func__, irq);
0043     return IRQ_HANDLED;
0044 }
0045 
0046 static struct meson_alg_template mc_algs[] = {
0047 {
0048     .type = CRYPTO_ALG_TYPE_SKCIPHER,
0049     .blockmode = MESON_OPMODE_CBC,
0050     .alg.skcipher = {
0051         .base = {
0052             .cra_name = "cbc(aes)",
0053             .cra_driver_name = "cbc-aes-gxl",
0054             .cra_priority = 400,
0055             .cra_blocksize = AES_BLOCK_SIZE,
0056             .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
0057                 CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
0058                 CRYPTO_ALG_NEED_FALLBACK,
0059             .cra_ctxsize = sizeof(struct meson_cipher_tfm_ctx),
0060             .cra_module = THIS_MODULE,
0061             .cra_alignmask = 0xf,
0062             .cra_init = meson_cipher_init,
0063             .cra_exit = meson_cipher_exit,
0064         },
0065         .min_keysize    = AES_MIN_KEY_SIZE,
0066         .max_keysize    = AES_MAX_KEY_SIZE,
0067         .ivsize     = AES_BLOCK_SIZE,
0068         .setkey     = meson_aes_setkey,
0069         .encrypt    = meson_skencrypt,
0070         .decrypt    = meson_skdecrypt,
0071     }
0072 },
0073 {
0074     .type = CRYPTO_ALG_TYPE_SKCIPHER,
0075     .blockmode = MESON_OPMODE_ECB,
0076     .alg.skcipher = {
0077         .base = {
0078             .cra_name = "ecb(aes)",
0079             .cra_driver_name = "ecb-aes-gxl",
0080             .cra_priority = 400,
0081             .cra_blocksize = AES_BLOCK_SIZE,
0082             .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER |
0083                 CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY |
0084                 CRYPTO_ALG_NEED_FALLBACK,
0085             .cra_ctxsize = sizeof(struct meson_cipher_tfm_ctx),
0086             .cra_module = THIS_MODULE,
0087             .cra_alignmask = 0xf,
0088             .cra_init = meson_cipher_init,
0089             .cra_exit = meson_cipher_exit,
0090         },
0091         .min_keysize    = AES_MIN_KEY_SIZE,
0092         .max_keysize    = AES_MAX_KEY_SIZE,
0093         .setkey     = meson_aes_setkey,
0094         .encrypt    = meson_skencrypt,
0095         .decrypt    = meson_skdecrypt,
0096     }
0097 },
0098 };
0099 
0100 #ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
0101 static int meson_debugfs_show(struct seq_file *seq, void *v)
0102 {
0103     struct meson_dev *mc = seq->private;
0104     int i;
0105 
0106     for (i = 0; i < MAXFLOW; i++)
0107         seq_printf(seq, "Channel %d: nreq %lu\n", i, mc->chanlist[i].stat_req);
0108 
0109     for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
0110         switch (mc_algs[i].type) {
0111         case CRYPTO_ALG_TYPE_SKCIPHER:
0112             seq_printf(seq, "%s %s %lu %lu\n",
0113                    mc_algs[i].alg.skcipher.base.cra_driver_name,
0114                    mc_algs[i].alg.skcipher.base.cra_name,
0115                    mc_algs[i].stat_req, mc_algs[i].stat_fb);
0116             break;
0117         }
0118     }
0119     return 0;
0120 }
0121 DEFINE_SHOW_ATTRIBUTE(meson_debugfs);
0122 #endif
0123 
0124 static void meson_free_chanlist(struct meson_dev *mc, int i)
0125 {
0126     while (i >= 0) {
0127         crypto_engine_exit(mc->chanlist[i].engine);
0128         if (mc->chanlist[i].tl)
0129             dma_free_coherent(mc->dev, sizeof(struct meson_desc) * MAXDESC,
0130                       mc->chanlist[i].tl,
0131                       mc->chanlist[i].t_phy);
0132         i--;
0133     }
0134 }
0135 
0136 /*
0137  * Allocate the channel list structure
0138  */
0139 static int meson_allocate_chanlist(struct meson_dev *mc)
0140 {
0141     int i, err;
0142 
0143     mc->chanlist = devm_kcalloc(mc->dev, MAXFLOW,
0144                     sizeof(struct meson_flow), GFP_KERNEL);
0145     if (!mc->chanlist)
0146         return -ENOMEM;
0147 
0148     for (i = 0; i < MAXFLOW; i++) {
0149         init_completion(&mc->chanlist[i].complete);
0150 
0151         mc->chanlist[i].engine = crypto_engine_alloc_init(mc->dev, true);
0152         if (!mc->chanlist[i].engine) {
0153             dev_err(mc->dev, "Cannot allocate engine\n");
0154             i--;
0155             err = -ENOMEM;
0156             goto error_engine;
0157         }
0158         err = crypto_engine_start(mc->chanlist[i].engine);
0159         if (err) {
0160             dev_err(mc->dev, "Cannot start engine\n");
0161             goto error_engine;
0162         }
0163         mc->chanlist[i].tl = dma_alloc_coherent(mc->dev,
0164                             sizeof(struct meson_desc) * MAXDESC,
0165                             &mc->chanlist[i].t_phy,
0166                             GFP_KERNEL);
0167         if (!mc->chanlist[i].tl) {
0168             err = -ENOMEM;
0169             goto error_engine;
0170         }
0171     }
0172     return 0;
0173 error_engine:
0174     meson_free_chanlist(mc, i);
0175     return err;
0176 }
0177 
0178 static int meson_register_algs(struct meson_dev *mc)
0179 {
0180     int err, i;
0181 
0182     for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
0183         mc_algs[i].mc = mc;
0184         switch (mc_algs[i].type) {
0185         case CRYPTO_ALG_TYPE_SKCIPHER:
0186             err = crypto_register_skcipher(&mc_algs[i].alg.skcipher);
0187             if (err) {
0188                 dev_err(mc->dev, "Fail to register %s\n",
0189                     mc_algs[i].alg.skcipher.base.cra_name);
0190                 mc_algs[i].mc = NULL;
0191                 return err;
0192             }
0193             break;
0194         }
0195     }
0196 
0197     return 0;
0198 }
0199 
0200 static void meson_unregister_algs(struct meson_dev *mc)
0201 {
0202     int i;
0203 
0204     for (i = 0; i < ARRAY_SIZE(mc_algs); i++) {
0205         if (!mc_algs[i].mc)
0206             continue;
0207         switch (mc_algs[i].type) {
0208         case CRYPTO_ALG_TYPE_SKCIPHER:
0209             crypto_unregister_skcipher(&mc_algs[i].alg.skcipher);
0210             break;
0211         }
0212     }
0213 }
0214 
0215 static int meson_crypto_probe(struct platform_device *pdev)
0216 {
0217     struct meson_dev *mc;
0218     int err, i;
0219 
0220     mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
0221     if (!mc)
0222         return -ENOMEM;
0223 
0224     mc->dev = &pdev->dev;
0225     platform_set_drvdata(pdev, mc);
0226 
0227     mc->base = devm_platform_ioremap_resource(pdev, 0);
0228     if (IS_ERR(mc->base)) {
0229         err = PTR_ERR(mc->base);
0230         dev_err(&pdev->dev, "Cannot request MMIO err=%d\n", err);
0231         return err;
0232     }
0233     mc->busclk = devm_clk_get(&pdev->dev, "blkmv");
0234     if (IS_ERR(mc->busclk)) {
0235         err = PTR_ERR(mc->busclk);
0236         dev_err(&pdev->dev, "Cannot get core clock err=%d\n", err);
0237         return err;
0238     }
0239 
0240     mc->irqs = devm_kcalloc(mc->dev, MAXFLOW, sizeof(int), GFP_KERNEL);
0241     for (i = 0; i < MAXFLOW; i++) {
0242         mc->irqs[i] = platform_get_irq(pdev, i);
0243         if (mc->irqs[i] < 0)
0244             return mc->irqs[i];
0245 
0246         err = devm_request_irq(&pdev->dev, mc->irqs[i], meson_irq_handler, 0,
0247                        "gxl-crypto", mc);
0248         if (err < 0) {
0249             dev_err(mc->dev, "Cannot request IRQ for flow %d\n", i);
0250             return err;
0251         }
0252     }
0253 
0254     err = clk_prepare_enable(mc->busclk);
0255     if (err != 0) {
0256         dev_err(&pdev->dev, "Cannot prepare_enable busclk\n");
0257         return err;
0258     }
0259 
0260     err = meson_allocate_chanlist(mc);
0261     if (err)
0262         goto error_flow;
0263 
0264     err = meson_register_algs(mc);
0265     if (err)
0266         goto error_alg;
0267 
0268 #ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
0269     mc->dbgfs_dir = debugfs_create_dir("gxl-crypto", NULL);
0270     debugfs_create_file("stats", 0444, mc->dbgfs_dir, mc, &meson_debugfs_fops);
0271 #endif
0272 
0273     return 0;
0274 error_alg:
0275     meson_unregister_algs(mc);
0276 error_flow:
0277     meson_free_chanlist(mc, MAXFLOW - 1);
0278     clk_disable_unprepare(mc->busclk);
0279     return err;
0280 }
0281 
0282 static int meson_crypto_remove(struct platform_device *pdev)
0283 {
0284     struct meson_dev *mc = platform_get_drvdata(pdev);
0285 
0286 #ifdef CONFIG_CRYPTO_DEV_AMLOGIC_GXL_DEBUG
0287     debugfs_remove_recursive(mc->dbgfs_dir);
0288 #endif
0289 
0290     meson_unregister_algs(mc);
0291 
0292     meson_free_chanlist(mc, MAXFLOW - 1);
0293 
0294     clk_disable_unprepare(mc->busclk);
0295     return 0;
0296 }
0297 
0298 static const struct of_device_id meson_crypto_of_match_table[] = {
0299     { .compatible = "amlogic,gxl-crypto", },
0300     {}
0301 };
0302 MODULE_DEVICE_TABLE(of, meson_crypto_of_match_table);
0303 
0304 static struct platform_driver meson_crypto_driver = {
0305     .probe       = meson_crypto_probe,
0306     .remove      = meson_crypto_remove,
0307     .driver      = {
0308         .name          = "gxl-crypto",
0309         .of_match_table = meson_crypto_of_match_table,
0310     },
0311 };
0312 
0313 module_platform_driver(meson_crypto_driver);
0314 
0315 MODULE_DESCRIPTION("Amlogic GXL cryptographic offloader");
0316 MODULE_LICENSE("GPL");
0317 MODULE_AUTHOR("Corentin Labbe <clabbe@baylibre.com>");