static int artpec6_crypto_prepare_crypto()

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);
}