Merge tag 'led-fix-for-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / crypto / s5p-sss.c
index faa282074e5aa4a611b9ee137fc393d3fecc4a3c..0064be0e3941b3fe741241705a24d0ee521193e3 100644 (file)
@@ -249,8 +249,8 @@ struct s5p_aes_reqctx {
 struct s5p_aes_ctx {
        struct s5p_aes_dev              *dev;
 
-       uint8_t                         aes_key[AES_MAX_KEY_SIZE];
-       uint8_t                         nonce[CTR_RFC3686_NONCE_SIZE];
+       u8                              aes_key[AES_MAX_KEY_SIZE];
+       u8                              nonce[CTR_RFC3686_NONCE_SIZE];
        int                             keylen;
 };
 
@@ -475,9 +475,9 @@ static void s5p_sg_done(struct s5p_aes_dev *dev)
 }
 
 /* Calls the completion. Cannot be called with dev->lock hold. */
-static void s5p_aes_complete(struct s5p_aes_dev *dev, int err)
+static void s5p_aes_complete(struct ablkcipher_request *req, int err)
 {
-       dev->req->base.complete(&dev->req->base, err);
+       req->base.complete(&req->base, err);
 }
 
 static void s5p_unset_outdata(struct s5p_aes_dev *dev)
@@ -491,7 +491,7 @@ static void s5p_unset_indata(struct s5p_aes_dev *dev)
 }
 
 static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src,
-                           struct scatterlist **dst)
+                          struct scatterlist **dst)
 {
        void *pages;
        int len;
@@ -518,46 +518,28 @@ static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src,
 
 static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
 {
-       int err;
-
-       if (!sg->length) {
-               err = -EINVAL;
-               goto exit;
-       }
+       if (!sg->length)
+               return -EINVAL;
 
-       err = dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE);
-       if (!err) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       if (!dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE))
+               return -ENOMEM;
 
        dev->sg_dst = sg;
-       err = 0;
 
-exit:
-       return err;
+       return 0;
 }
 
 static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
 {
-       int err;
-
-       if (!sg->length) {
-               err = -EINVAL;
-               goto exit;
-       }
+       if (!sg->length)
+               return -EINVAL;
 
-       err = dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE);
-       if (!err) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       if (!dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE))
+               return -ENOMEM;
 
        dev->sg_src = sg;
-       err = 0;
 
-exit:
-       return err;
+       return 0;
 }
 
 /*
@@ -655,14 +637,14 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
 {
        struct platform_device *pdev = dev_id;
        struct s5p_aes_dev *dev = platform_get_drvdata(pdev);
+       struct ablkcipher_request *req;
        int err_dma_tx = 0;
        int err_dma_rx = 0;
        int err_dma_hx = 0;
        bool tx_end = false;
        bool hx_end = false;
        unsigned long flags;
-       uint32_t status;
-       u32 st_bits;
+       u32 status, st_bits;
        int err;
 
        spin_lock_irqsave(&dev->lock, flags);
@@ -727,7 +709,7 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
 
                spin_unlock_irqrestore(&dev->lock, flags);
 
-               s5p_aes_complete(dev, 0);
+               s5p_aes_complete(dev->req, 0);
                /* Device is still busy */
                tasklet_schedule(&dev->tasklet);
        } else {
@@ -752,11 +734,12 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
 error:
        s5p_sg_done(dev);
        dev->busy = false;
+       req = dev->req;
        if (err_dma_hx == 1)
                s5p_set_dma_hashdata(dev, dev->hash_sg_iter);
 
        spin_unlock_irqrestore(&dev->lock, flags);
-       s5p_aes_complete(dev, err);
+       s5p_aes_complete(req, err);
 
 hash_irq_end:
        /*
@@ -1830,7 +1813,7 @@ static struct ahash_alg algs_sha1_md5_sha256[] = {
 };
 
 static void s5p_set_aes(struct s5p_aes_dev *dev,
-                       const uint8_t *key, const uint8_t *iv,
+                       const u8 *key, const u8 *iv, const u8 *ctr,
                        unsigned int keylen)
 {
        void __iomem *keystart;
@@ -1838,6 +1821,9 @@ static void s5p_set_aes(struct s5p_aes_dev *dev,
        if (iv)
                memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10);
 
+       if (ctr)
+               memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_CNT_DATA(0), ctr, 0x10);
+
        if (keylen == AES_KEYSIZE_256)
                keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0);
        else if (keylen == AES_KEYSIZE_192)
@@ -1887,7 +1873,7 @@ static int s5p_set_indata_start(struct s5p_aes_dev *dev,
 }
 
 static int s5p_set_outdata_start(struct s5p_aes_dev *dev,
-                               struct ablkcipher_request *req)
+                                struct ablkcipher_request *req)
 {
        struct scatterlist *sg;
        int err;
@@ -1916,11 +1902,12 @@ static int s5p_set_outdata_start(struct s5p_aes_dev *dev,
 static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
 {
        struct ablkcipher_request *req = dev->req;
-       uint32_t aes_control;
+       u32 aes_control;
        unsigned long flags;
        int err;
-       u8 *iv;
+       u8 *iv, *ctr;
 
+       /* This sets bit [13:12] to 00, which selects 128-bit counter */
        aes_control = SSS_AES_KEY_CHANGE_MODE;
        if (mode & FLAGS_AES_DECRYPT)
                aes_control |= SSS_AES_MODE_DECRYPT;
@@ -1928,11 +1915,14 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
        if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) {
                aes_control |= SSS_AES_CHAIN_MODE_CBC;
                iv = req->info;
+               ctr = NULL;
        } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) {
                aes_control |= SSS_AES_CHAIN_MODE_CTR;
-               iv = req->info;
+               iv = NULL;
+               ctr = req->info;
        } else {
                iv = NULL; /* AES_ECB */
+               ctr = NULL;
        }
 
        if (dev->ctx->keylen == AES_KEYSIZE_192)
@@ -1964,7 +1954,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
                goto outdata_error;
 
        SSS_AES_WRITE(dev, AES_CONTROL, aes_control);
-       s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen);
+       s5p_set_aes(dev, dev->ctx->aes_key, iv, ctr, dev->ctx->keylen);
 
        s5p_set_dma_indata(dev,  dev->sg_src);
        s5p_set_dma_outdata(dev, dev->sg_dst);
@@ -1983,7 +1973,7 @@ indata_error:
        s5p_sg_done(dev);
        dev->busy = false;
        spin_unlock_irqrestore(&dev->lock, flags);
-       s5p_aes_complete(dev, err);
+       s5p_aes_complete(req, err);
 }
 
 static void s5p_tasklet_cb(unsigned long data)
@@ -2024,7 +2014,7 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev,
        err = ablkcipher_enqueue_request(&dev->queue, req);
        if (dev->busy) {
                spin_unlock_irqrestore(&dev->lock, flags);
-               goto exit;
+               return err;
        }
        dev->busy = true;
 
@@ -2032,7 +2022,6 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev,
 
        tasklet_schedule(&dev->tasklet);
 
-exit:
        return err;
 }
 
@@ -2043,7 +2032,8 @@ static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
        struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
        struct s5p_aes_dev *dev = ctx->dev;
 
-       if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
+       if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE) &&
+                       ((mode & FLAGS_AES_MODE_MASK) != FLAGS_AES_CTR)) {
                dev_err(dev->dev, "request size is not exact amount of AES blocks\n");
                return -EINVAL;
        }
@@ -2054,7 +2044,7 @@ static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
 }
 
 static int s5p_aes_setkey(struct crypto_ablkcipher *cipher,
-                         const uint8_t *key, unsigned int keylen)
+                         const u8 *key, unsigned int keylen)
 {
        struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
        struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm);
@@ -2090,6 +2080,11 @@ static int s5p_aes_cbc_decrypt(struct ablkcipher_request *req)
        return s5p_aes_crypt(req, FLAGS_AES_DECRYPT | FLAGS_AES_CBC);
 }
 
+static int s5p_aes_ctr_crypt(struct ablkcipher_request *req)
+{
+       return s5p_aes_crypt(req, FLAGS_AES_CTR);
+}
+
 static int s5p_aes_cra_init(struct crypto_tfm *tfm)
 {
        struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm);
@@ -2144,6 +2139,28 @@ static struct crypto_alg algs[] = {
                        .decrypt        = s5p_aes_cbc_decrypt,
                }
        },
+       {
+               .cra_name               = "ctr(aes)",
+               .cra_driver_name        = "ctr-aes-s5p",
+               .cra_priority           = 100,
+               .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER |
+                                         CRYPTO_ALG_ASYNC |
+                                         CRYPTO_ALG_KERN_DRIVER_ONLY,
+               .cra_blocksize          = AES_BLOCK_SIZE,
+               .cra_ctxsize            = sizeof(struct s5p_aes_ctx),
+               .cra_alignmask          = 0x0f,
+               .cra_type               = &crypto_ablkcipher_type,
+               .cra_module             = THIS_MODULE,
+               .cra_init               = s5p_aes_cra_init,
+               .cra_u.ablkcipher = {
+                       .min_keysize    = AES_MIN_KEY_SIZE,
+                       .max_keysize    = AES_MAX_KEY_SIZE,
+                       .ivsize         = AES_BLOCK_SIZE,
+                       .setkey         = s5p_aes_setkey,
+                       .encrypt        = s5p_aes_ctr_crypt,
+                       .decrypt        = s5p_aes_ctr_crypt,
+               }
+       },
 };
 
 static int s5p_aes_probe(struct platform_device *pdev)