summaryrefslogtreecommitdiff
path: root/drivers/crypto/caam/caamalg.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/crypto/caam/caamalg.c')
-rw-r--r--drivers/crypto/caam/caamalg.c177
1 files changed, 167 insertions, 10 deletions
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 413e1f35773f..dbcfed5171b2 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -1,7 +1,8 @@
/*
* caam - Freescale FSL CAAM support for crypto API
*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
*
* Based on talitos crypto API driver.
*
@@ -163,6 +164,9 @@ struct caam_aead_alg {
bool registered;
};
+static uint8_t *ecb_zero_iv;
+static dma_addr_t ecb_ziv_dma;
+
/* Set DK bit in class 1 operation if shared */
static inline void append_dec_op1(u32 *desc, u32 type)
{
@@ -1764,6 +1768,33 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
return ret;
}
+
+static int ablkcipher_des_setkey(struct crypto_ablkcipher *ablkcipher,
+ const u8 *key, unsigned int keylen)
+{
+ u32 tmp[DES_EXPKEY_WORDS];
+ u32 flags;
+ int ret;
+
+ if (keylen != DES_KEY_SIZE) {
+ crypto_ablkcipher_set_flags(ablkcipher,
+ CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ ret = des_ekey(tmp, key);
+
+ flags = crypto_ablkcipher_get_flags(ablkcipher);
+ if (!ret && (flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ crypto_ablkcipher_set_flags(ablkcipher,
+ CRYPTO_TFM_RES_WEAK_KEY);
+ return -EINVAL;
+ }
+
+ return ablkcipher_setkey(ablkcipher, key, keylen);
+}
+
+
static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
const u8 *key, unsigned int keylen)
{
@@ -2025,7 +2056,9 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
struct ablkcipher_edesc *edesc;
struct crypto_ablkcipher *ablkcipher = crypto_ablkcipher_reqtfm(req);
struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher);
+ int bsize = crypto_ablkcipher_blocksize(ablkcipher);
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
+ size_t ivcopy = min_t(size_t, bsize, ivsize);
#ifdef DEBUG
dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
@@ -2058,6 +2091,12 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
kfree(edesc);
+ /* Pass IV along for cbc */
+ if ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == OP_ALG_AAI_CBC) {
+ scatterwalk_map_and_copy(req->info, req->dst,
+ req->nbytes - bsize, ivcopy, 0);
+ }
+
ablkcipher_request_complete(req, err);
}
@@ -2640,6 +2679,7 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
int sgc;
int ivsize = crypto_ablkcipher_ivsize(ablkcipher);
int sec4_sg_index;
+ uint32_t c1_alg_typ = ctx->class1_alg_type;
src_nents = sg_count(req->src, req->nbytes);
@@ -2656,10 +2696,17 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request
DMA_FROM_DEVICE);
}
- iv_dma = dma_map_single(jrdev, req->info, ivsize, DMA_TO_DEVICE);
- if (dma_mapping_error(jrdev, iv_dma)) {
- dev_err(jrdev, "unable to map IV\n");
- return ERR_PTR(-ENOMEM);
+ if ((!req->info && ivsize) &&
+ ((c1_alg_typ & OP_ALG_ALGSEL_MASK) == OP_ALG_ALGSEL_AES) &&
+ ((c1_alg_typ & OP_ALG_AAI_MASK) == OP_ALG_AAI_ECB)) {
+ iv_dma = ecb_ziv_dma;
+ } else {
+ iv_dma = dma_map_single(jrdev, req->info, ivsize,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, iv_dma)) {
+ dev_err(jrdev, "unable to map IV\n");
+ return ERR_PTR(-ENOMEM);
+ }
}
/*
@@ -2970,6 +3017,22 @@ static struct caam_alg_template driver_algs[] = {
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
},
{
+ .name = "ecb(aes)",
+ .driver_name = "ecb-aes-caam",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ablkcipher_setkey,
+ .encrypt = ablkcipher_encrypt,
+ .decrypt = ablkcipher_decrypt,
+ .geniv = "eseqiv",
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_ECB,
+ },
+ {
.name = "cbc(des3_ede)",
.driver_name = "cbc-3des-caam",
.blocksize = DES3_EDE_BLOCK_SIZE,
@@ -2987,6 +3050,22 @@ static struct caam_alg_template driver_algs[] = {
.class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
},
{
+ .name = "ecb(des3_ede)",
+ .driver_name = "ecb-des3-caam",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ablkcipher_setkey,
+ .encrypt = ablkcipher_encrypt,
+ .decrypt = ablkcipher_decrypt,
+ .geniv = "eseqiv",
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_ECB,
+ },
+ {
.name = "cbc(des)",
.driver_name = "cbc-des-caam",
.blocksize = DES_BLOCK_SIZE,
@@ -3004,6 +3083,22 @@ static struct caam_alg_template driver_algs[] = {
.class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
},
{
+ .name = "ecb(des)",
+ .driver_name = "ecb-des-caam",
+ .blocksize = DES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ablkcipher_des_setkey,
+ .encrypt = ablkcipher_encrypt,
+ .decrypt = ablkcipher_decrypt,
+ .geniv = "eseqiv",
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_ECB,
+ },
+ {
.name = "ctr(aes)",
.driver_name = "ctr-aes-caam",
.blocksize = 1,
@@ -3054,6 +3149,23 @@ static struct caam_alg_template driver_algs[] = {
},
.class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XTS,
},
+ {
+ .name = "ecb(arc4)",
+ .driver_name = "ecb-arc4-caam",
+ .blocksize = ARC4_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ablkcipher_setkey,
+ .encrypt = ablkcipher_encrypt,
+ .decrypt = ablkcipher_decrypt,
+ .geniv = "eseqiv",
+ .min_keysize = ARC4_MIN_KEY_SIZE,
+ .max_keysize = ARC4_MAX_KEY_SIZE,
+ .ivsize = ARC4_BLOCK_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_ARC4 | OP_ALG_AAI_ECB
+ },
+
};
static struct caam_aead_alg driver_aeads[] = {
@@ -4469,10 +4581,35 @@ static void caam_aead_exit(struct crypto_aead *tfm)
static void __exit caam_algapi_exit(void)
{
-
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+ struct device *ctrldev;
struct caam_crypto_alg *t_alg, *n;
int i;
+ if (!ecb_zero_iv)
+ goto skip_ecb_ziv;
+
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ goto skip_ecb_ziv;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+
+ if (!pdev) {
+ of_node_put(dev_node);
+ goto skip_ecb_ziv;
+ }
+
+ ctrldev = &pdev->dev;
+
+ dma_unmap_single(ctrldev, ecb_ziv_dma, AES_BLOCK_SIZE, DMA_TO_DEVICE);
+ kfree(ecb_zero_iv);
+
+skip_ecb_ziv:
for (i = 0; i < ARRAY_SIZE(driver_aeads); i++) {
struct caam_aead_alg *t_alg = driver_aeads + i;
@@ -4514,8 +4651,12 @@ static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template
alg->cra_blocksize = template->blocksize;
alg->cra_alignmask = 0;
alg->cra_ctxsize = sizeof(struct caam_ctx);
- alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
- template->type;
+ alg->cra_flags = CRYPTO_ALG_ASYNC | template->type;
+
+#ifdef CRYPTO_ALG_KERN_DRIVER_ONLY
+ alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY;
+#endif
+
switch (template->type) {
case CRYPTO_ALG_TYPE_GIVCIPHER:
alg->cra_type = &crypto_givcipher_type;
@@ -4582,6 +4723,16 @@ static int __init caam_algapi_init(void)
if (!priv)
return -ENODEV;
+ ecb_zero_iv = kzalloc(AES_BLOCK_SIZE, GFP_KERNEL);
+ if (!ecb_zero_iv)
+ return -ENOMEM;
+
+ ecb_ziv_dma = dma_map_single(ctrldev, ecb_zero_iv, AES_BLOCK_SIZE,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ctrldev, ecb_ziv_dma)) {
+ kfree(ecb_zero_iv);
+ return -ENOMEM;
+ }
INIT_LIST_HEAD(&alg_list);
@@ -4589,8 +4740,14 @@ static int __init caam_algapi_init(void)
* Register crypto algorithms the device supports.
* First, detect presence and attributes of DES, AES, and MD blocks.
*/
- cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls);
- cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+ if (priv->has_seco) {
+ i = priv->first_jr_index;
+ cha_vid = rd_reg32(&priv->jr[i]->perfmon.cha_id_ls);
+ cha_inst = rd_reg32(&priv->jr[i]->perfmon.cha_num_ls);
+ } else {
+ cha_vid = rd_reg32(&priv->ctrl->perfmon.cha_id_ls);
+ cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+ }
des_inst = (cha_inst & CHA_ID_LS_DES_MASK) >> CHA_ID_LS_DES_SHIFT;
aes_inst = (cha_inst & CHA_ID_LS_AES_MASK) >> CHA_ID_LS_AES_SHIFT;
md_inst = (cha_inst & CHA_ID_LS_MD_MASK) >> CHA_ID_LS_MD_SHIFT;