in axis/artpec6_crypto.c [1660:1825]
static int artpec6_crypto_prepare_crypto(struct skcipher_request *areq)
{
int ret;
struct artpec6_crypto_walk walk;
struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(areq);
struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher);
struct artpec6_crypto_request_context *req_ctx = NULL;
size_t iv_len = crypto_skcipher_ivsize(cipher);
struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
enum artpec6_crypto_variant variant = ac->variant;
struct artpec6_crypto_req_common *common;
bool cipher_decr = false;
size_t cipher_klen;
u32 cipher_len = 0; /* Same as regk_crypto_key_128 for NULL crypto */
u32 oper;
req_ctx = skcipher_request_ctx(areq);
common = &req_ctx->common;
artpec6_crypto_init_dma_operation(common);
if (variant == ARTPEC6_CRYPTO)
ctx->key_md = FIELD_PREP(A6_CRY_MD_OPER, a6_regk_crypto_dlkey);
else
ctx->key_md = FIELD_PREP(A7_CRY_MD_OPER, a7_regk_crypto_dlkey);
ret = artpec6_crypto_setup_out_descr(common, (void *)&ctx->key_md,
sizeof(ctx->key_md), false, false);
if (ret)
return ret;
ret = artpec6_crypto_setup_out_descr(common, ctx->aes_key,
ctx->key_length, true, false);
if (ret)
return ret;
req_ctx->cipher_md = 0;
if (ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_XTS)
cipher_klen = ctx->key_length/2;
else
cipher_klen = ctx->key_length;
/* Metadata */
switch (cipher_klen) {
case 16:
cipher_len = regk_crypto_key_128;
break;
case 24:
cipher_len = regk_crypto_key_192;
break;
case 32:
cipher_len = regk_crypto_key_256;
break;
default:
pr_err("%s: Invalid key length %d!\n",
MODULE_NAME, ctx->key_length);
return -EINVAL;
}
switch (ctx->crypto_type) {
case ARTPEC6_CRYPTO_CIPHER_AES_ECB:
oper = regk_crypto_aes_ecb;
cipher_decr = req_ctx->decrypt;
break;
case ARTPEC6_CRYPTO_CIPHER_AES_CBC:
oper = regk_crypto_aes_cbc;
cipher_decr = req_ctx->decrypt;
break;
case ARTPEC6_CRYPTO_CIPHER_AES_CTR:
oper = regk_crypto_aes_ctr;
cipher_decr = false;
break;
case ARTPEC6_CRYPTO_CIPHER_AES_XTS:
oper = regk_crypto_aes_xts;
cipher_decr = req_ctx->decrypt;
if (variant == ARTPEC6_CRYPTO)
req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DSEQ;
else
req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DSEQ;
break;
default:
pr_err("%s: Invalid cipher mode %d!\n",
MODULE_NAME, ctx->crypto_type);
return -EINVAL;
}
if (variant == ARTPEC6_CRYPTO) {
req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_OPER, oper);
req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_CIPHER_LEN,
cipher_len);
if (cipher_decr)
req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DECR;
} else {
req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_OPER, oper);
req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_CIPHER_LEN,
cipher_len);
if (cipher_decr)
req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DECR;
}
ret = artpec6_crypto_setup_out_descr(common,
&req_ctx->cipher_md,
sizeof(req_ctx->cipher_md),
false, false);
if (ret)
return ret;
ret = artpec6_crypto_setup_in_descr(common, ac->pad_buffer, 4, false);
if (ret)
return ret;
if (iv_len) {
ret = artpec6_crypto_setup_out_descr(common, areq->iv, iv_len,
false, false);
if (ret)
return ret;
}
/* Data out */
artpec6_crypto_walk_init(&walk, areq->src);
ret = artpec6_crypto_setup_sg_descrs_out(common, &walk, areq->cryptlen);
if (ret)
return ret;
/* Data in */
artpec6_crypto_walk_init(&walk, areq->dst);
ret = artpec6_crypto_setup_sg_descrs_in(common, &walk, areq->cryptlen);
if (ret)
return ret;
/* CTR-mode padding required by the HW. */
if (ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_CTR ||
ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_XTS) {
size_t pad = ALIGN(areq->cryptlen, AES_BLOCK_SIZE) -
areq->cryptlen;
if (pad) {
ret = artpec6_crypto_setup_out_descr(common,
ac->pad_buffer,
pad, false, false);
if (ret)
return ret;
ret = artpec6_crypto_setup_in_descr(common,
ac->pad_buffer, pad,
false);
if (ret)
return ret;
}
}
ret = artpec6_crypto_terminate_out_descrs(common);
if (ret)
return ret;
ret = artpec6_crypto_terminate_in_descrs(common);
if (ret)
return ret;
return artpec6_crypto_dma_map_descs(common);
}