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 b7216935236f03fc1892f9ec3e4b8bff7a48f07e..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;
 };
 
@@ -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;
 }
 
 /*
@@ -662,8 +644,7 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
        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);
@@ -1832,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;
@@ -1840,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)
@@ -1918,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;
@@ -1930,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)
@@ -1966,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);
@@ -2026,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;
 
@@ -2034,7 +2022,6 @@ static int s5p_aes_handle_req(struct s5p_aes_dev *dev,
 
        tasklet_schedule(&dev->tasklet);
 
-exit:
        return err;
 }
 
@@ -2045,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;
        }
@@ -2056,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);
@@ -2092,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);
@@ -2146,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)