Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Support for OMAP DES and Triple DES HW acceleration.
0004  *
0005  * Copyright (c) 2013 Texas Instruments Incorporated
0006  * Author: Joel Fernandes <joelf@ti.com>
0007  */
0008 
0009 #define pr_fmt(fmt) "%s: " fmt, __func__
0010 
0011 #ifdef DEBUG
0012 #define prn(num) printk(#num "=%d\n", num)
0013 #define prx(num) printk(#num "=%x\n", num)
0014 #else
0015 #define prn(num) do { } while (0)
0016 #define prx(num)  do { } while (0)
0017 #endif
0018 
0019 #include <linux/err.h>
0020 #include <linux/module.h>
0021 #include <linux/init.h>
0022 #include <linux/errno.h>
0023 #include <linux/kernel.h>
0024 #include <linux/platform_device.h>
0025 #include <linux/scatterlist.h>
0026 #include <linux/dma-mapping.h>
0027 #include <linux/dmaengine.h>
0028 #include <linux/pm_runtime.h>
0029 #include <linux/of.h>
0030 #include <linux/of_device.h>
0031 #include <linux/of_address.h>
0032 #include <linux/io.h>
0033 #include <linux/crypto.h>
0034 #include <linux/interrupt.h>
0035 #include <crypto/scatterwalk.h>
0036 #include <crypto/internal/des.h>
0037 #include <crypto/internal/skcipher.h>
0038 #include <crypto/algapi.h>
0039 #include <crypto/engine.h>
0040 
0041 #include "omap-crypto.h"
0042 
0043 #define DST_MAXBURST            2
0044 
0045 #define DES_BLOCK_WORDS     (DES_BLOCK_SIZE >> 2)
0046 
0047 #define _calc_walked(inout) (dd->inout##_walk.offset - dd->inout##_sg->offset)
0048 
0049 #define DES_REG_KEY(dd, x)      ((dd)->pdata->key_ofs - \
0050                         ((x ^ 0x01) * 0x04))
0051 
0052 #define DES_REG_IV(dd, x)       ((dd)->pdata->iv_ofs + ((x) * 0x04))
0053 
0054 #define DES_REG_CTRL(dd)        ((dd)->pdata->ctrl_ofs)
0055 #define DES_REG_CTRL_CBC        BIT(4)
0056 #define DES_REG_CTRL_TDES       BIT(3)
0057 #define DES_REG_CTRL_DIRECTION      BIT(2)
0058 #define DES_REG_CTRL_INPUT_READY    BIT(1)
0059 #define DES_REG_CTRL_OUTPUT_READY   BIT(0)
0060 
0061 #define DES_REG_DATA_N(dd, x)       ((dd)->pdata->data_ofs + ((x) * 0x04))
0062 
0063 #define DES_REG_REV(dd)         ((dd)->pdata->rev_ofs)
0064 
0065 #define DES_REG_MASK(dd)        ((dd)->pdata->mask_ofs)
0066 
0067 #define DES_REG_LENGTH_N(x)     (0x24 + ((x) * 0x04))
0068 
0069 #define DES_REG_IRQ_STATUS(dd)         ((dd)->pdata->irq_status_ofs)
0070 #define DES_REG_IRQ_ENABLE(dd)         ((dd)->pdata->irq_enable_ofs)
0071 #define DES_REG_IRQ_DATA_IN            BIT(1)
0072 #define DES_REG_IRQ_DATA_OUT           BIT(2)
0073 
0074 #define FLAGS_MODE_MASK     0x000f
0075 #define FLAGS_ENCRYPT       BIT(0)
0076 #define FLAGS_CBC       BIT(1)
0077 #define FLAGS_INIT      BIT(4)
0078 #define FLAGS_BUSY      BIT(6)
0079 
0080 #define DEFAULT_AUTOSUSPEND_DELAY   1000
0081 
0082 #define FLAGS_IN_DATA_ST_SHIFT  8
0083 #define FLAGS_OUT_DATA_ST_SHIFT 10
0084 
0085 struct omap_des_ctx {
0086     struct crypto_engine_ctx enginectx;
0087     struct omap_des_dev *dd;
0088 
0089     int     keylen;
0090     __le32      key[(3 * DES_KEY_SIZE) / sizeof(u32)];
0091     unsigned long   flags;
0092 };
0093 
0094 struct omap_des_reqctx {
0095     unsigned long mode;
0096 };
0097 
0098 #define OMAP_DES_QUEUE_LENGTH   1
0099 #define OMAP_DES_CACHE_SIZE 0
0100 
0101 struct omap_des_algs_info {
0102     struct skcipher_alg *algs_list;
0103     unsigned int        size;
0104     unsigned int        registered;
0105 };
0106 
0107 struct omap_des_pdata {
0108     struct omap_des_algs_info   *algs_info;
0109     unsigned int    algs_info_size;
0110 
0111     void        (*trigger)(struct omap_des_dev *dd, int length);
0112 
0113     u32     key_ofs;
0114     u32     iv_ofs;
0115     u32     ctrl_ofs;
0116     u32     data_ofs;
0117     u32     rev_ofs;
0118     u32     mask_ofs;
0119     u32             irq_enable_ofs;
0120     u32             irq_status_ofs;
0121 
0122     u32     dma_enable_in;
0123     u32     dma_enable_out;
0124     u32     dma_start;
0125 
0126     u32     major_mask;
0127     u32     major_shift;
0128     u32     minor_mask;
0129     u32     minor_shift;
0130 };
0131 
0132 struct omap_des_dev {
0133     struct list_head    list;
0134     unsigned long       phys_base;
0135     void __iomem        *io_base;
0136     struct omap_des_ctx *ctx;
0137     struct device       *dev;
0138     unsigned long       flags;
0139     int         err;
0140 
0141     struct tasklet_struct   done_task;
0142 
0143     struct skcipher_request *req;
0144     struct crypto_engine        *engine;
0145     /*
0146      * total is used by PIO mode for book keeping so introduce
0147      * variable total_save as need it to calc page_order
0148      */
0149     size_t                          total;
0150     size_t                          total_save;
0151 
0152     struct scatterlist      *in_sg;
0153     struct scatterlist      *out_sg;
0154 
0155     /* Buffers for copying for unaligned cases */
0156     struct scatterlist      in_sgl;
0157     struct scatterlist      out_sgl;
0158     struct scatterlist      *orig_out;
0159 
0160     struct scatter_walk     in_walk;
0161     struct scatter_walk     out_walk;
0162     struct dma_chan     *dma_lch_in;
0163     struct dma_chan     *dma_lch_out;
0164     int         in_sg_len;
0165     int         out_sg_len;
0166     int         pio_only;
0167     const struct omap_des_pdata *pdata;
0168 };
0169 
0170 /* keep registered devices data here */
0171 static LIST_HEAD(dev_list);
0172 static DEFINE_SPINLOCK(list_lock);
0173 
0174 #ifdef DEBUG
0175 #define omap_des_read(dd, offset)                               \
0176     ({                                                              \
0177      int _read_ret;                                          \
0178      _read_ret = __raw_readl(dd->io_base + offset);          \
0179      pr_err("omap_des_read(" #offset "=%#x)= %#x\n",       \
0180          offset, _read_ret);                            \
0181      _read_ret;                                              \
0182      })
0183 #else
0184 static inline u32 omap_des_read(struct omap_des_dev *dd, u32 offset)
0185 {
0186     return __raw_readl(dd->io_base + offset);
0187 }
0188 #endif
0189 
0190 #ifdef DEBUG
0191 #define omap_des_write(dd, offset, value)                               \
0192     do {                                                            \
0193         pr_err("omap_des_write(" #offset "=%#x) value=%#x\n", \
0194                 offset, value);                                \
0195         __raw_writel(value, dd->io_base + offset);              \
0196     } while (0)
0197 #else
0198 static inline void omap_des_write(struct omap_des_dev *dd, u32 offset,
0199         u32 value)
0200 {
0201     __raw_writel(value, dd->io_base + offset);
0202 }
0203 #endif
0204 
0205 static inline void omap_des_write_mask(struct omap_des_dev *dd, u32 offset,
0206                     u32 value, u32 mask)
0207 {
0208     u32 val;
0209 
0210     val = omap_des_read(dd, offset);
0211     val &= ~mask;
0212     val |= value;
0213     omap_des_write(dd, offset, val);
0214 }
0215 
0216 static void omap_des_write_n(struct omap_des_dev *dd, u32 offset,
0217                     u32 *value, int count)
0218 {
0219     for (; count--; value++, offset += 4)
0220         omap_des_write(dd, offset, *value);
0221 }
0222 
0223 static int omap_des_hw_init(struct omap_des_dev *dd)
0224 {
0225     int err;
0226 
0227     /*
0228      * clocks are enabled when request starts and disabled when finished.
0229      * It may be long delays between requests.
0230      * Device might go to off mode to save power.
0231      */
0232     err = pm_runtime_resume_and_get(dd->dev);
0233     if (err < 0) {
0234         dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err);
0235         return err;
0236     }
0237 
0238     if (!(dd->flags & FLAGS_INIT)) {
0239         dd->flags |= FLAGS_INIT;
0240         dd->err = 0;
0241     }
0242 
0243     return 0;
0244 }
0245 
0246 static int omap_des_write_ctrl(struct omap_des_dev *dd)
0247 {
0248     unsigned int key32;
0249     int i, err;
0250     u32 val = 0, mask = 0;
0251 
0252     err = omap_des_hw_init(dd);
0253     if (err)
0254         return err;
0255 
0256     key32 = dd->ctx->keylen / sizeof(u32);
0257 
0258     /* it seems a key should always be set even if it has not changed */
0259     for (i = 0; i < key32; i++) {
0260         omap_des_write(dd, DES_REG_KEY(dd, i),
0261                    __le32_to_cpu(dd->ctx->key[i]));
0262     }
0263 
0264     if ((dd->flags & FLAGS_CBC) && dd->req->iv)
0265         omap_des_write_n(dd, DES_REG_IV(dd, 0), (void *)dd->req->iv, 2);
0266 
0267     if (dd->flags & FLAGS_CBC)
0268         val |= DES_REG_CTRL_CBC;
0269     if (dd->flags & FLAGS_ENCRYPT)
0270         val |= DES_REG_CTRL_DIRECTION;
0271     if (key32 == 6)
0272         val |= DES_REG_CTRL_TDES;
0273 
0274     mask |= DES_REG_CTRL_CBC | DES_REG_CTRL_DIRECTION | DES_REG_CTRL_TDES;
0275 
0276     omap_des_write_mask(dd, DES_REG_CTRL(dd), val, mask);
0277 
0278     return 0;
0279 }
0280 
0281 static void omap_des_dma_trigger_omap4(struct omap_des_dev *dd, int length)
0282 {
0283     u32 mask, val;
0284 
0285     omap_des_write(dd, DES_REG_LENGTH_N(0), length);
0286 
0287     val = dd->pdata->dma_start;
0288 
0289     if (dd->dma_lch_out != NULL)
0290         val |= dd->pdata->dma_enable_out;
0291     if (dd->dma_lch_in != NULL)
0292         val |= dd->pdata->dma_enable_in;
0293 
0294     mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in |
0295            dd->pdata->dma_start;
0296 
0297     omap_des_write_mask(dd, DES_REG_MASK(dd), val, mask);
0298 }
0299 
0300 static void omap_des_dma_stop(struct omap_des_dev *dd)
0301 {
0302     u32 mask;
0303 
0304     mask = dd->pdata->dma_enable_out | dd->pdata->dma_enable_in |
0305            dd->pdata->dma_start;
0306 
0307     omap_des_write_mask(dd, DES_REG_MASK(dd), 0, mask);
0308 }
0309 
0310 static struct omap_des_dev *omap_des_find_dev(struct omap_des_ctx *ctx)
0311 {
0312     struct omap_des_dev *dd = NULL, *tmp;
0313 
0314     spin_lock_bh(&list_lock);
0315     if (!ctx->dd) {
0316         list_for_each_entry(tmp, &dev_list, list) {
0317             /* FIXME: take fist available des core */
0318             dd = tmp;
0319             break;
0320         }
0321         ctx->dd = dd;
0322     } else {
0323         /* already found before */
0324         dd = ctx->dd;
0325     }
0326     spin_unlock_bh(&list_lock);
0327 
0328     return dd;
0329 }
0330 
0331 static void omap_des_dma_out_callback(void *data)
0332 {
0333     struct omap_des_dev *dd = data;
0334 
0335     /* dma_lch_out - completed */
0336     tasklet_schedule(&dd->done_task);
0337 }
0338 
0339 static int omap_des_dma_init(struct omap_des_dev *dd)
0340 {
0341     int err;
0342 
0343     dd->dma_lch_out = NULL;
0344     dd->dma_lch_in = NULL;
0345 
0346     dd->dma_lch_in = dma_request_chan(dd->dev, "rx");
0347     if (IS_ERR(dd->dma_lch_in)) {
0348         dev_err(dd->dev, "Unable to request in DMA channel\n");
0349         return PTR_ERR(dd->dma_lch_in);
0350     }
0351 
0352     dd->dma_lch_out = dma_request_chan(dd->dev, "tx");
0353     if (IS_ERR(dd->dma_lch_out)) {
0354         dev_err(dd->dev, "Unable to request out DMA channel\n");
0355         err = PTR_ERR(dd->dma_lch_out);
0356         goto err_dma_out;
0357     }
0358 
0359     return 0;
0360 
0361 err_dma_out:
0362     dma_release_channel(dd->dma_lch_in);
0363 
0364     return err;
0365 }
0366 
0367 static void omap_des_dma_cleanup(struct omap_des_dev *dd)
0368 {
0369     if (dd->pio_only)
0370         return;
0371 
0372     dma_release_channel(dd->dma_lch_out);
0373     dma_release_channel(dd->dma_lch_in);
0374 }
0375 
0376 static int omap_des_crypt_dma(struct crypto_tfm *tfm,
0377         struct scatterlist *in_sg, struct scatterlist *out_sg,
0378         int in_sg_len, int out_sg_len)
0379 {
0380     struct omap_des_ctx *ctx = crypto_tfm_ctx(tfm);
0381     struct omap_des_dev *dd = ctx->dd;
0382     struct dma_async_tx_descriptor *tx_in, *tx_out;
0383     struct dma_slave_config cfg;
0384     int ret;
0385 
0386     if (dd->pio_only) {
0387         scatterwalk_start(&dd->in_walk, dd->in_sg);
0388         scatterwalk_start(&dd->out_walk, dd->out_sg);
0389 
0390         /* Enable DATAIN interrupt and let it take
0391            care of the rest */
0392         omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2);
0393         return 0;
0394     }
0395 
0396     dma_sync_sg_for_device(dd->dev, dd->in_sg, in_sg_len, DMA_TO_DEVICE);
0397 
0398     memset(&cfg, 0, sizeof(cfg));
0399 
0400     cfg.src_addr = dd->phys_base + DES_REG_DATA_N(dd, 0);
0401     cfg.dst_addr = dd->phys_base + DES_REG_DATA_N(dd, 0);
0402     cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0403     cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0404     cfg.src_maxburst = DST_MAXBURST;
0405     cfg.dst_maxburst = DST_MAXBURST;
0406 
0407     /* IN */
0408     ret = dmaengine_slave_config(dd->dma_lch_in, &cfg);
0409     if (ret) {
0410         dev_err(dd->dev, "can't configure IN dmaengine slave: %d\n",
0411             ret);
0412         return ret;
0413     }
0414 
0415     tx_in = dmaengine_prep_slave_sg(dd->dma_lch_in, in_sg, in_sg_len,
0416                     DMA_MEM_TO_DEV,
0417                     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
0418     if (!tx_in) {
0419         dev_err(dd->dev, "IN prep_slave_sg() failed\n");
0420         return -EINVAL;
0421     }
0422 
0423     /* No callback necessary */
0424     tx_in->callback_param = dd;
0425 
0426     /* OUT */
0427     ret = dmaengine_slave_config(dd->dma_lch_out, &cfg);
0428     if (ret) {
0429         dev_err(dd->dev, "can't configure OUT dmaengine slave: %d\n",
0430             ret);
0431         return ret;
0432     }
0433 
0434     tx_out = dmaengine_prep_slave_sg(dd->dma_lch_out, out_sg, out_sg_len,
0435                     DMA_DEV_TO_MEM,
0436                     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
0437     if (!tx_out) {
0438         dev_err(dd->dev, "OUT prep_slave_sg() failed\n");
0439         return -EINVAL;
0440     }
0441 
0442     tx_out->callback = omap_des_dma_out_callback;
0443     tx_out->callback_param = dd;
0444 
0445     dmaengine_submit(tx_in);
0446     dmaengine_submit(tx_out);
0447 
0448     dma_async_issue_pending(dd->dma_lch_in);
0449     dma_async_issue_pending(dd->dma_lch_out);
0450 
0451     /* start DMA */
0452     dd->pdata->trigger(dd, dd->total);
0453 
0454     return 0;
0455 }
0456 
0457 static int omap_des_crypt_dma_start(struct omap_des_dev *dd)
0458 {
0459     struct crypto_tfm *tfm = crypto_skcipher_tfm(
0460                     crypto_skcipher_reqtfm(dd->req));
0461     int err;
0462 
0463     pr_debug("total: %zd\n", dd->total);
0464 
0465     if (!dd->pio_only) {
0466         err = dma_map_sg(dd->dev, dd->in_sg, dd->in_sg_len,
0467                  DMA_TO_DEVICE);
0468         if (!err) {
0469             dev_err(dd->dev, "dma_map_sg() error\n");
0470             return -EINVAL;
0471         }
0472 
0473         err = dma_map_sg(dd->dev, dd->out_sg, dd->out_sg_len,
0474                  DMA_FROM_DEVICE);
0475         if (!err) {
0476             dev_err(dd->dev, "dma_map_sg() error\n");
0477             return -EINVAL;
0478         }
0479     }
0480 
0481     err = omap_des_crypt_dma(tfm, dd->in_sg, dd->out_sg, dd->in_sg_len,
0482                  dd->out_sg_len);
0483     if (err && !dd->pio_only) {
0484         dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
0485         dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len,
0486                  DMA_FROM_DEVICE);
0487     }
0488 
0489     return err;
0490 }
0491 
0492 static void omap_des_finish_req(struct omap_des_dev *dd, int err)
0493 {
0494     struct skcipher_request *req = dd->req;
0495 
0496     pr_debug("err: %d\n", err);
0497 
0498     crypto_finalize_skcipher_request(dd->engine, req, err);
0499 
0500     pm_runtime_mark_last_busy(dd->dev);
0501     pm_runtime_put_autosuspend(dd->dev);
0502 }
0503 
0504 static int omap_des_crypt_dma_stop(struct omap_des_dev *dd)
0505 {
0506     pr_debug("total: %zd\n", dd->total);
0507 
0508     omap_des_dma_stop(dd);
0509 
0510     dmaengine_terminate_all(dd->dma_lch_in);
0511     dmaengine_terminate_all(dd->dma_lch_out);
0512 
0513     return 0;
0514 }
0515 
0516 static int omap_des_handle_queue(struct omap_des_dev *dd,
0517                  struct skcipher_request *req)
0518 {
0519     if (req)
0520         return crypto_transfer_skcipher_request_to_engine(dd->engine, req);
0521 
0522     return 0;
0523 }
0524 
0525 static int omap_des_prepare_req(struct crypto_engine *engine,
0526                 void *areq)
0527 {
0528     struct skcipher_request *req = container_of(areq, struct skcipher_request, base);
0529     struct omap_des_ctx *ctx = crypto_skcipher_ctx(
0530             crypto_skcipher_reqtfm(req));
0531     struct omap_des_dev *dd = omap_des_find_dev(ctx);
0532     struct omap_des_reqctx *rctx;
0533     int ret;
0534     u16 flags;
0535 
0536     if (!dd)
0537         return -ENODEV;
0538 
0539     /* assign new request to device */
0540     dd->req = req;
0541     dd->total = req->cryptlen;
0542     dd->total_save = req->cryptlen;
0543     dd->in_sg = req->src;
0544     dd->out_sg = req->dst;
0545     dd->orig_out = req->dst;
0546 
0547     flags = OMAP_CRYPTO_COPY_DATA;
0548     if (req->src == req->dst)
0549         flags |= OMAP_CRYPTO_FORCE_COPY;
0550 
0551     ret = omap_crypto_align_sg(&dd->in_sg, dd->total, DES_BLOCK_SIZE,
0552                    &dd->in_sgl, flags,
0553                    FLAGS_IN_DATA_ST_SHIFT, &dd->flags);
0554     if (ret)
0555         return ret;
0556 
0557     ret = omap_crypto_align_sg(&dd->out_sg, dd->total, DES_BLOCK_SIZE,
0558                    &dd->out_sgl, 0,
0559                    FLAGS_OUT_DATA_ST_SHIFT, &dd->flags);
0560     if (ret)
0561         return ret;
0562 
0563     dd->in_sg_len = sg_nents_for_len(dd->in_sg, dd->total);
0564     if (dd->in_sg_len < 0)
0565         return dd->in_sg_len;
0566 
0567     dd->out_sg_len = sg_nents_for_len(dd->out_sg, dd->total);
0568     if (dd->out_sg_len < 0)
0569         return dd->out_sg_len;
0570 
0571     rctx = skcipher_request_ctx(req);
0572     ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
0573     rctx->mode &= FLAGS_MODE_MASK;
0574     dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
0575 
0576     dd->ctx = ctx;
0577     ctx->dd = dd;
0578 
0579     return omap_des_write_ctrl(dd);
0580 }
0581 
0582 static int omap_des_crypt_req(struct crypto_engine *engine,
0583                   void *areq)
0584 {
0585     struct skcipher_request *req = container_of(areq, struct skcipher_request, base);
0586     struct omap_des_ctx *ctx = crypto_skcipher_ctx(
0587             crypto_skcipher_reqtfm(req));
0588     struct omap_des_dev *dd = omap_des_find_dev(ctx);
0589 
0590     if (!dd)
0591         return -ENODEV;
0592 
0593     return omap_des_crypt_dma_start(dd);
0594 }
0595 
0596 static void omap_des_done_task(unsigned long data)
0597 {
0598     struct omap_des_dev *dd = (struct omap_des_dev *)data;
0599     int i;
0600 
0601     pr_debug("enter done_task\n");
0602 
0603     if (!dd->pio_only) {
0604         dma_sync_sg_for_device(dd->dev, dd->out_sg, dd->out_sg_len,
0605                        DMA_FROM_DEVICE);
0606         dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
0607         dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len,
0608                  DMA_FROM_DEVICE);
0609         omap_des_crypt_dma_stop(dd);
0610     }
0611 
0612     omap_crypto_cleanup(&dd->in_sgl, NULL, 0, dd->total_save,
0613                 FLAGS_IN_DATA_ST_SHIFT, dd->flags);
0614 
0615     omap_crypto_cleanup(&dd->out_sgl, dd->orig_out, 0, dd->total_save,
0616                 FLAGS_OUT_DATA_ST_SHIFT, dd->flags);
0617 
0618     if ((dd->flags & FLAGS_CBC) && dd->req->iv)
0619         for (i = 0; i < 2; i++)
0620             ((u32 *)dd->req->iv)[i] =
0621                 omap_des_read(dd, DES_REG_IV(dd, i));
0622 
0623     omap_des_finish_req(dd, 0);
0624 
0625     pr_debug("exit\n");
0626 }
0627 
0628 static int omap_des_crypt(struct skcipher_request *req, unsigned long mode)
0629 {
0630     struct omap_des_ctx *ctx = crypto_skcipher_ctx(
0631             crypto_skcipher_reqtfm(req));
0632     struct omap_des_reqctx *rctx = skcipher_request_ctx(req);
0633     struct omap_des_dev *dd;
0634 
0635     pr_debug("nbytes: %d, enc: %d, cbc: %d\n", req->cryptlen,
0636          !!(mode & FLAGS_ENCRYPT),
0637          !!(mode & FLAGS_CBC));
0638 
0639     if (!req->cryptlen)
0640         return 0;
0641 
0642     if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE))
0643         return -EINVAL;
0644 
0645     dd = omap_des_find_dev(ctx);
0646     if (!dd)
0647         return -ENODEV;
0648 
0649     rctx->mode = mode;
0650 
0651     return omap_des_handle_queue(dd, req);
0652 }
0653 
0654 /* ********************** ALG API ************************************ */
0655 
0656 static int omap_des_setkey(struct crypto_skcipher *cipher, const u8 *key,
0657                unsigned int keylen)
0658 {
0659     struct omap_des_ctx *ctx = crypto_skcipher_ctx(cipher);
0660     int err;
0661 
0662     pr_debug("enter, keylen: %d\n", keylen);
0663 
0664     err = verify_skcipher_des_key(cipher, key);
0665     if (err)
0666         return err;
0667 
0668     memcpy(ctx->key, key, keylen);
0669     ctx->keylen = keylen;
0670 
0671     return 0;
0672 }
0673 
0674 static int omap_des3_setkey(struct crypto_skcipher *cipher, const u8 *key,
0675                 unsigned int keylen)
0676 {
0677     struct omap_des_ctx *ctx = crypto_skcipher_ctx(cipher);
0678     int err;
0679 
0680     pr_debug("enter, keylen: %d\n", keylen);
0681 
0682     err = verify_skcipher_des3_key(cipher, key);
0683     if (err)
0684         return err;
0685 
0686     memcpy(ctx->key, key, keylen);
0687     ctx->keylen = keylen;
0688 
0689     return 0;
0690 }
0691 
0692 static int omap_des_ecb_encrypt(struct skcipher_request *req)
0693 {
0694     return omap_des_crypt(req, FLAGS_ENCRYPT);
0695 }
0696 
0697 static int omap_des_ecb_decrypt(struct skcipher_request *req)
0698 {
0699     return omap_des_crypt(req, 0);
0700 }
0701 
0702 static int omap_des_cbc_encrypt(struct skcipher_request *req)
0703 {
0704     return omap_des_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC);
0705 }
0706 
0707 static int omap_des_cbc_decrypt(struct skcipher_request *req)
0708 {
0709     return omap_des_crypt(req, FLAGS_CBC);
0710 }
0711 
0712 static int omap_des_prepare_req(struct crypto_engine *engine,
0713                 void *areq);
0714 static int omap_des_crypt_req(struct crypto_engine *engine,
0715                   void *areq);
0716 
0717 static int omap_des_init_tfm(struct crypto_skcipher *tfm)
0718 {
0719     struct omap_des_ctx *ctx = crypto_skcipher_ctx(tfm);
0720 
0721     pr_debug("enter\n");
0722 
0723     crypto_skcipher_set_reqsize(tfm, sizeof(struct omap_des_reqctx));
0724 
0725     ctx->enginectx.op.prepare_request = omap_des_prepare_req;
0726     ctx->enginectx.op.unprepare_request = NULL;
0727     ctx->enginectx.op.do_one_request = omap_des_crypt_req;
0728 
0729     return 0;
0730 }
0731 
0732 /* ********************** ALGS ************************************ */
0733 
0734 static struct skcipher_alg algs_ecb_cbc[] = {
0735 {
0736     .base.cra_name      = "ecb(des)",
0737     .base.cra_driver_name   = "ecb-des-omap",
0738     .base.cra_priority  = 300,
0739     .base.cra_flags     = CRYPTO_ALG_KERN_DRIVER_ONLY |
0740                   CRYPTO_ALG_ASYNC,
0741     .base.cra_blocksize = DES_BLOCK_SIZE,
0742     .base.cra_ctxsize   = sizeof(struct omap_des_ctx),
0743     .base.cra_module    = THIS_MODULE,
0744 
0745     .min_keysize        = DES_KEY_SIZE,
0746     .max_keysize        = DES_KEY_SIZE,
0747     .setkey         = omap_des_setkey,
0748     .encrypt        = omap_des_ecb_encrypt,
0749     .decrypt        = omap_des_ecb_decrypt,
0750     .init           = omap_des_init_tfm,
0751 },
0752 {
0753     .base.cra_name      = "cbc(des)",
0754     .base.cra_driver_name   = "cbc-des-omap",
0755     .base.cra_priority  = 300,
0756     .base.cra_flags     = CRYPTO_ALG_KERN_DRIVER_ONLY |
0757                   CRYPTO_ALG_ASYNC,
0758     .base.cra_blocksize = DES_BLOCK_SIZE,
0759     .base.cra_ctxsize   = sizeof(struct omap_des_ctx),
0760     .base.cra_module    = THIS_MODULE,
0761 
0762     .min_keysize        = DES_KEY_SIZE,
0763     .max_keysize        = DES_KEY_SIZE,
0764     .ivsize         = DES_BLOCK_SIZE,
0765     .setkey         = omap_des_setkey,
0766     .encrypt        = omap_des_cbc_encrypt,
0767     .decrypt        = omap_des_cbc_decrypt,
0768     .init           = omap_des_init_tfm,
0769 },
0770 {
0771     .base.cra_name      = "ecb(des3_ede)",
0772     .base.cra_driver_name   = "ecb-des3-omap",
0773     .base.cra_priority  = 300,
0774     .base.cra_flags     = CRYPTO_ALG_KERN_DRIVER_ONLY |
0775                   CRYPTO_ALG_ASYNC,
0776     .base.cra_blocksize = DES3_EDE_BLOCK_SIZE,
0777     .base.cra_ctxsize   = sizeof(struct omap_des_ctx),
0778     .base.cra_module    = THIS_MODULE,
0779 
0780     .min_keysize        = DES3_EDE_KEY_SIZE,
0781     .max_keysize        = DES3_EDE_KEY_SIZE,
0782     .setkey         = omap_des3_setkey,
0783     .encrypt        = omap_des_ecb_encrypt,
0784     .decrypt        = omap_des_ecb_decrypt,
0785     .init           = omap_des_init_tfm,
0786 },
0787 {
0788     .base.cra_name      = "cbc(des3_ede)",
0789     .base.cra_driver_name   = "cbc-des3-omap",
0790     .base.cra_priority  = 300,
0791     .base.cra_flags     = CRYPTO_ALG_KERN_DRIVER_ONLY |
0792                   CRYPTO_ALG_ASYNC,
0793     .base.cra_blocksize = DES3_EDE_BLOCK_SIZE,
0794     .base.cra_ctxsize   = sizeof(struct omap_des_ctx),
0795     .base.cra_module    = THIS_MODULE,
0796 
0797     .min_keysize        = DES3_EDE_KEY_SIZE,
0798     .max_keysize        = DES3_EDE_KEY_SIZE,
0799     .ivsize         = DES3_EDE_BLOCK_SIZE,
0800     .setkey         = omap_des3_setkey,
0801     .encrypt        = omap_des_cbc_encrypt,
0802     .decrypt        = omap_des_cbc_decrypt,
0803     .init           = omap_des_init_tfm,
0804 }
0805 };
0806 
0807 static struct omap_des_algs_info omap_des_algs_info_ecb_cbc[] = {
0808     {
0809         .algs_list  = algs_ecb_cbc,
0810         .size       = ARRAY_SIZE(algs_ecb_cbc),
0811     },
0812 };
0813 
0814 #ifdef CONFIG_OF
0815 static const struct omap_des_pdata omap_des_pdata_omap4 = {
0816     .algs_info  = omap_des_algs_info_ecb_cbc,
0817     .algs_info_size = ARRAY_SIZE(omap_des_algs_info_ecb_cbc),
0818     .trigger    = omap_des_dma_trigger_omap4,
0819     .key_ofs    = 0x14,
0820     .iv_ofs     = 0x18,
0821     .ctrl_ofs   = 0x20,
0822     .data_ofs   = 0x28,
0823     .rev_ofs    = 0x30,
0824     .mask_ofs   = 0x34,
0825     .irq_status_ofs = 0x3c,
0826     .irq_enable_ofs = 0x40,
0827     .dma_enable_in  = BIT(5),
0828     .dma_enable_out = BIT(6),
0829     .major_mask = 0x0700,
0830     .major_shift    = 8,
0831     .minor_mask = 0x003f,
0832     .minor_shift    = 0,
0833 };
0834 
0835 static irqreturn_t omap_des_irq(int irq, void *dev_id)
0836 {
0837     struct omap_des_dev *dd = dev_id;
0838     u32 status, i;
0839     u32 *src, *dst;
0840 
0841     status = omap_des_read(dd, DES_REG_IRQ_STATUS(dd));
0842     if (status & DES_REG_IRQ_DATA_IN) {
0843         omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0);
0844 
0845         BUG_ON(!dd->in_sg);
0846 
0847         BUG_ON(_calc_walked(in) > dd->in_sg->length);
0848 
0849         src = sg_virt(dd->in_sg) + _calc_walked(in);
0850 
0851         for (i = 0; i < DES_BLOCK_WORDS; i++) {
0852             omap_des_write(dd, DES_REG_DATA_N(dd, i), *src);
0853 
0854             scatterwalk_advance(&dd->in_walk, 4);
0855             if (dd->in_sg->length == _calc_walked(in)) {
0856                 dd->in_sg = sg_next(dd->in_sg);
0857                 if (dd->in_sg) {
0858                     scatterwalk_start(&dd->in_walk,
0859                               dd->in_sg);
0860                     src = sg_virt(dd->in_sg) +
0861                           _calc_walked(in);
0862                 }
0863             } else {
0864                 src++;
0865             }
0866         }
0867 
0868         /* Clear IRQ status */
0869         status &= ~DES_REG_IRQ_DATA_IN;
0870         omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status);
0871 
0872         /* Enable DATA_OUT interrupt */
0873         omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x4);
0874 
0875     } else if (status & DES_REG_IRQ_DATA_OUT) {
0876         omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x0);
0877 
0878         BUG_ON(!dd->out_sg);
0879 
0880         BUG_ON(_calc_walked(out) > dd->out_sg->length);
0881 
0882         dst = sg_virt(dd->out_sg) + _calc_walked(out);
0883 
0884         for (i = 0; i < DES_BLOCK_WORDS; i++) {
0885             *dst = omap_des_read(dd, DES_REG_DATA_N(dd, i));
0886             scatterwalk_advance(&dd->out_walk, 4);
0887             if (dd->out_sg->length == _calc_walked(out)) {
0888                 dd->out_sg = sg_next(dd->out_sg);
0889                 if (dd->out_sg) {
0890                     scatterwalk_start(&dd->out_walk,
0891                               dd->out_sg);
0892                     dst = sg_virt(dd->out_sg) +
0893                           _calc_walked(out);
0894                 }
0895             } else {
0896                 dst++;
0897             }
0898         }
0899 
0900         BUG_ON(dd->total < DES_BLOCK_SIZE);
0901 
0902         dd->total -= DES_BLOCK_SIZE;
0903 
0904         /* Clear IRQ status */
0905         status &= ~DES_REG_IRQ_DATA_OUT;
0906         omap_des_write(dd, DES_REG_IRQ_STATUS(dd), status);
0907 
0908         if (!dd->total)
0909             /* All bytes read! */
0910             tasklet_schedule(&dd->done_task);
0911         else
0912             /* Enable DATA_IN interrupt for next block */
0913             omap_des_write(dd, DES_REG_IRQ_ENABLE(dd), 0x2);
0914     }
0915 
0916     return IRQ_HANDLED;
0917 }
0918 
0919 static const struct of_device_id omap_des_of_match[] = {
0920     {
0921         .compatible = "ti,omap4-des",
0922         .data       = &omap_des_pdata_omap4,
0923     },
0924     {},
0925 };
0926 MODULE_DEVICE_TABLE(of, omap_des_of_match);
0927 
0928 static int omap_des_get_of(struct omap_des_dev *dd,
0929         struct platform_device *pdev)
0930 {
0931 
0932     dd->pdata = of_device_get_match_data(&pdev->dev);
0933     if (!dd->pdata) {
0934         dev_err(&pdev->dev, "no compatible OF match\n");
0935         return -EINVAL;
0936     }
0937 
0938     return 0;
0939 }
0940 #else
0941 static int omap_des_get_of(struct omap_des_dev *dd,
0942         struct device *dev)
0943 {
0944     return -EINVAL;
0945 }
0946 #endif
0947 
0948 static int omap_des_get_pdev(struct omap_des_dev *dd,
0949         struct platform_device *pdev)
0950 {
0951     /* non-DT devices get pdata from pdev */
0952     dd->pdata = pdev->dev.platform_data;
0953 
0954     return 0;
0955 }
0956 
0957 static int omap_des_probe(struct platform_device *pdev)
0958 {
0959     struct device *dev = &pdev->dev;
0960     struct omap_des_dev *dd;
0961     struct skcipher_alg *algp;
0962     struct resource *res;
0963     int err = -ENOMEM, i, j, irq = -1;
0964     u32 reg;
0965 
0966     dd = devm_kzalloc(dev, sizeof(struct omap_des_dev), GFP_KERNEL);
0967     if (dd == NULL) {
0968         dev_err(dev, "unable to alloc data struct.\n");
0969         goto err_data;
0970     }
0971     dd->dev = dev;
0972     platform_set_drvdata(pdev, dd);
0973 
0974     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0975     if (!res) {
0976         dev_err(dev, "no MEM resource info\n");
0977         goto err_res;
0978     }
0979 
0980     err = (dev->of_node) ? omap_des_get_of(dd, pdev) :
0981                    omap_des_get_pdev(dd, pdev);
0982     if (err)
0983         goto err_res;
0984 
0985     dd->io_base = devm_ioremap_resource(dev, res);
0986     if (IS_ERR(dd->io_base)) {
0987         err = PTR_ERR(dd->io_base);
0988         goto err_res;
0989     }
0990     dd->phys_base = res->start;
0991 
0992     pm_runtime_use_autosuspend(dev);
0993     pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY);
0994 
0995     pm_runtime_enable(dev);
0996     err = pm_runtime_resume_and_get(dev);
0997     if (err < 0) {
0998         dev_err(dd->dev, "%s: failed to get_sync(%d)\n", __func__, err);
0999         goto err_get;
1000     }
1001 
1002     omap_des_dma_stop(dd);
1003 
1004     reg = omap_des_read(dd, DES_REG_REV(dd));
1005 
1006     pm_runtime_put_sync(dev);
1007 
1008     dev_info(dev, "OMAP DES hw accel rev: %u.%u\n",
1009          (reg & dd->pdata->major_mask) >> dd->pdata->major_shift,
1010          (reg & dd->pdata->minor_mask) >> dd->pdata->minor_shift);
1011 
1012     tasklet_init(&dd->done_task, omap_des_done_task, (unsigned long)dd);
1013 
1014     err = omap_des_dma_init(dd);
1015     if (err == -EPROBE_DEFER) {
1016         goto err_irq;
1017     } else if (err && DES_REG_IRQ_STATUS(dd) && DES_REG_IRQ_ENABLE(dd)) {
1018         dd->pio_only = 1;
1019 
1020         irq = platform_get_irq(pdev, 0);
1021         if (irq < 0) {
1022             err = irq;
1023             goto err_irq;
1024         }
1025 
1026         err = devm_request_irq(dev, irq, omap_des_irq, 0,
1027                 dev_name(dev), dd);
1028         if (err) {
1029             dev_err(dev, "Unable to grab omap-des IRQ\n");
1030             goto err_irq;
1031         }
1032     }
1033 
1034 
1035     INIT_LIST_HEAD(&dd->list);
1036     spin_lock_bh(&list_lock);
1037     list_add_tail(&dd->list, &dev_list);
1038     spin_unlock_bh(&list_lock);
1039 
1040     /* Initialize des crypto engine */
1041     dd->engine = crypto_engine_alloc_init(dev, 1);
1042     if (!dd->engine) {
1043         err = -ENOMEM;
1044         goto err_engine;
1045     }
1046 
1047     err = crypto_engine_start(dd->engine);
1048     if (err)
1049         goto err_engine;
1050 
1051     for (i = 0; i < dd->pdata->algs_info_size; i++) {
1052         for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
1053             algp = &dd->pdata->algs_info[i].algs_list[j];
1054 
1055             pr_debug("reg alg: %s\n", algp->base.cra_name);
1056 
1057             err = crypto_register_skcipher(algp);
1058             if (err)
1059                 goto err_algs;
1060 
1061             dd->pdata->algs_info[i].registered++;
1062         }
1063     }
1064 
1065     return 0;
1066 
1067 err_algs:
1068     for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
1069         for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
1070             crypto_unregister_skcipher(
1071                     &dd->pdata->algs_info[i].algs_list[j]);
1072 
1073 err_engine:
1074     if (dd->engine)
1075         crypto_engine_exit(dd->engine);
1076 
1077     omap_des_dma_cleanup(dd);
1078 err_irq:
1079     tasklet_kill(&dd->done_task);
1080 err_get:
1081     pm_runtime_disable(dev);
1082 err_res:
1083     dd = NULL;
1084 err_data:
1085     dev_err(dev, "initialization failed.\n");
1086     return err;
1087 }
1088 
1089 static int omap_des_remove(struct platform_device *pdev)
1090 {
1091     struct omap_des_dev *dd = platform_get_drvdata(pdev);
1092     int i, j;
1093 
1094     spin_lock_bh(&list_lock);
1095     list_del(&dd->list);
1096     spin_unlock_bh(&list_lock);
1097 
1098     for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
1099         for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
1100             crypto_unregister_skcipher(
1101                     &dd->pdata->algs_info[i].algs_list[j]);
1102 
1103     tasklet_kill(&dd->done_task);
1104     omap_des_dma_cleanup(dd);
1105     pm_runtime_disable(dd->dev);
1106 
1107     return 0;
1108 }
1109 
1110 #ifdef CONFIG_PM_SLEEP
1111 static int omap_des_suspend(struct device *dev)
1112 {
1113     pm_runtime_put_sync(dev);
1114     return 0;
1115 }
1116 
1117 static int omap_des_resume(struct device *dev)
1118 {
1119     int err;
1120 
1121     err = pm_runtime_resume_and_get(dev);
1122     if (err < 0) {
1123         dev_err(dev, "%s: failed to get_sync(%d)\n", __func__, err);
1124         return err;
1125     }
1126     return 0;
1127 }
1128 #endif
1129 
1130 static SIMPLE_DEV_PM_OPS(omap_des_pm_ops, omap_des_suspend, omap_des_resume);
1131 
1132 static struct platform_driver omap_des_driver = {
1133     .probe  = omap_des_probe,
1134     .remove = omap_des_remove,
1135     .driver = {
1136         .name   = "omap-des",
1137         .pm = &omap_des_pm_ops,
1138         .of_match_table = of_match_ptr(omap_des_of_match),
1139     },
1140 };
1141 
1142 module_platform_driver(omap_des_driver);
1143 
1144 MODULE_DESCRIPTION("OMAP DES hw acceleration support.");
1145 MODULE_LICENSE("GPL v2");
1146 MODULE_AUTHOR("Joel Fernandes <joelf@ti.com>");