xref: /linux/drivers/crypto/inside-secure/eip93/eip93-common.c (revision 217460544a1b9741874dab826eb614e8c006f8a8)
19739f5f9SChristian Marangi // SPDX-License-Identifier: GPL-2.0
29739f5f9SChristian Marangi /*
39739f5f9SChristian Marangi  * Copyright (C) 2019 - 2021
49739f5f9SChristian Marangi  *
59739f5f9SChristian Marangi  * Richard van Schagen <vschagen@icloud.com>
69739f5f9SChristian Marangi  * Christian Marangi <ansuelsmth@gmail.com
79739f5f9SChristian Marangi  */
89739f5f9SChristian Marangi 
99739f5f9SChristian Marangi #include <crypto/aes.h>
109739f5f9SChristian Marangi #include <crypto/ctr.h>
119739f5f9SChristian Marangi #include <crypto/hmac.h>
129739f5f9SChristian Marangi #include <crypto/sha1.h>
139739f5f9SChristian Marangi #include <crypto/sha2.h>
149739f5f9SChristian Marangi #include <linux/kernel.h>
159739f5f9SChristian Marangi #include <linux/delay.h>
169739f5f9SChristian Marangi #include <linux/dma-mapping.h>
179739f5f9SChristian Marangi #include <linux/scatterlist.h>
189739f5f9SChristian Marangi 
199739f5f9SChristian Marangi #include "eip93-cipher.h"
209739f5f9SChristian Marangi #include "eip93-hash.h"
219739f5f9SChristian Marangi #include "eip93-common.h"
229739f5f9SChristian Marangi #include "eip93-main.h"
239739f5f9SChristian Marangi #include "eip93-regs.h"
249739f5f9SChristian Marangi 
259739f5f9SChristian Marangi int eip93_parse_ctrl_stat_err(struct eip93_device *eip93, int err)
269739f5f9SChristian Marangi {
279739f5f9SChristian Marangi 	u32 ext_err;
289739f5f9SChristian Marangi 
299739f5f9SChristian Marangi 	if (!err)
309739f5f9SChristian Marangi 		return 0;
319739f5f9SChristian Marangi 
329739f5f9SChristian Marangi 	switch (err & ~EIP93_PE_CTRL_PE_EXT_ERR_CODE) {
339739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_AUTH_ERR:
349739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_PAD_ERR:
359739f5f9SChristian Marangi 		return -EBADMSG;
369739f5f9SChristian Marangi 	/* let software handle anti-replay errors */
379739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_SEQNUM_ERR:
389739f5f9SChristian Marangi 		return 0;
399739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_EXT_ERR:
409739f5f9SChristian Marangi 		break;
419739f5f9SChristian Marangi 	default:
429739f5f9SChristian Marangi 		dev_err(eip93->dev, "Unhandled error 0x%08x\n", err);
439739f5f9SChristian Marangi 		return -EINVAL;
449739f5f9SChristian Marangi 	}
459739f5f9SChristian Marangi 
469739f5f9SChristian Marangi 	/* Parse additional ext errors */
479739f5f9SChristian Marangi 	ext_err = FIELD_GET(EIP93_PE_CTRL_PE_EXT_ERR_CODE, err);
489739f5f9SChristian Marangi 	switch (ext_err) {
499739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_EXT_ERR_BUS:
509739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_EXT_ERR_PROCESSING:
519739f5f9SChristian Marangi 		return -EIO;
529739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_EXT_ERR_DESC_OWNER:
539739f5f9SChristian Marangi 		return -EACCES;
549739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_CRYPTO_OP:
559739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_CRYPTO_ALGO:
569739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_EXT_ERR_SPI:
579739f5f9SChristian Marangi 		return -EINVAL;
589739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_EXT_ERR_ZERO_LENGTH:
599739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_EXT_ERR_INVALID_PK_LENGTH:
609739f5f9SChristian Marangi 	case EIP93_PE_CTRL_PE_EXT_ERR_BLOCK_SIZE_ERR:
619739f5f9SChristian Marangi 		return -EBADMSG;
629739f5f9SChristian Marangi 	default:
639739f5f9SChristian Marangi 		dev_err(eip93->dev, "Unhandled ext error 0x%08x\n", ext_err);
649739f5f9SChristian Marangi 		return -EINVAL;
659739f5f9SChristian Marangi 	}
669739f5f9SChristian Marangi }
679739f5f9SChristian Marangi 
689739f5f9SChristian Marangi static void *eip93_ring_next_wptr(struct eip93_device *eip93,
699739f5f9SChristian Marangi 				  struct eip93_desc_ring *ring)
709739f5f9SChristian Marangi {
719739f5f9SChristian Marangi 	void *ptr = ring->write;
729739f5f9SChristian Marangi 
739739f5f9SChristian Marangi 	if ((ring->write == ring->read - ring->offset) ||
749739f5f9SChristian Marangi 	    (ring->read == ring->base && ring->write == ring->base_end))
759739f5f9SChristian Marangi 		return ERR_PTR(-ENOMEM);
769739f5f9SChristian Marangi 
779739f5f9SChristian Marangi 	if (ring->write == ring->base_end)
789739f5f9SChristian Marangi 		ring->write = ring->base;
799739f5f9SChristian Marangi 	else
809739f5f9SChristian Marangi 		ring->write += ring->offset;
819739f5f9SChristian Marangi 
829739f5f9SChristian Marangi 	return ptr;
839739f5f9SChristian Marangi }
849739f5f9SChristian Marangi 
859739f5f9SChristian Marangi static void *eip93_ring_next_rptr(struct eip93_device *eip93,
869739f5f9SChristian Marangi 				  struct eip93_desc_ring *ring)
879739f5f9SChristian Marangi {
889739f5f9SChristian Marangi 	void *ptr = ring->read;
899739f5f9SChristian Marangi 
909739f5f9SChristian Marangi 	if (ring->write == ring->read)
919739f5f9SChristian Marangi 		return ERR_PTR(-ENOENT);
929739f5f9SChristian Marangi 
939739f5f9SChristian Marangi 	if (ring->read == ring->base_end)
949739f5f9SChristian Marangi 		ring->read = ring->base;
959739f5f9SChristian Marangi 	else
969739f5f9SChristian Marangi 		ring->read += ring->offset;
979739f5f9SChristian Marangi 
989739f5f9SChristian Marangi 	return ptr;
999739f5f9SChristian Marangi }
1009739f5f9SChristian Marangi 
1019739f5f9SChristian Marangi int eip93_put_descriptor(struct eip93_device *eip93,
1029739f5f9SChristian Marangi 			 struct eip93_descriptor *desc)
1039739f5f9SChristian Marangi {
1049739f5f9SChristian Marangi 	struct eip93_descriptor *cdesc;
1059739f5f9SChristian Marangi 	struct eip93_descriptor *rdesc;
1069739f5f9SChristian Marangi 
1079739f5f9SChristian Marangi 	rdesc = eip93_ring_next_wptr(eip93, &eip93->ring->rdr);
1089739f5f9SChristian Marangi 	if (IS_ERR(rdesc))
1099739f5f9SChristian Marangi 		return -ENOENT;
1109739f5f9SChristian Marangi 
1119739f5f9SChristian Marangi 	cdesc = eip93_ring_next_wptr(eip93, &eip93->ring->cdr);
1129739f5f9SChristian Marangi 	if (IS_ERR(cdesc))
1139739f5f9SChristian Marangi 		return -ENOENT;
1149739f5f9SChristian Marangi 
1159739f5f9SChristian Marangi 	memset(rdesc, 0, sizeof(struct eip93_descriptor));
1169739f5f9SChristian Marangi 
1179739f5f9SChristian Marangi 	memcpy(cdesc, desc, sizeof(struct eip93_descriptor));
1189739f5f9SChristian Marangi 
1199739f5f9SChristian Marangi 	return 0;
1209739f5f9SChristian Marangi }
1219739f5f9SChristian Marangi 
1229739f5f9SChristian Marangi void *eip93_get_descriptor(struct eip93_device *eip93)
1239739f5f9SChristian Marangi {
1249739f5f9SChristian Marangi 	struct eip93_descriptor *cdesc;
1259739f5f9SChristian Marangi 	void *ptr;
1269739f5f9SChristian Marangi 
1279739f5f9SChristian Marangi 	cdesc = eip93_ring_next_rptr(eip93, &eip93->ring->cdr);
1289739f5f9SChristian Marangi 	if (IS_ERR(cdesc))
1299739f5f9SChristian Marangi 		return ERR_PTR(-ENOENT);
1309739f5f9SChristian Marangi 
1319739f5f9SChristian Marangi 	memset(cdesc, 0, sizeof(struct eip93_descriptor));
1329739f5f9SChristian Marangi 
1339739f5f9SChristian Marangi 	ptr = eip93_ring_next_rptr(eip93, &eip93->ring->rdr);
1349739f5f9SChristian Marangi 	if (IS_ERR(ptr))
1359739f5f9SChristian Marangi 		return ERR_PTR(-ENOENT);
1369739f5f9SChristian Marangi 
1379739f5f9SChristian Marangi 	return ptr;
1389739f5f9SChristian Marangi }
1399739f5f9SChristian Marangi 
1409739f5f9SChristian Marangi static void eip93_free_sg_copy(const int len, struct scatterlist **sg)
1419739f5f9SChristian Marangi {
1429739f5f9SChristian Marangi 	if (!*sg || !len)
1439739f5f9SChristian Marangi 		return;
1449739f5f9SChristian Marangi 
1459739f5f9SChristian Marangi 	free_pages((unsigned long)sg_virt(*sg), get_order(len));
1469739f5f9SChristian Marangi 	kfree(*sg);
1479739f5f9SChristian Marangi 	*sg = NULL;
1489739f5f9SChristian Marangi }
1499739f5f9SChristian Marangi 
1509739f5f9SChristian Marangi static int eip93_make_sg_copy(struct scatterlist *src, struct scatterlist **dst,
1519739f5f9SChristian Marangi 			      const u32 len, const bool copy)
1529739f5f9SChristian Marangi {
1539739f5f9SChristian Marangi 	void *pages;
1549739f5f9SChristian Marangi 
1559739f5f9SChristian Marangi 	*dst = kmalloc(sizeof(**dst), GFP_KERNEL);
1569739f5f9SChristian Marangi 	if (!*dst)
1579739f5f9SChristian Marangi 		return -ENOMEM;
1589739f5f9SChristian Marangi 
1599739f5f9SChristian Marangi 	pages = (void *)__get_free_pages(GFP_KERNEL | GFP_DMA,
1609739f5f9SChristian Marangi 					 get_order(len));
1619739f5f9SChristian Marangi 	if (!pages) {
1629739f5f9SChristian Marangi 		kfree(*dst);
1639739f5f9SChristian Marangi 		*dst = NULL;
1649739f5f9SChristian Marangi 		return -ENOMEM;
1659739f5f9SChristian Marangi 	}
1669739f5f9SChristian Marangi 
1679739f5f9SChristian Marangi 	sg_init_table(*dst, 1);
1689739f5f9SChristian Marangi 	sg_set_buf(*dst, pages, len);
1699739f5f9SChristian Marangi 
1709739f5f9SChristian Marangi 	/* copy only as requested */
1719739f5f9SChristian Marangi 	if (copy)
1729739f5f9SChristian Marangi 		sg_copy_to_buffer(src, sg_nents(src), pages, len);
1739739f5f9SChristian Marangi 
1749739f5f9SChristian Marangi 	return 0;
1759739f5f9SChristian Marangi }
1769739f5f9SChristian Marangi 
1779739f5f9SChristian Marangi static bool eip93_is_sg_aligned(struct scatterlist *sg, u32 len,
1789739f5f9SChristian Marangi 				const int blksize)
1799739f5f9SChristian Marangi {
1809739f5f9SChristian Marangi 	int nents;
1819739f5f9SChristian Marangi 
1829739f5f9SChristian Marangi 	for (nents = 0; sg; sg = sg_next(sg), ++nents) {
1839739f5f9SChristian Marangi 		if (!IS_ALIGNED(sg->offset, 4))
1849739f5f9SChristian Marangi 			return false;
1859739f5f9SChristian Marangi 
1869739f5f9SChristian Marangi 		if (len <= sg->length) {
1879739f5f9SChristian Marangi 			if (!IS_ALIGNED(len, blksize))
1889739f5f9SChristian Marangi 				return false;
1899739f5f9SChristian Marangi 
1909739f5f9SChristian Marangi 			return true;
1919739f5f9SChristian Marangi 		}
1929739f5f9SChristian Marangi 
1939739f5f9SChristian Marangi 		if (!IS_ALIGNED(sg->length, blksize))
1949739f5f9SChristian Marangi 			return false;
1959739f5f9SChristian Marangi 
1969739f5f9SChristian Marangi 		len -= sg->length;
1979739f5f9SChristian Marangi 	}
1989739f5f9SChristian Marangi 	return false;
1999739f5f9SChristian Marangi }
2009739f5f9SChristian Marangi 
2019739f5f9SChristian Marangi int check_valid_request(struct eip93_cipher_reqctx *rctx)
2029739f5f9SChristian Marangi {
2039739f5f9SChristian Marangi 	struct scatterlist *src = rctx->sg_src;
2049739f5f9SChristian Marangi 	struct scatterlist *dst = rctx->sg_dst;
2059739f5f9SChristian Marangi 	u32 textsize = rctx->textsize;
2069739f5f9SChristian Marangi 	u32 authsize = rctx->authsize;
2079739f5f9SChristian Marangi 	u32 blksize = rctx->blksize;
2089739f5f9SChristian Marangi 	u32 totlen_src = rctx->assoclen + rctx->textsize;
2099739f5f9SChristian Marangi 	u32 totlen_dst = rctx->assoclen + rctx->textsize;
2109739f5f9SChristian Marangi 	u32 copy_len;
2119739f5f9SChristian Marangi 	bool src_align, dst_align;
212*21746054SChristian Marangi 	int src_nents, dst_nents;
2139739f5f9SChristian Marangi 	int err = -EINVAL;
2149739f5f9SChristian Marangi 
2159739f5f9SChristian Marangi 	if (!IS_CTR(rctx->flags)) {
2169739f5f9SChristian Marangi 		if (!IS_ALIGNED(textsize, blksize))
2179739f5f9SChristian Marangi 			return err;
2189739f5f9SChristian Marangi 	}
2199739f5f9SChristian Marangi 
2209739f5f9SChristian Marangi 	if (authsize) {
2219739f5f9SChristian Marangi 		if (IS_ENCRYPT(rctx->flags))
2229739f5f9SChristian Marangi 			totlen_dst += authsize;
2239739f5f9SChristian Marangi 		else
2249739f5f9SChristian Marangi 			totlen_src += authsize;
2259739f5f9SChristian Marangi 	}
2269739f5f9SChristian Marangi 
2279739f5f9SChristian Marangi 	src_nents = sg_nents_for_len(src, totlen_src);
228*21746054SChristian Marangi 	if (src_nents < 0)
229*21746054SChristian Marangi 		return src_nents;
230*21746054SChristian Marangi 
2319739f5f9SChristian Marangi 	dst_nents = sg_nents_for_len(dst, totlen_dst);
232*21746054SChristian Marangi 	if (dst_nents < 0)
233*21746054SChristian Marangi 		return dst_nents;
2349739f5f9SChristian Marangi 
2359739f5f9SChristian Marangi 	if (src == dst) {
2369739f5f9SChristian Marangi 		src_nents = max(src_nents, dst_nents);
2379739f5f9SChristian Marangi 		dst_nents = src_nents;
238*21746054SChristian Marangi 		if (unlikely((totlen_src || totlen_dst) && !src_nents))
2399739f5f9SChristian Marangi 			return err;
2409739f5f9SChristian Marangi 
2419739f5f9SChristian Marangi 	} else {
242*21746054SChristian Marangi 		if (unlikely(totlen_src && !src_nents))
2439739f5f9SChristian Marangi 			return err;
2449739f5f9SChristian Marangi 
245*21746054SChristian Marangi 		if (unlikely(totlen_dst && !dst_nents))
2469739f5f9SChristian Marangi 			return err;
2479739f5f9SChristian Marangi 	}
2489739f5f9SChristian Marangi 
2499739f5f9SChristian Marangi 	if (authsize) {
2509739f5f9SChristian Marangi 		if (dst_nents == 1 && src_nents == 1) {
2519739f5f9SChristian Marangi 			src_align = eip93_is_sg_aligned(src, totlen_src, blksize);
2529739f5f9SChristian Marangi 			if (src ==  dst)
2539739f5f9SChristian Marangi 				dst_align = src_align;
2549739f5f9SChristian Marangi 			else
2559739f5f9SChristian Marangi 				dst_align = eip93_is_sg_aligned(dst, totlen_dst, blksize);
2569739f5f9SChristian Marangi 		} else {
2579739f5f9SChristian Marangi 			src_align = false;
2589739f5f9SChristian Marangi 			dst_align = false;
2599739f5f9SChristian Marangi 		}
2609739f5f9SChristian Marangi 	} else {
2619739f5f9SChristian Marangi 		src_align = eip93_is_sg_aligned(src, totlen_src, blksize);
2629739f5f9SChristian Marangi 		if (src == dst)
2639739f5f9SChristian Marangi 			dst_align = src_align;
2649739f5f9SChristian Marangi 		else
2659739f5f9SChristian Marangi 			dst_align = eip93_is_sg_aligned(dst, totlen_dst, blksize);
2669739f5f9SChristian Marangi 	}
2679739f5f9SChristian Marangi 
2689739f5f9SChristian Marangi 	copy_len = max(totlen_src, totlen_dst);
2699739f5f9SChristian Marangi 	if (!src_align) {
2709739f5f9SChristian Marangi 		err = eip93_make_sg_copy(src, &rctx->sg_src, copy_len, true);
2719739f5f9SChristian Marangi 		if (err)
2729739f5f9SChristian Marangi 			return err;
2739739f5f9SChristian Marangi 	}
2749739f5f9SChristian Marangi 
2759739f5f9SChristian Marangi 	if (!dst_align) {
2769739f5f9SChristian Marangi 		err = eip93_make_sg_copy(dst, &rctx->sg_dst, copy_len, false);
2779739f5f9SChristian Marangi 		if (err)
2789739f5f9SChristian Marangi 			return err;
2799739f5f9SChristian Marangi 	}
2809739f5f9SChristian Marangi 
281*21746054SChristian Marangi 	src_nents = sg_nents_for_len(rctx->sg_src, totlen_src);
282*21746054SChristian Marangi 	if (src_nents < 0)
283*21746054SChristian Marangi 		return src_nents;
284*21746054SChristian Marangi 
285*21746054SChristian Marangi 	dst_nents = sg_nents_for_len(rctx->sg_dst, totlen_dst);
286*21746054SChristian Marangi 	if (dst_nents < 0)
287*21746054SChristian Marangi 		return dst_nents;
288*21746054SChristian Marangi 
289*21746054SChristian Marangi 	rctx->src_nents = src_nents;
290*21746054SChristian Marangi 	rctx->dst_nents = dst_nents;
2919739f5f9SChristian Marangi 
2929739f5f9SChristian Marangi 	return 0;
2939739f5f9SChristian Marangi }
2949739f5f9SChristian Marangi 
2959739f5f9SChristian Marangi /*
2969739f5f9SChristian Marangi  * Set sa_record function:
2979739f5f9SChristian Marangi  * Even sa_record is set to "0", keep " = 0" for readability.
2989739f5f9SChristian Marangi  */
2999739f5f9SChristian Marangi void eip93_set_sa_record(struct sa_record *sa_record, const unsigned int keylen,
3009739f5f9SChristian Marangi 			 const u32 flags)
3019739f5f9SChristian Marangi {
3029739f5f9SChristian Marangi 	/* Reset cmd word */
3039739f5f9SChristian Marangi 	sa_record->sa_cmd0_word = 0;
3049739f5f9SChristian Marangi 	sa_record->sa_cmd1_word = 0;
3059739f5f9SChristian Marangi 
3069739f5f9SChristian Marangi 	sa_record->sa_cmd0_word |= EIP93_SA_CMD_IV_FROM_STATE;
3079739f5f9SChristian Marangi 	if (!IS_ECB(flags))
3089739f5f9SChristian Marangi 		sa_record->sa_cmd0_word |= EIP93_SA_CMD_SAVE_IV;
3099739f5f9SChristian Marangi 
3109739f5f9SChristian Marangi 	sa_record->sa_cmd0_word |= EIP93_SA_CMD_OP_BASIC;
3119739f5f9SChristian Marangi 
3129739f5f9SChristian Marangi 	switch ((flags & EIP93_ALG_MASK)) {
3139739f5f9SChristian Marangi 	case EIP93_ALG_AES:
3149739f5f9SChristian Marangi 		sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_AES;
3159739f5f9SChristian Marangi 		sa_record->sa_cmd1_word |= FIELD_PREP(EIP93_SA_CMD_AES_KEY_LENGTH,
3169739f5f9SChristian Marangi 						      keylen >> 3);
3179739f5f9SChristian Marangi 		break;
3189739f5f9SChristian Marangi 	case EIP93_ALG_3DES:
3199739f5f9SChristian Marangi 		sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_3DES;
3209739f5f9SChristian Marangi 		break;
3219739f5f9SChristian Marangi 	case EIP93_ALG_DES:
3229739f5f9SChristian Marangi 		sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_DES;
3239739f5f9SChristian Marangi 		break;
3249739f5f9SChristian Marangi 	default:
3259739f5f9SChristian Marangi 		sa_record->sa_cmd0_word |= EIP93_SA_CMD_CIPHER_NULL;
3269739f5f9SChristian Marangi 	}
3279739f5f9SChristian Marangi 
3289739f5f9SChristian Marangi 	switch ((flags & EIP93_HASH_MASK)) {
3299739f5f9SChristian Marangi 	case EIP93_HASH_SHA256:
3309739f5f9SChristian Marangi 		sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA256;
3319739f5f9SChristian Marangi 		break;
3329739f5f9SChristian Marangi 	case EIP93_HASH_SHA224:
3339739f5f9SChristian Marangi 		sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA224;
3349739f5f9SChristian Marangi 		break;
3359739f5f9SChristian Marangi 	case EIP93_HASH_SHA1:
3369739f5f9SChristian Marangi 		sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_SHA1;
3379739f5f9SChristian Marangi 		break;
3389739f5f9SChristian Marangi 	case EIP93_HASH_MD5:
3399739f5f9SChristian Marangi 		sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_MD5;
3409739f5f9SChristian Marangi 		break;
3419739f5f9SChristian Marangi 	default:
3429739f5f9SChristian Marangi 		sa_record->sa_cmd0_word |= EIP93_SA_CMD_HASH_NULL;
3439739f5f9SChristian Marangi 	}
3449739f5f9SChristian Marangi 
3459739f5f9SChristian Marangi 	sa_record->sa_cmd0_word |= EIP93_SA_CMD_PAD_ZERO;
3469739f5f9SChristian Marangi 
3479739f5f9SChristian Marangi 	switch ((flags & EIP93_MODE_MASK)) {
3489739f5f9SChristian Marangi 	case EIP93_MODE_CBC:
3499739f5f9SChristian Marangi 		sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_CBC;
3509739f5f9SChristian Marangi 		break;
3519739f5f9SChristian Marangi 	case EIP93_MODE_CTR:
3529739f5f9SChristian Marangi 		sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_CTR;
3539739f5f9SChristian Marangi 		break;
3549739f5f9SChristian Marangi 	case EIP93_MODE_ECB:
3559739f5f9SChristian Marangi 		sa_record->sa_cmd1_word |= EIP93_SA_CMD_CHIPER_MODE_ECB;
3569739f5f9SChristian Marangi 		break;
3579739f5f9SChristian Marangi 	}
3589739f5f9SChristian Marangi 
3599739f5f9SChristian Marangi 	sa_record->sa_cmd0_word |= EIP93_SA_CMD_DIGEST_3WORD;
3609739f5f9SChristian Marangi 	if (IS_HASH(flags)) {
3619739f5f9SChristian Marangi 		sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_PAD;
3629739f5f9SChristian Marangi 		sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_DIGEST;
3639739f5f9SChristian Marangi 	}
3649739f5f9SChristian Marangi 
3659739f5f9SChristian Marangi 	if (IS_HMAC(flags)) {
3669739f5f9SChristian Marangi 		sa_record->sa_cmd1_word |= EIP93_SA_CMD_HMAC;
3679739f5f9SChristian Marangi 		sa_record->sa_cmd1_word |= EIP93_SA_CMD_COPY_HEADER;
3689739f5f9SChristian Marangi 	}
3699739f5f9SChristian Marangi 
3709739f5f9SChristian Marangi 	sa_record->sa_spi = 0x0;
3719739f5f9SChristian Marangi 	sa_record->sa_seqmum_mask[0] = 0xFFFFFFFF;
3729739f5f9SChristian Marangi 	sa_record->sa_seqmum_mask[1] = 0x0;
3739739f5f9SChristian Marangi }
3749739f5f9SChristian Marangi 
3759739f5f9SChristian Marangi /*
3769739f5f9SChristian Marangi  * Poor mans Scatter/gather function:
3779739f5f9SChristian Marangi  * Create a Descriptor for every segment to avoid copying buffers.
3789739f5f9SChristian Marangi  * For performance better to wait for hardware to perform multiple DMA
3799739f5f9SChristian Marangi  */
3809739f5f9SChristian Marangi static int eip93_scatter_combine(struct eip93_device *eip93,
3819739f5f9SChristian Marangi 				 struct eip93_cipher_reqctx *rctx,
3829739f5f9SChristian Marangi 				 u32 datalen, u32 split, int offsetin)
3839739f5f9SChristian Marangi {
3849739f5f9SChristian Marangi 	struct eip93_descriptor *cdesc = rctx->cdesc;
3859739f5f9SChristian Marangi 	struct scatterlist *sgsrc = rctx->sg_src;
3869739f5f9SChristian Marangi 	struct scatterlist *sgdst = rctx->sg_dst;
3879739f5f9SChristian Marangi 	unsigned int remainin = sg_dma_len(sgsrc);
3889739f5f9SChristian Marangi 	unsigned int remainout = sg_dma_len(sgdst);
3899739f5f9SChristian Marangi 	dma_addr_t saddr = sg_dma_address(sgsrc);
3909739f5f9SChristian Marangi 	dma_addr_t daddr = sg_dma_address(sgdst);
3919739f5f9SChristian Marangi 	dma_addr_t state_addr;
3929739f5f9SChristian Marangi 	u32 src_addr, dst_addr, len, n;
3939739f5f9SChristian Marangi 	bool nextin = false;
3949739f5f9SChristian Marangi 	bool nextout = false;
3959739f5f9SChristian Marangi 	int offsetout = 0;
3969739f5f9SChristian Marangi 	int err;
3979739f5f9SChristian Marangi 
3989739f5f9SChristian Marangi 	if (IS_ECB(rctx->flags))
3999739f5f9SChristian Marangi 		rctx->sa_state_base = 0;
4009739f5f9SChristian Marangi 
4019739f5f9SChristian Marangi 	if (split < datalen) {
4029739f5f9SChristian Marangi 		state_addr = rctx->sa_state_ctr_base;
4039739f5f9SChristian Marangi 		n = split;
4049739f5f9SChristian Marangi 	} else {
4059739f5f9SChristian Marangi 		state_addr = rctx->sa_state_base;
4069739f5f9SChristian Marangi 		n = datalen;
4079739f5f9SChristian Marangi 	}
4089739f5f9SChristian Marangi 
4099739f5f9SChristian Marangi 	do {
4109739f5f9SChristian Marangi 		if (nextin) {
4119739f5f9SChristian Marangi 			sgsrc = sg_next(sgsrc);
4129739f5f9SChristian Marangi 			remainin = sg_dma_len(sgsrc);
4139739f5f9SChristian Marangi 			if (remainin == 0)
4149739f5f9SChristian Marangi 				continue;
4159739f5f9SChristian Marangi 
4169739f5f9SChristian Marangi 			saddr = sg_dma_address(sgsrc);
4179739f5f9SChristian Marangi 			offsetin = 0;
4189739f5f9SChristian Marangi 			nextin = false;
4199739f5f9SChristian Marangi 		}
4209739f5f9SChristian Marangi 
4219739f5f9SChristian Marangi 		if (nextout) {
4229739f5f9SChristian Marangi 			sgdst = sg_next(sgdst);
4239739f5f9SChristian Marangi 			remainout = sg_dma_len(sgdst);
4249739f5f9SChristian Marangi 			if (remainout == 0)
4259739f5f9SChristian Marangi 				continue;
4269739f5f9SChristian Marangi 
4279739f5f9SChristian Marangi 			daddr = sg_dma_address(sgdst);
4289739f5f9SChristian Marangi 			offsetout = 0;
4299739f5f9SChristian Marangi 			nextout = false;
4309739f5f9SChristian Marangi 		}
4319739f5f9SChristian Marangi 		src_addr = saddr + offsetin;
4329739f5f9SChristian Marangi 		dst_addr = daddr + offsetout;
4339739f5f9SChristian Marangi 
4349739f5f9SChristian Marangi 		if (remainin == remainout) {
4359739f5f9SChristian Marangi 			len = remainin;
4369739f5f9SChristian Marangi 			if (len > n) {
4379739f5f9SChristian Marangi 				len = n;
4389739f5f9SChristian Marangi 				remainin -= n;
4399739f5f9SChristian Marangi 				remainout -= n;
4409739f5f9SChristian Marangi 				offsetin += n;
4419739f5f9SChristian Marangi 				offsetout += n;
4429739f5f9SChristian Marangi 			} else {
4439739f5f9SChristian Marangi 				nextin = true;
4449739f5f9SChristian Marangi 				nextout = true;
4459739f5f9SChristian Marangi 			}
4469739f5f9SChristian Marangi 		} else if (remainin < remainout) {
4479739f5f9SChristian Marangi 			len = remainin;
4489739f5f9SChristian Marangi 			if (len > n) {
4499739f5f9SChristian Marangi 				len = n;
4509739f5f9SChristian Marangi 				remainin -= n;
4519739f5f9SChristian Marangi 				remainout -= n;
4529739f5f9SChristian Marangi 				offsetin += n;
4539739f5f9SChristian Marangi 				offsetout += n;
4549739f5f9SChristian Marangi 			} else {
4559739f5f9SChristian Marangi 				offsetout += len;
4569739f5f9SChristian Marangi 				remainout -= len;
4579739f5f9SChristian Marangi 				nextin = true;
4589739f5f9SChristian Marangi 			}
4599739f5f9SChristian Marangi 		} else {
4609739f5f9SChristian Marangi 			len = remainout;
4619739f5f9SChristian Marangi 			if (len > n) {
4629739f5f9SChristian Marangi 				len = n;
4639739f5f9SChristian Marangi 				remainin -= n;
4649739f5f9SChristian Marangi 				remainout -= n;
4659739f5f9SChristian Marangi 				offsetin += n;
4669739f5f9SChristian Marangi 				offsetout += n;
4679739f5f9SChristian Marangi 			} else {
4689739f5f9SChristian Marangi 				offsetin += len;
4699739f5f9SChristian Marangi 				remainin -= len;
4709739f5f9SChristian Marangi 				nextout = true;
4719739f5f9SChristian Marangi 			}
4729739f5f9SChristian Marangi 		}
4739739f5f9SChristian Marangi 		n -= len;
4749739f5f9SChristian Marangi 
4759739f5f9SChristian Marangi 		cdesc->src_addr = src_addr;
4769739f5f9SChristian Marangi 		cdesc->dst_addr = dst_addr;
4779739f5f9SChristian Marangi 		cdesc->state_addr = state_addr;
4789739f5f9SChristian Marangi 		cdesc->pe_length_word = FIELD_PREP(EIP93_PE_LENGTH_HOST_PE_READY,
4799739f5f9SChristian Marangi 						   EIP93_PE_LENGTH_HOST_READY);
4809739f5f9SChristian Marangi 		cdesc->pe_length_word |= FIELD_PREP(EIP93_PE_LENGTH_LENGTH, len);
4819739f5f9SChristian Marangi 
4829739f5f9SChristian Marangi 		if (n == 0) {
4839739f5f9SChristian Marangi 			n = datalen - split;
4849739f5f9SChristian Marangi 			split = datalen;
4859739f5f9SChristian Marangi 			state_addr = rctx->sa_state_base;
4869739f5f9SChristian Marangi 		}
4879739f5f9SChristian Marangi 
4889739f5f9SChristian Marangi 		if (n == 0)
4899739f5f9SChristian Marangi 			cdesc->user_id |= FIELD_PREP(EIP93_PE_USER_ID_DESC_FLAGS,
4909739f5f9SChristian Marangi 						     EIP93_DESC_LAST);
4919739f5f9SChristian Marangi 
4929739f5f9SChristian Marangi 		/*
4939739f5f9SChristian Marangi 		 * Loop - Delay - No need to rollback
4949739f5f9SChristian Marangi 		 * Maybe refine by slowing down at EIP93_RING_BUSY
4959739f5f9SChristian Marangi 		 */
4969739f5f9SChristian Marangi again:
4979739f5f9SChristian Marangi 		scoped_guard(spinlock_irqsave, &eip93->ring->write_lock)
4989739f5f9SChristian Marangi 			err = eip93_put_descriptor(eip93, cdesc);
4999739f5f9SChristian Marangi 		if (err) {
5009739f5f9SChristian Marangi 			usleep_range(EIP93_RING_BUSY_DELAY,
5019739f5f9SChristian Marangi 				     EIP93_RING_BUSY_DELAY * 2);
5029739f5f9SChristian Marangi 			goto again;
5039739f5f9SChristian Marangi 		}
5049739f5f9SChristian Marangi 		/* Writing new descriptor count starts DMA action */
5059739f5f9SChristian Marangi 		writel(1, eip93->base + EIP93_REG_PE_CD_COUNT);
5069739f5f9SChristian Marangi 	} while (n);
5079739f5f9SChristian Marangi 
5089739f5f9SChristian Marangi 	return -EINPROGRESS;
5099739f5f9SChristian Marangi }
5109739f5f9SChristian Marangi 
5119739f5f9SChristian Marangi int eip93_send_req(struct crypto_async_request *async,
5129739f5f9SChristian Marangi 		   const u8 *reqiv, struct eip93_cipher_reqctx *rctx)
5139739f5f9SChristian Marangi {
5149739f5f9SChristian Marangi 	struct eip93_crypto_ctx *ctx = crypto_tfm_ctx(async->tfm);
5159739f5f9SChristian Marangi 	struct eip93_device *eip93 = ctx->eip93;
5169739f5f9SChristian Marangi 	struct scatterlist *src = rctx->sg_src;
5179739f5f9SChristian Marangi 	struct scatterlist *dst = rctx->sg_dst;
5189739f5f9SChristian Marangi 	struct sa_state *sa_state;
5199739f5f9SChristian Marangi 	struct eip93_descriptor cdesc;
5209739f5f9SChristian Marangi 	u32 flags = rctx->flags;
5219739f5f9SChristian Marangi 	int offsetin = 0, err;
5229739f5f9SChristian Marangi 	u32 datalen = rctx->assoclen + rctx->textsize;
5239739f5f9SChristian Marangi 	u32 split = datalen;
5249739f5f9SChristian Marangi 	u32 start, end, ctr, blocks;
5259739f5f9SChristian Marangi 	u32 iv[AES_BLOCK_SIZE / sizeof(u32)];
5269739f5f9SChristian Marangi 	int crypto_async_idr;
5279739f5f9SChristian Marangi 
5289739f5f9SChristian Marangi 	rctx->sa_state_ctr = NULL;
5299739f5f9SChristian Marangi 	rctx->sa_state = NULL;
5309739f5f9SChristian Marangi 
5319739f5f9SChristian Marangi 	if (IS_ECB(flags))
5329739f5f9SChristian Marangi 		goto skip_iv;
5339739f5f9SChristian Marangi 
5349739f5f9SChristian Marangi 	memcpy(iv, reqiv, rctx->ivsize);
5359739f5f9SChristian Marangi 
5369739f5f9SChristian Marangi 	rctx->sa_state = kzalloc(sizeof(*rctx->sa_state), GFP_KERNEL);
5379739f5f9SChristian Marangi 	if (!rctx->sa_state)
5389739f5f9SChristian Marangi 		return -ENOMEM;
5399739f5f9SChristian Marangi 
5409739f5f9SChristian Marangi 	sa_state = rctx->sa_state;
5419739f5f9SChristian Marangi 
5429739f5f9SChristian Marangi 	memcpy(sa_state->state_iv, iv, rctx->ivsize);
5439739f5f9SChristian Marangi 	if (IS_RFC3686(flags)) {
5449739f5f9SChristian Marangi 		sa_state->state_iv[0] = ctx->sa_nonce;
5459739f5f9SChristian Marangi 		sa_state->state_iv[1] = iv[0];
5469739f5f9SChristian Marangi 		sa_state->state_iv[2] = iv[1];
5479739f5f9SChristian Marangi 		sa_state->state_iv[3] = (u32 __force)cpu_to_be32(0x1);
5489739f5f9SChristian Marangi 	} else if (!IS_HMAC(flags) && IS_CTR(flags)) {
5499739f5f9SChristian Marangi 		/* Compute data length. */
5509739f5f9SChristian Marangi 		blocks = DIV_ROUND_UP(rctx->textsize, AES_BLOCK_SIZE);
5519739f5f9SChristian Marangi 		ctr = be32_to_cpu((__be32 __force)iv[3]);
5529739f5f9SChristian Marangi 		/* Check 32bit counter overflow. */
5539739f5f9SChristian Marangi 		start = ctr;
5549739f5f9SChristian Marangi 		end = start + blocks - 1;
5559739f5f9SChristian Marangi 		if (end < start) {
5569739f5f9SChristian Marangi 			split = AES_BLOCK_SIZE * -start;
5579739f5f9SChristian Marangi 			/*
5589739f5f9SChristian Marangi 			 * Increment the counter manually to cope with
5599739f5f9SChristian Marangi 			 * the hardware counter overflow.
5609739f5f9SChristian Marangi 			 */
5619739f5f9SChristian Marangi 			iv[3] = 0xffffffff;
5629739f5f9SChristian Marangi 			crypto_inc((u8 *)iv, AES_BLOCK_SIZE);
5639739f5f9SChristian Marangi 
5649739f5f9SChristian Marangi 			rctx->sa_state_ctr = kzalloc(sizeof(*rctx->sa_state_ctr),
5659739f5f9SChristian Marangi 						     GFP_KERNEL);
5669739f5f9SChristian Marangi 			if (!rctx->sa_state_ctr) {
5679739f5f9SChristian Marangi 				err = -ENOMEM;
5689739f5f9SChristian Marangi 				goto free_sa_state;
5699739f5f9SChristian Marangi 			}
5709739f5f9SChristian Marangi 
5719739f5f9SChristian Marangi 			memcpy(rctx->sa_state_ctr->state_iv, reqiv, rctx->ivsize);
5729739f5f9SChristian Marangi 			memcpy(sa_state->state_iv, iv, rctx->ivsize);
5739739f5f9SChristian Marangi 
5749739f5f9SChristian Marangi 			rctx->sa_state_ctr_base = dma_map_single(eip93->dev, rctx->sa_state_ctr,
5759739f5f9SChristian Marangi 								 sizeof(*rctx->sa_state_ctr),
5769739f5f9SChristian Marangi 								 DMA_TO_DEVICE);
5779739f5f9SChristian Marangi 			err = dma_mapping_error(eip93->dev, rctx->sa_state_ctr_base);
5789739f5f9SChristian Marangi 			if (err)
5799739f5f9SChristian Marangi 				goto free_sa_state_ctr;
5809739f5f9SChristian Marangi 		}
5819739f5f9SChristian Marangi 	}
5829739f5f9SChristian Marangi 
5839739f5f9SChristian Marangi 	rctx->sa_state_base = dma_map_single(eip93->dev, rctx->sa_state,
5849739f5f9SChristian Marangi 					     sizeof(*rctx->sa_state), DMA_TO_DEVICE);
5859739f5f9SChristian Marangi 	err = dma_mapping_error(eip93->dev, rctx->sa_state_base);
5869739f5f9SChristian Marangi 	if (err)
5879739f5f9SChristian Marangi 		goto free_sa_state_ctr_dma;
5889739f5f9SChristian Marangi 
5899739f5f9SChristian Marangi skip_iv:
5909739f5f9SChristian Marangi 
5919739f5f9SChristian Marangi 	cdesc.pe_ctrl_stat_word = FIELD_PREP(EIP93_PE_CTRL_PE_READY_DES_TRING_OWN,
5929739f5f9SChristian Marangi 					     EIP93_PE_CTRL_HOST_READY);
5939739f5f9SChristian Marangi 	cdesc.sa_addr = rctx->sa_record_base;
5949739f5f9SChristian Marangi 	cdesc.arc4_addr = 0;
5959739f5f9SChristian Marangi 
5969739f5f9SChristian Marangi 	scoped_guard(spinlock_bh, &eip93->ring->idr_lock)
5979739f5f9SChristian Marangi 		crypto_async_idr = idr_alloc(&eip93->ring->crypto_async_idr, async, 0,
5989739f5f9SChristian Marangi 					     EIP93_RING_NUM - 1, GFP_ATOMIC);
5999739f5f9SChristian Marangi 
6009739f5f9SChristian Marangi 	cdesc.user_id = FIELD_PREP(EIP93_PE_USER_ID_CRYPTO_IDR, (u16)crypto_async_idr) |
6019739f5f9SChristian Marangi 			FIELD_PREP(EIP93_PE_USER_ID_DESC_FLAGS, rctx->desc_flags);
6029739f5f9SChristian Marangi 
6039739f5f9SChristian Marangi 	rctx->cdesc = &cdesc;
6049739f5f9SChristian Marangi 
6059739f5f9SChristian Marangi 	/* map DMA_BIDIRECTIONAL to invalidate cache on destination
6069739f5f9SChristian Marangi 	 * implies __dma_cache_wback_inv
6079739f5f9SChristian Marangi 	 */
6089739f5f9SChristian Marangi 	if (!dma_map_sg(eip93->dev, dst, rctx->dst_nents, DMA_BIDIRECTIONAL)) {
6099739f5f9SChristian Marangi 		err = -ENOMEM;
6109739f5f9SChristian Marangi 		goto free_sa_state_ctr_dma;
6119739f5f9SChristian Marangi 	}
6129739f5f9SChristian Marangi 
6139739f5f9SChristian Marangi 	if (src != dst &&
6149739f5f9SChristian Marangi 	    !dma_map_sg(eip93->dev, src, rctx->src_nents, DMA_TO_DEVICE)) {
6159739f5f9SChristian Marangi 		err = -ENOMEM;
6169739f5f9SChristian Marangi 		goto free_sg_dma;
6179739f5f9SChristian Marangi 	}
6189739f5f9SChristian Marangi 
6199739f5f9SChristian Marangi 	return eip93_scatter_combine(eip93, rctx, datalen, split, offsetin);
6209739f5f9SChristian Marangi 
6219739f5f9SChristian Marangi free_sg_dma:
6229739f5f9SChristian Marangi 	dma_unmap_sg(eip93->dev, dst, rctx->dst_nents, DMA_BIDIRECTIONAL);
6239739f5f9SChristian Marangi free_sa_state_ctr_dma:
6249739f5f9SChristian Marangi 	if (rctx->sa_state_ctr)
6259739f5f9SChristian Marangi 		dma_unmap_single(eip93->dev, rctx->sa_state_ctr_base,
6269739f5f9SChristian Marangi 				 sizeof(*rctx->sa_state_ctr),
6279739f5f9SChristian Marangi 				 DMA_TO_DEVICE);
6289739f5f9SChristian Marangi free_sa_state_ctr:
6299739f5f9SChristian Marangi 	kfree(rctx->sa_state_ctr);
6309739f5f9SChristian Marangi 	if (rctx->sa_state)
6319739f5f9SChristian Marangi 		dma_unmap_single(eip93->dev, rctx->sa_state_base,
6329739f5f9SChristian Marangi 				 sizeof(*rctx->sa_state),
6339739f5f9SChristian Marangi 				 DMA_TO_DEVICE);
6349739f5f9SChristian Marangi free_sa_state:
6359739f5f9SChristian Marangi 	kfree(rctx->sa_state);
6369739f5f9SChristian Marangi 
6379739f5f9SChristian Marangi 	return err;
6389739f5f9SChristian Marangi }
6399739f5f9SChristian Marangi 
6409739f5f9SChristian Marangi void eip93_unmap_dma(struct eip93_device *eip93, struct eip93_cipher_reqctx *rctx,
6419739f5f9SChristian Marangi 		     struct scatterlist *reqsrc, struct scatterlist *reqdst)
6429739f5f9SChristian Marangi {
6439739f5f9SChristian Marangi 	u32 len = rctx->assoclen + rctx->textsize;
6449739f5f9SChristian Marangi 	u32 authsize = rctx->authsize;
6459739f5f9SChristian Marangi 	u32 flags = rctx->flags;
6469739f5f9SChristian Marangi 	u32 *otag;
6479739f5f9SChristian Marangi 	int i;
6489739f5f9SChristian Marangi 
6499739f5f9SChristian Marangi 	if (rctx->sg_src == rctx->sg_dst) {
6509739f5f9SChristian Marangi 		dma_unmap_sg(eip93->dev, rctx->sg_dst, rctx->dst_nents,
6519739f5f9SChristian Marangi 			     DMA_BIDIRECTIONAL);
6529739f5f9SChristian Marangi 		goto process_tag;
6539739f5f9SChristian Marangi 	}
6549739f5f9SChristian Marangi 
6559739f5f9SChristian Marangi 	dma_unmap_sg(eip93->dev, rctx->sg_src, rctx->src_nents,
6569739f5f9SChristian Marangi 		     DMA_TO_DEVICE);
6579739f5f9SChristian Marangi 
6589739f5f9SChristian Marangi 	if (rctx->sg_src != reqsrc)
6599739f5f9SChristian Marangi 		eip93_free_sg_copy(len +  rctx->authsize, &rctx->sg_src);
6609739f5f9SChristian Marangi 
6619739f5f9SChristian Marangi 	dma_unmap_sg(eip93->dev, rctx->sg_dst, rctx->dst_nents,
6629739f5f9SChristian Marangi 		     DMA_BIDIRECTIONAL);
6639739f5f9SChristian Marangi 
6649739f5f9SChristian Marangi 	/* SHA tags need conversion from net-to-host */
6659739f5f9SChristian Marangi process_tag:
6669739f5f9SChristian Marangi 	if (IS_DECRYPT(flags))
6679739f5f9SChristian Marangi 		authsize = 0;
6689739f5f9SChristian Marangi 
6699739f5f9SChristian Marangi 	if (authsize) {
6709739f5f9SChristian Marangi 		if (!IS_HASH_MD5(flags)) {
6719739f5f9SChristian Marangi 			otag = sg_virt(rctx->sg_dst) + len;
6729739f5f9SChristian Marangi 			for (i = 0; i < (authsize / 4); i++)
6739739f5f9SChristian Marangi 				otag[i] = be32_to_cpu((__be32 __force)otag[i]);
6749739f5f9SChristian Marangi 		}
6759739f5f9SChristian Marangi 	}
6769739f5f9SChristian Marangi 
6779739f5f9SChristian Marangi 	if (rctx->sg_dst != reqdst) {
6789739f5f9SChristian Marangi 		sg_copy_from_buffer(reqdst, sg_nents(reqdst),
6799739f5f9SChristian Marangi 				    sg_virt(rctx->sg_dst), len + authsize);
6809739f5f9SChristian Marangi 		eip93_free_sg_copy(len + rctx->authsize, &rctx->sg_dst);
6819739f5f9SChristian Marangi 	}
6829739f5f9SChristian Marangi }
6839739f5f9SChristian Marangi 
6849739f5f9SChristian Marangi void eip93_handle_result(struct eip93_device *eip93, struct eip93_cipher_reqctx *rctx,
6859739f5f9SChristian Marangi 			 u8 *reqiv)
6869739f5f9SChristian Marangi {
6879739f5f9SChristian Marangi 	if (rctx->sa_state_ctr)
6889739f5f9SChristian Marangi 		dma_unmap_single(eip93->dev, rctx->sa_state_ctr_base,
6899739f5f9SChristian Marangi 				 sizeof(*rctx->sa_state_ctr),
6909739f5f9SChristian Marangi 				 DMA_FROM_DEVICE);
6919739f5f9SChristian Marangi 
6929739f5f9SChristian Marangi 	if (rctx->sa_state)
6939739f5f9SChristian Marangi 		dma_unmap_single(eip93->dev, rctx->sa_state_base,
6949739f5f9SChristian Marangi 				 sizeof(*rctx->sa_state),
6959739f5f9SChristian Marangi 				 DMA_FROM_DEVICE);
6969739f5f9SChristian Marangi 
6979739f5f9SChristian Marangi 	if (!IS_ECB(rctx->flags))
6989739f5f9SChristian Marangi 		memcpy(reqiv, rctx->sa_state->state_iv, rctx->ivsize);
6999739f5f9SChristian Marangi 
7009739f5f9SChristian Marangi 	kfree(rctx->sa_state_ctr);
7019739f5f9SChristian Marangi 	kfree(rctx->sa_state);
7029739f5f9SChristian Marangi }
7039739f5f9SChristian Marangi 
7049739f5f9SChristian Marangi int eip93_hmac_setkey(u32 ctx_flags, const u8 *key, unsigned int keylen,
7059739f5f9SChristian Marangi 		      unsigned int hashlen, u8 *dest_ipad, u8 *dest_opad,
7069739f5f9SChristian Marangi 		      bool skip_ipad)
7079739f5f9SChristian Marangi {
7089739f5f9SChristian Marangi 	u8 ipad[SHA256_BLOCK_SIZE], opad[SHA256_BLOCK_SIZE];
7099739f5f9SChristian Marangi 	struct crypto_ahash *ahash_tfm;
7109739f5f9SChristian Marangi 	struct eip93_hash_reqctx *rctx;
7119739f5f9SChristian Marangi 	struct ahash_request *req;
7129739f5f9SChristian Marangi 	DECLARE_CRYPTO_WAIT(wait);
7139739f5f9SChristian Marangi 	struct scatterlist sg[1];
7149739f5f9SChristian Marangi 	const char *alg_name;
7159739f5f9SChristian Marangi 	int i, ret;
7169739f5f9SChristian Marangi 
7179739f5f9SChristian Marangi 	switch (ctx_flags & EIP93_HASH_MASK) {
7189739f5f9SChristian Marangi 	case EIP93_HASH_SHA256:
7199739f5f9SChristian Marangi 		alg_name = "sha256-eip93";
7209739f5f9SChristian Marangi 		break;
7219739f5f9SChristian Marangi 	case EIP93_HASH_SHA224:
7229739f5f9SChristian Marangi 		alg_name = "sha224-eip93";
7239739f5f9SChristian Marangi 		break;
7249739f5f9SChristian Marangi 	case EIP93_HASH_SHA1:
7259739f5f9SChristian Marangi 		alg_name = "sha1-eip93";
7269739f5f9SChristian Marangi 		break;
7279739f5f9SChristian Marangi 	case EIP93_HASH_MD5:
7289739f5f9SChristian Marangi 		alg_name = "md5-eip93";
7299739f5f9SChristian Marangi 		break;
7309739f5f9SChristian Marangi 	default: /* Impossible */
7319739f5f9SChristian Marangi 		return -EINVAL;
7329739f5f9SChristian Marangi 	}
7339739f5f9SChristian Marangi 
7349739f5f9SChristian Marangi 	ahash_tfm = crypto_alloc_ahash(alg_name, 0, CRYPTO_ALG_ASYNC);
7359739f5f9SChristian Marangi 	if (IS_ERR(ahash_tfm))
7369739f5f9SChristian Marangi 		return PTR_ERR(ahash_tfm);
7379739f5f9SChristian Marangi 
7389739f5f9SChristian Marangi 	req = ahash_request_alloc(ahash_tfm, GFP_ATOMIC);
7399739f5f9SChristian Marangi 	if (!req) {
7409739f5f9SChristian Marangi 		ret = -ENOMEM;
7419739f5f9SChristian Marangi 		goto err_ahash;
7429739f5f9SChristian Marangi 	}
7439739f5f9SChristian Marangi 
7449739f5f9SChristian Marangi 	rctx = ahash_request_ctx_dma(req);
7459739f5f9SChristian Marangi 	crypto_init_wait(&wait);
7469739f5f9SChristian Marangi 	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
7479739f5f9SChristian Marangi 				   crypto_req_done, &wait);
7489739f5f9SChristian Marangi 
7499739f5f9SChristian Marangi 	/* Hash the key if > SHA256_BLOCK_SIZE */
7509739f5f9SChristian Marangi 	if (keylen > SHA256_BLOCK_SIZE) {
7519739f5f9SChristian Marangi 		sg_init_one(&sg[0], key, keylen);
7529739f5f9SChristian Marangi 
7539739f5f9SChristian Marangi 		ahash_request_set_crypt(req, sg, ipad, keylen);
7549739f5f9SChristian Marangi 		ret = crypto_wait_req(crypto_ahash_digest(req), &wait);
7559739f5f9SChristian Marangi 		if (ret)
7569739f5f9SChristian Marangi 			goto err_req;
7579739f5f9SChristian Marangi 
7589739f5f9SChristian Marangi 		keylen = hashlen;
7599739f5f9SChristian Marangi 	} else {
7609739f5f9SChristian Marangi 		memcpy(ipad, key, keylen);
7619739f5f9SChristian Marangi 	}
7629739f5f9SChristian Marangi 
7639739f5f9SChristian Marangi 	/* Copy to opad */
7649739f5f9SChristian Marangi 	memset(ipad + keylen, 0, SHA256_BLOCK_SIZE - keylen);
7659739f5f9SChristian Marangi 	memcpy(opad, ipad, SHA256_BLOCK_SIZE);
7669739f5f9SChristian Marangi 
7679739f5f9SChristian Marangi 	/* Pad with HMAC constants */
7689739f5f9SChristian Marangi 	for (i = 0; i < SHA256_BLOCK_SIZE; i++) {
7699739f5f9SChristian Marangi 		ipad[i] ^= HMAC_IPAD_VALUE;
7709739f5f9SChristian Marangi 		opad[i] ^= HMAC_OPAD_VALUE;
7719739f5f9SChristian Marangi 	}
7729739f5f9SChristian Marangi 
7739739f5f9SChristian Marangi 	if (skip_ipad) {
7749739f5f9SChristian Marangi 		memcpy(dest_ipad, ipad, SHA256_BLOCK_SIZE);
7759739f5f9SChristian Marangi 	} else {
7769739f5f9SChristian Marangi 		/* Hash ipad */
7779739f5f9SChristian Marangi 		sg_init_one(&sg[0], ipad, SHA256_BLOCK_SIZE);
7789739f5f9SChristian Marangi 		ahash_request_set_crypt(req, sg, dest_ipad, SHA256_BLOCK_SIZE);
7799739f5f9SChristian Marangi 		ret = crypto_ahash_init(req);
7809739f5f9SChristian Marangi 		if (ret)
7819739f5f9SChristian Marangi 			goto err_req;
7829739f5f9SChristian Marangi 
7839739f5f9SChristian Marangi 		/* Disable HASH_FINALIZE for ipad hash */
7849739f5f9SChristian Marangi 		rctx->partial_hash = true;
7859739f5f9SChristian Marangi 
7869739f5f9SChristian Marangi 		ret = crypto_wait_req(crypto_ahash_finup(req), &wait);
7879739f5f9SChristian Marangi 		if (ret)
7889739f5f9SChristian Marangi 			goto err_req;
7899739f5f9SChristian Marangi 	}
7909739f5f9SChristian Marangi 
7919739f5f9SChristian Marangi 	/* Hash opad */
7929739f5f9SChristian Marangi 	sg_init_one(&sg[0], opad, SHA256_BLOCK_SIZE);
7939739f5f9SChristian Marangi 	ahash_request_set_crypt(req, sg, dest_opad, SHA256_BLOCK_SIZE);
7949739f5f9SChristian Marangi 	ret = crypto_ahash_init(req);
7959739f5f9SChristian Marangi 	if (ret)
7969739f5f9SChristian Marangi 		goto err_req;
7979739f5f9SChristian Marangi 
7989739f5f9SChristian Marangi 	/* Disable HASH_FINALIZE for opad hash */
7999739f5f9SChristian Marangi 	rctx->partial_hash = true;
8009739f5f9SChristian Marangi 
8019739f5f9SChristian Marangi 	ret = crypto_wait_req(crypto_ahash_finup(req), &wait);
8029739f5f9SChristian Marangi 	if (ret)
8039739f5f9SChristian Marangi 		goto err_req;
8049739f5f9SChristian Marangi 
8059739f5f9SChristian Marangi 	if (!IS_HASH_MD5(ctx_flags)) {
8069739f5f9SChristian Marangi 		for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++) {
8079739f5f9SChristian Marangi 			u32 *ipad_hash = (u32 *)dest_ipad;
8089739f5f9SChristian Marangi 			u32 *opad_hash = (u32 *)dest_opad;
8099739f5f9SChristian Marangi 
8109739f5f9SChristian Marangi 			if (!skip_ipad)
8119739f5f9SChristian Marangi 				ipad_hash[i] = (u32 __force)cpu_to_be32(ipad_hash[i]);
8129739f5f9SChristian Marangi 			opad_hash[i] = (u32 __force)cpu_to_be32(opad_hash[i]);
8139739f5f9SChristian Marangi 		}
8149739f5f9SChristian Marangi 	}
8159739f5f9SChristian Marangi 
8169739f5f9SChristian Marangi err_req:
8179739f5f9SChristian Marangi 	ahash_request_free(req);
8189739f5f9SChristian Marangi err_ahash:
8199739f5f9SChristian Marangi 	crypto_free_ahash(ahash_tfm);
8209739f5f9SChristian Marangi 
8219739f5f9SChristian Marangi 	return ret;
8229739f5f9SChristian Marangi }
823