162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   Driver for ARTPEC-6 crypto block using the kernel asynchronous crypto api.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *    Copyright (C) 2014-2017  Axis Communications AB
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bitfield.h>
1062306a36Sopenharmony_ci#include <linux/crypto.h>
1162306a36Sopenharmony_ci#include <linux/debugfs.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1462306a36Sopenharmony_ci#include <linux/fault-inject.h>
1562306a36Sopenharmony_ci#include <linux/init.h>
1662306a36Sopenharmony_ci#include <linux/interrupt.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci#include <linux/list.h>
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/of.h>
2162306a36Sopenharmony_ci#include <linux/platform_device.h>
2262306a36Sopenharmony_ci#include <linux/scatterlist.h>
2362306a36Sopenharmony_ci#include <linux/slab.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <crypto/aes.h>
2662306a36Sopenharmony_ci#include <crypto/gcm.h>
2762306a36Sopenharmony_ci#include <crypto/internal/aead.h>
2862306a36Sopenharmony_ci#include <crypto/internal/hash.h>
2962306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
3062306a36Sopenharmony_ci#include <crypto/scatterwalk.h>
3162306a36Sopenharmony_ci#include <crypto/sha1.h>
3262306a36Sopenharmony_ci#include <crypto/sha2.h>
3362306a36Sopenharmony_ci#include <crypto/xts.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* Max length of a line in all cache levels for Artpec SoCs. */
3662306a36Sopenharmony_ci#define ARTPEC_CACHE_LINE_MAX	32
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define PDMA_OUT_CFG		0x0000
3962306a36Sopenharmony_ci#define PDMA_OUT_BUF_CFG	0x0004
4062306a36Sopenharmony_ci#define PDMA_OUT_CMD		0x0008
4162306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_PUSH	0x0010
4262306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_STAT	0x0014
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define A6_PDMA_IN_CFG		0x0028
4562306a36Sopenharmony_ci#define A6_PDMA_IN_BUF_CFG	0x002c
4662306a36Sopenharmony_ci#define A6_PDMA_IN_CMD		0x0030
4762306a36Sopenharmony_ci#define A6_PDMA_IN_STATQ_PUSH	0x0038
4862306a36Sopenharmony_ci#define A6_PDMA_IN_DESCRQ_PUSH	0x0044
4962306a36Sopenharmony_ci#define A6_PDMA_IN_DESCRQ_STAT	0x0048
5062306a36Sopenharmony_ci#define A6_PDMA_INTR_MASK	0x0068
5162306a36Sopenharmony_ci#define A6_PDMA_ACK_INTR	0x006c
5262306a36Sopenharmony_ci#define A6_PDMA_MASKED_INTR	0x0074
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define A7_PDMA_IN_CFG		0x002c
5562306a36Sopenharmony_ci#define A7_PDMA_IN_BUF_CFG	0x0030
5662306a36Sopenharmony_ci#define A7_PDMA_IN_CMD		0x0034
5762306a36Sopenharmony_ci#define A7_PDMA_IN_STATQ_PUSH	0x003c
5862306a36Sopenharmony_ci#define A7_PDMA_IN_DESCRQ_PUSH	0x0048
5962306a36Sopenharmony_ci#define A7_PDMA_IN_DESCRQ_STAT	0x004C
6062306a36Sopenharmony_ci#define A7_PDMA_INTR_MASK	0x006c
6162306a36Sopenharmony_ci#define A7_PDMA_ACK_INTR	0x0070
6262306a36Sopenharmony_ci#define A7_PDMA_MASKED_INTR	0x0078
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define PDMA_OUT_CFG_EN				BIT(0)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define PDMA_OUT_BUF_CFG_DATA_BUF_SIZE		GENMASK(4, 0)
6762306a36Sopenharmony_ci#define PDMA_OUT_BUF_CFG_DESCR_BUF_SIZE		GENMASK(9, 5)
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define PDMA_OUT_CMD_START			BIT(0)
7062306a36Sopenharmony_ci#define A6_PDMA_OUT_CMD_STOP			BIT(3)
7162306a36Sopenharmony_ci#define A7_PDMA_OUT_CMD_STOP			BIT(2)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_PUSH_LEN		GENMASK(5, 0)
7462306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_PUSH_ADDR		GENMASK(31, 6)
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_STAT_LEVEL		GENMASK(3, 0)
7762306a36Sopenharmony_ci#define PDMA_OUT_DESCRQ_STAT_SIZE		GENMASK(7, 4)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define PDMA_IN_CFG_EN				BIT(0)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define PDMA_IN_BUF_CFG_DATA_BUF_SIZE		GENMASK(4, 0)
8262306a36Sopenharmony_ci#define PDMA_IN_BUF_CFG_DESCR_BUF_SIZE		GENMASK(9, 5)
8362306a36Sopenharmony_ci#define PDMA_IN_BUF_CFG_STAT_BUF_SIZE		GENMASK(14, 10)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define PDMA_IN_CMD_START			BIT(0)
8662306a36Sopenharmony_ci#define A6_PDMA_IN_CMD_FLUSH_STAT		BIT(2)
8762306a36Sopenharmony_ci#define A6_PDMA_IN_CMD_STOP			BIT(3)
8862306a36Sopenharmony_ci#define A7_PDMA_IN_CMD_FLUSH_STAT		BIT(1)
8962306a36Sopenharmony_ci#define A7_PDMA_IN_CMD_STOP			BIT(2)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define PDMA_IN_STATQ_PUSH_LEN			GENMASK(5, 0)
9262306a36Sopenharmony_ci#define PDMA_IN_STATQ_PUSH_ADDR			GENMASK(31, 6)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define PDMA_IN_DESCRQ_PUSH_LEN			GENMASK(5, 0)
9562306a36Sopenharmony_ci#define PDMA_IN_DESCRQ_PUSH_ADDR		GENMASK(31, 6)
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define PDMA_IN_DESCRQ_STAT_LEVEL		GENMASK(3, 0)
9862306a36Sopenharmony_ci#define PDMA_IN_DESCRQ_STAT_SIZE		GENMASK(7, 4)
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define A6_PDMA_INTR_MASK_IN_DATA		BIT(2)
10162306a36Sopenharmony_ci#define A6_PDMA_INTR_MASK_IN_EOP		BIT(3)
10262306a36Sopenharmony_ci#define A6_PDMA_INTR_MASK_IN_EOP_FLUSH		BIT(4)
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define A7_PDMA_INTR_MASK_IN_DATA		BIT(3)
10562306a36Sopenharmony_ci#define A7_PDMA_INTR_MASK_IN_EOP		BIT(4)
10662306a36Sopenharmony_ci#define A7_PDMA_INTR_MASK_IN_EOP_FLUSH		BIT(5)
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define A6_CRY_MD_OPER		GENMASK(19, 16)
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define A6_CRY_MD_HASH_SEL_CTX	GENMASK(21, 20)
11162306a36Sopenharmony_ci#define A6_CRY_MD_HASH_HMAC_FIN	BIT(23)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#define A6_CRY_MD_CIPHER_LEN	GENMASK(21, 20)
11462306a36Sopenharmony_ci#define A6_CRY_MD_CIPHER_DECR	BIT(22)
11562306a36Sopenharmony_ci#define A6_CRY_MD_CIPHER_TWEAK	BIT(23)
11662306a36Sopenharmony_ci#define A6_CRY_MD_CIPHER_DSEQ	BIT(24)
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define A7_CRY_MD_OPER		GENMASK(11, 8)
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define A7_CRY_MD_HASH_SEL_CTX	GENMASK(13, 12)
12162306a36Sopenharmony_ci#define A7_CRY_MD_HASH_HMAC_FIN	BIT(15)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define A7_CRY_MD_CIPHER_LEN	GENMASK(13, 12)
12462306a36Sopenharmony_ci#define A7_CRY_MD_CIPHER_DECR	BIT(14)
12562306a36Sopenharmony_ci#define A7_CRY_MD_CIPHER_TWEAK	BIT(15)
12662306a36Sopenharmony_ci#define A7_CRY_MD_CIPHER_DSEQ	BIT(16)
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/* DMA metadata constants */
12962306a36Sopenharmony_ci#define regk_crypto_aes_cbc     0x00000002
13062306a36Sopenharmony_ci#define regk_crypto_aes_ctr     0x00000003
13162306a36Sopenharmony_ci#define regk_crypto_aes_ecb     0x00000001
13262306a36Sopenharmony_ci#define regk_crypto_aes_gcm     0x00000004
13362306a36Sopenharmony_ci#define regk_crypto_aes_xts     0x00000005
13462306a36Sopenharmony_ci#define regk_crypto_cache       0x00000002
13562306a36Sopenharmony_ci#define a6_regk_crypto_dlkey    0x0000000a
13662306a36Sopenharmony_ci#define a7_regk_crypto_dlkey    0x0000000e
13762306a36Sopenharmony_ci#define regk_crypto_ext         0x00000001
13862306a36Sopenharmony_ci#define regk_crypto_hmac_sha1   0x00000007
13962306a36Sopenharmony_ci#define regk_crypto_hmac_sha256 0x00000009
14062306a36Sopenharmony_ci#define regk_crypto_init        0x00000000
14162306a36Sopenharmony_ci#define regk_crypto_key_128     0x00000000
14262306a36Sopenharmony_ci#define regk_crypto_key_192     0x00000001
14362306a36Sopenharmony_ci#define regk_crypto_key_256     0x00000002
14462306a36Sopenharmony_ci#define regk_crypto_null        0x00000000
14562306a36Sopenharmony_ci#define regk_crypto_sha1        0x00000006
14662306a36Sopenharmony_ci#define regk_crypto_sha256      0x00000008
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/* DMA descriptor structures */
14962306a36Sopenharmony_cistruct pdma_descr_ctrl  {
15062306a36Sopenharmony_ci	unsigned char short_descr : 1;
15162306a36Sopenharmony_ci	unsigned char pad1        : 1;
15262306a36Sopenharmony_ci	unsigned char eop         : 1;
15362306a36Sopenharmony_ci	unsigned char intr        : 1;
15462306a36Sopenharmony_ci	unsigned char short_len   : 3;
15562306a36Sopenharmony_ci	unsigned char pad2        : 1;
15662306a36Sopenharmony_ci} __packed;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistruct pdma_data_descr {
15962306a36Sopenharmony_ci	unsigned int len : 24;
16062306a36Sopenharmony_ci	unsigned int buf : 32;
16162306a36Sopenharmony_ci} __packed;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistruct pdma_short_descr {
16462306a36Sopenharmony_ci	unsigned char data[7];
16562306a36Sopenharmony_ci} __packed;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistruct pdma_descr {
16862306a36Sopenharmony_ci	struct pdma_descr_ctrl ctrl;
16962306a36Sopenharmony_ci	union {
17062306a36Sopenharmony_ci		struct pdma_data_descr   data;
17162306a36Sopenharmony_ci		struct pdma_short_descr  shrt;
17262306a36Sopenharmony_ci	};
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistruct pdma_stat_descr {
17662306a36Sopenharmony_ci	unsigned char pad1        : 1;
17762306a36Sopenharmony_ci	unsigned char pad2        : 1;
17862306a36Sopenharmony_ci	unsigned char eop         : 1;
17962306a36Sopenharmony_ci	unsigned char pad3        : 5;
18062306a36Sopenharmony_ci	unsigned int  len         : 24;
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/* Each descriptor array can hold max 64 entries */
18462306a36Sopenharmony_ci#define PDMA_DESCR_COUNT	64
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci#define MODULE_NAME   "Artpec-6 CA"
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/* Hash modes (including HMAC variants) */
18962306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_HASH_SHA1	1
19062306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_HASH_SHA256	2
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/* Crypto modes */
19362306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_ECB	1
19462306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_CBC	2
19562306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_CTR	3
19662306a36Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_XTS	5
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/* The PDMA is a DMA-engine tightly coupled with a ciphering engine.
19962306a36Sopenharmony_ci * It operates on a descriptor array with up to 64 descriptor entries.
20062306a36Sopenharmony_ci * The arrays must be 64 byte aligned in memory.
20162306a36Sopenharmony_ci *
20262306a36Sopenharmony_ci * The ciphering unit has no registers and is completely controlled by
20362306a36Sopenharmony_ci * a 4-byte metadata that is inserted at the beginning of each dma packet.
20462306a36Sopenharmony_ci *
20562306a36Sopenharmony_ci * A dma packet is a sequence of descriptors terminated by setting the .eop
20662306a36Sopenharmony_ci * field in the final descriptor of the packet.
20762306a36Sopenharmony_ci *
20862306a36Sopenharmony_ci * Multiple packets are used for providing context data, key data and
20962306a36Sopenharmony_ci * the plain/ciphertext.
21062306a36Sopenharmony_ci *
21162306a36Sopenharmony_ci *   PDMA Descriptors (Array)
21262306a36Sopenharmony_ci *  +------+------+------+~~+-------+------+----
21362306a36Sopenharmony_ci *  |  0   |  1   |  2   |~~| 11 EOP|  12  |  ....
21462306a36Sopenharmony_ci *  +--+---+--+---+----+-+~~+-------+----+-+----
21562306a36Sopenharmony_ci *     |      |        |       |         |
21662306a36Sopenharmony_ci *     |      |        |       |         |
21762306a36Sopenharmony_ci *   __|__  +-------++-------++-------+ +----+
21862306a36Sopenharmony_ci *  | MD  | |Payload||Payload||Payload| | MD |
21962306a36Sopenharmony_ci *  +-----+ +-------++-------++-------+ +----+
22062306a36Sopenharmony_ci */
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistruct artpec6_crypto_bounce_buffer {
22362306a36Sopenharmony_ci	struct list_head list;
22462306a36Sopenharmony_ci	size_t length;
22562306a36Sopenharmony_ci	struct scatterlist *sg;
22662306a36Sopenharmony_ci	size_t offset;
22762306a36Sopenharmony_ci	/* buf is aligned to ARTPEC_CACHE_LINE_MAX and
22862306a36Sopenharmony_ci	 * holds up to ARTPEC_CACHE_LINE_MAX bytes data.
22962306a36Sopenharmony_ci	 */
23062306a36Sopenharmony_ci	void *buf;
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistruct artpec6_crypto_dma_map {
23462306a36Sopenharmony_ci	dma_addr_t dma_addr;
23562306a36Sopenharmony_ci	size_t size;
23662306a36Sopenharmony_ci	enum dma_data_direction dir;
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistruct artpec6_crypto_dma_descriptors {
24062306a36Sopenharmony_ci	struct pdma_descr out[PDMA_DESCR_COUNT] __aligned(64);
24162306a36Sopenharmony_ci	struct pdma_descr in[PDMA_DESCR_COUNT] __aligned(64);
24262306a36Sopenharmony_ci	u32 stat[PDMA_DESCR_COUNT] __aligned(64);
24362306a36Sopenharmony_ci	struct list_head bounce_buffers;
24462306a36Sopenharmony_ci	/* Enough maps for all out/in buffers, and all three descr. arrays */
24562306a36Sopenharmony_ci	struct artpec6_crypto_dma_map maps[PDMA_DESCR_COUNT * 2 + 2];
24662306a36Sopenharmony_ci	dma_addr_t out_dma_addr;
24762306a36Sopenharmony_ci	dma_addr_t in_dma_addr;
24862306a36Sopenharmony_ci	dma_addr_t stat_dma_addr;
24962306a36Sopenharmony_ci	size_t out_cnt;
25062306a36Sopenharmony_ci	size_t in_cnt;
25162306a36Sopenharmony_ci	size_t map_count;
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cienum artpec6_crypto_variant {
25562306a36Sopenharmony_ci	ARTPEC6_CRYPTO,
25662306a36Sopenharmony_ci	ARTPEC7_CRYPTO,
25762306a36Sopenharmony_ci};
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistruct artpec6_crypto {
26062306a36Sopenharmony_ci	void __iomem *base;
26162306a36Sopenharmony_ci	spinlock_t queue_lock;
26262306a36Sopenharmony_ci	struct list_head queue; /* waiting for pdma fifo space */
26362306a36Sopenharmony_ci	struct list_head pending; /* submitted to pdma fifo */
26462306a36Sopenharmony_ci	struct tasklet_struct task;
26562306a36Sopenharmony_ci	struct kmem_cache *dma_cache;
26662306a36Sopenharmony_ci	int pending_count;
26762306a36Sopenharmony_ci	struct timer_list timer;
26862306a36Sopenharmony_ci	enum artpec6_crypto_variant variant;
26962306a36Sopenharmony_ci	void *pad_buffer; /* cache-aligned block padding buffer */
27062306a36Sopenharmony_ci	void *zero_buffer;
27162306a36Sopenharmony_ci};
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cienum artpec6_crypto_hash_flags {
27462306a36Sopenharmony_ci	HASH_FLAG_INIT_CTX = 2,
27562306a36Sopenharmony_ci	HASH_FLAG_UPDATE = 4,
27662306a36Sopenharmony_ci	HASH_FLAG_FINALIZE = 8,
27762306a36Sopenharmony_ci	HASH_FLAG_HMAC = 16,
27862306a36Sopenharmony_ci	HASH_FLAG_UPDATE_KEY = 32,
27962306a36Sopenharmony_ci};
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistruct artpec6_crypto_req_common {
28262306a36Sopenharmony_ci	struct list_head list;
28362306a36Sopenharmony_ci	struct list_head complete_in_progress;
28462306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma;
28562306a36Sopenharmony_ci	struct crypto_async_request *req;
28662306a36Sopenharmony_ci	void (*complete)(struct crypto_async_request *req);
28762306a36Sopenharmony_ci	gfp_t gfp_flags;
28862306a36Sopenharmony_ci};
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistruct artpec6_hash_request_context {
29162306a36Sopenharmony_ci	char partial_buffer[SHA256_BLOCK_SIZE];
29262306a36Sopenharmony_ci	char partial_buffer_out[SHA256_BLOCK_SIZE];
29362306a36Sopenharmony_ci	char key_buffer[SHA256_BLOCK_SIZE];
29462306a36Sopenharmony_ci	char pad_buffer[SHA256_BLOCK_SIZE + 32];
29562306a36Sopenharmony_ci	unsigned char digeststate[SHA256_DIGEST_SIZE];
29662306a36Sopenharmony_ci	size_t partial_bytes;
29762306a36Sopenharmony_ci	u64 digcnt;
29862306a36Sopenharmony_ci	u32 key_md;
29962306a36Sopenharmony_ci	u32 hash_md;
30062306a36Sopenharmony_ci	enum artpec6_crypto_hash_flags hash_flags;
30162306a36Sopenharmony_ci	struct artpec6_crypto_req_common common;
30262306a36Sopenharmony_ci};
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistruct artpec6_hash_export_state {
30562306a36Sopenharmony_ci	char partial_buffer[SHA256_BLOCK_SIZE];
30662306a36Sopenharmony_ci	unsigned char digeststate[SHA256_DIGEST_SIZE];
30762306a36Sopenharmony_ci	size_t partial_bytes;
30862306a36Sopenharmony_ci	u64 digcnt;
30962306a36Sopenharmony_ci	int oper;
31062306a36Sopenharmony_ci	unsigned int hash_flags;
31162306a36Sopenharmony_ci};
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistruct artpec6_hashalg_context {
31462306a36Sopenharmony_ci	char hmac_key[SHA256_BLOCK_SIZE];
31562306a36Sopenharmony_ci	size_t hmac_key_length;
31662306a36Sopenharmony_ci	struct crypto_shash *child_hash;
31762306a36Sopenharmony_ci};
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistruct artpec6_crypto_request_context {
32062306a36Sopenharmony_ci	u32 cipher_md;
32162306a36Sopenharmony_ci	bool decrypt;
32262306a36Sopenharmony_ci	struct artpec6_crypto_req_common common;
32362306a36Sopenharmony_ci};
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistruct artpec6_cryptotfm_context {
32662306a36Sopenharmony_ci	unsigned char aes_key[2*AES_MAX_KEY_SIZE];
32762306a36Sopenharmony_ci	size_t key_length;
32862306a36Sopenharmony_ci	u32 key_md;
32962306a36Sopenharmony_ci	int crypto_type;
33062306a36Sopenharmony_ci	struct crypto_sync_skcipher *fallback;
33162306a36Sopenharmony_ci};
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistruct artpec6_crypto_aead_hw_ctx {
33462306a36Sopenharmony_ci	__be64	aad_length_bits;
33562306a36Sopenharmony_ci	__be64  text_length_bits;
33662306a36Sopenharmony_ci	__u8	J0[AES_BLOCK_SIZE];
33762306a36Sopenharmony_ci};
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistruct artpec6_crypto_aead_req_ctx {
34062306a36Sopenharmony_ci	struct artpec6_crypto_aead_hw_ctx hw_ctx;
34162306a36Sopenharmony_ci	u32 cipher_md;
34262306a36Sopenharmony_ci	bool decrypt;
34362306a36Sopenharmony_ci	struct artpec6_crypto_req_common common;
34462306a36Sopenharmony_ci	__u8 decryption_tag[AES_BLOCK_SIZE] ____cacheline_aligned;
34562306a36Sopenharmony_ci};
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci/* The crypto framework makes it hard to avoid this global. */
34862306a36Sopenharmony_cistatic struct device *artpec6_crypto_dev;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION
35162306a36Sopenharmony_cistatic DECLARE_FAULT_ATTR(artpec6_crypto_fail_status_read);
35262306a36Sopenharmony_cistatic DECLARE_FAULT_ATTR(artpec6_crypto_fail_dma_array_full);
35362306a36Sopenharmony_ci#endif
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cienum {
35662306a36Sopenharmony_ci	ARTPEC6_CRYPTO_PREPARE_HASH_NO_START,
35762306a36Sopenharmony_ci	ARTPEC6_CRYPTO_PREPARE_HASH_START,
35862306a36Sopenharmony_ci};
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic int artpec6_crypto_prepare_aead(struct aead_request *areq);
36162306a36Sopenharmony_cistatic int artpec6_crypto_prepare_crypto(struct skcipher_request *areq);
36262306a36Sopenharmony_cistatic int artpec6_crypto_prepare_hash(struct ahash_request *areq);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic void
36562306a36Sopenharmony_ciartpec6_crypto_complete_crypto(struct crypto_async_request *req);
36662306a36Sopenharmony_cistatic void
36762306a36Sopenharmony_ciartpec6_crypto_complete_cbc_encrypt(struct crypto_async_request *req);
36862306a36Sopenharmony_cistatic void
36962306a36Sopenharmony_ciartpec6_crypto_complete_cbc_decrypt(struct crypto_async_request *req);
37062306a36Sopenharmony_cistatic void
37162306a36Sopenharmony_ciartpec6_crypto_complete_aead(struct crypto_async_request *req);
37262306a36Sopenharmony_cistatic void
37362306a36Sopenharmony_ciartpec6_crypto_complete_hash(struct crypto_async_request *req);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic int
37662306a36Sopenharmony_ciartpec6_crypto_common_destroy(struct artpec6_crypto_req_common *common);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic void
37962306a36Sopenharmony_ciartpec6_crypto_start_dma(struct artpec6_crypto_req_common *common);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistruct artpec6_crypto_walk {
38262306a36Sopenharmony_ci	struct scatterlist *sg;
38362306a36Sopenharmony_ci	size_t offset;
38462306a36Sopenharmony_ci};
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic void artpec6_crypto_walk_init(struct artpec6_crypto_walk *awalk,
38762306a36Sopenharmony_ci				     struct scatterlist *sg)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	awalk->sg = sg;
39062306a36Sopenharmony_ci	awalk->offset = 0;
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic size_t artpec6_crypto_walk_advance(struct artpec6_crypto_walk *awalk,
39462306a36Sopenharmony_ci					  size_t nbytes)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	while (nbytes && awalk->sg) {
39762306a36Sopenharmony_ci		size_t piece;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci		WARN_ON(awalk->offset > awalk->sg->length);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		piece = min(nbytes, (size_t)awalk->sg->length - awalk->offset);
40262306a36Sopenharmony_ci		nbytes -= piece;
40362306a36Sopenharmony_ci		awalk->offset += piece;
40462306a36Sopenharmony_ci		if (awalk->offset == awalk->sg->length) {
40562306a36Sopenharmony_ci			awalk->sg = sg_next(awalk->sg);
40662306a36Sopenharmony_ci			awalk->offset = 0;
40762306a36Sopenharmony_ci		}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	return nbytes;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic size_t
41562306a36Sopenharmony_ciartpec6_crypto_walk_chunklen(const struct artpec6_crypto_walk *awalk)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	WARN_ON(awalk->sg->length == awalk->offset);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	return awalk->sg->length - awalk->offset;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic dma_addr_t
42362306a36Sopenharmony_ciartpec6_crypto_walk_chunk_phys(const struct artpec6_crypto_walk *awalk)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	return sg_phys(awalk->sg) + awalk->offset;
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic void
42962306a36Sopenharmony_ciartpec6_crypto_copy_bounce_buffers(struct artpec6_crypto_req_common *common)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
43262306a36Sopenharmony_ci	struct artpec6_crypto_bounce_buffer *b;
43362306a36Sopenharmony_ci	struct artpec6_crypto_bounce_buffer *next;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	list_for_each_entry_safe(b, next, &dma->bounce_buffers, list) {
43662306a36Sopenharmony_ci		pr_debug("bounce entry %p: %zu bytes @ %zu from %p\n",
43762306a36Sopenharmony_ci			 b, b->length, b->offset, b->buf);
43862306a36Sopenharmony_ci		sg_pcopy_from_buffer(b->sg,
43962306a36Sopenharmony_ci				   1,
44062306a36Sopenharmony_ci				   b->buf,
44162306a36Sopenharmony_ci				   b->length,
44262306a36Sopenharmony_ci				   b->offset);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		list_del(&b->list);
44562306a36Sopenharmony_ci		kfree(b);
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic inline bool artpec6_crypto_busy(void)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
45262306a36Sopenharmony_ci	int fifo_count = ac->pending_count;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	return fifo_count > 6;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int artpec6_crypto_submit(struct artpec6_crypto_req_common *req)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
46062306a36Sopenharmony_ci	int ret = -EBUSY;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	spin_lock_bh(&ac->queue_lock);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (!artpec6_crypto_busy()) {
46562306a36Sopenharmony_ci		list_add_tail(&req->list, &ac->pending);
46662306a36Sopenharmony_ci		artpec6_crypto_start_dma(req);
46762306a36Sopenharmony_ci		ret = -EINPROGRESS;
46862306a36Sopenharmony_ci	} else if (req->req->flags & CRYPTO_TFM_REQ_MAY_BACKLOG) {
46962306a36Sopenharmony_ci		list_add_tail(&req->list, &ac->queue);
47062306a36Sopenharmony_ci	} else {
47162306a36Sopenharmony_ci		artpec6_crypto_common_destroy(req);
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	spin_unlock_bh(&ac->queue_lock);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	return ret;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cistatic void artpec6_crypto_start_dma(struct artpec6_crypto_req_common *common)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
48262306a36Sopenharmony_ci	enum artpec6_crypto_variant variant = ac->variant;
48362306a36Sopenharmony_ci	void __iomem *base = ac->base;
48462306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
48562306a36Sopenharmony_ci	u32 ind, statd, outd;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	/* Make descriptor content visible to the DMA before starting it. */
48862306a36Sopenharmony_ci	wmb();
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	ind = FIELD_PREP(PDMA_IN_DESCRQ_PUSH_LEN, dma->in_cnt - 1) |
49162306a36Sopenharmony_ci	      FIELD_PREP(PDMA_IN_DESCRQ_PUSH_ADDR, dma->in_dma_addr >> 6);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	statd = FIELD_PREP(PDMA_IN_STATQ_PUSH_LEN, dma->in_cnt - 1) |
49462306a36Sopenharmony_ci		FIELD_PREP(PDMA_IN_STATQ_PUSH_ADDR, dma->stat_dma_addr >> 6);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	outd = FIELD_PREP(PDMA_OUT_DESCRQ_PUSH_LEN, dma->out_cnt - 1) |
49762306a36Sopenharmony_ci	       FIELD_PREP(PDMA_OUT_DESCRQ_PUSH_ADDR, dma->out_dma_addr >> 6);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO) {
50062306a36Sopenharmony_ci		writel_relaxed(ind, base + A6_PDMA_IN_DESCRQ_PUSH);
50162306a36Sopenharmony_ci		writel_relaxed(statd, base + A6_PDMA_IN_STATQ_PUSH);
50262306a36Sopenharmony_ci		writel_relaxed(PDMA_IN_CMD_START, base + A6_PDMA_IN_CMD);
50362306a36Sopenharmony_ci	} else {
50462306a36Sopenharmony_ci		writel_relaxed(ind, base + A7_PDMA_IN_DESCRQ_PUSH);
50562306a36Sopenharmony_ci		writel_relaxed(statd, base + A7_PDMA_IN_STATQ_PUSH);
50662306a36Sopenharmony_ci		writel_relaxed(PDMA_IN_CMD_START, base + A7_PDMA_IN_CMD);
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	writel_relaxed(outd, base + PDMA_OUT_DESCRQ_PUSH);
51062306a36Sopenharmony_ci	writel_relaxed(PDMA_OUT_CMD_START, base + PDMA_OUT_CMD);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	ac->pending_count++;
51362306a36Sopenharmony_ci}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic void
51662306a36Sopenharmony_ciartpec6_crypto_init_dma_operation(struct artpec6_crypto_req_common *common)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	dma->out_cnt = 0;
52162306a36Sopenharmony_ci	dma->in_cnt = 0;
52262306a36Sopenharmony_ci	dma->map_count = 0;
52362306a36Sopenharmony_ci	INIT_LIST_HEAD(&dma->bounce_buffers);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic bool fault_inject_dma_descr(void)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION
52962306a36Sopenharmony_ci	return should_fail(&artpec6_crypto_fail_dma_array_full, 1);
53062306a36Sopenharmony_ci#else
53162306a36Sopenharmony_ci	return false;
53262306a36Sopenharmony_ci#endif
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci/** artpec6_crypto_setup_out_descr_phys - Setup an out channel with a
53662306a36Sopenharmony_ci *                                        physical address
53762306a36Sopenharmony_ci *
53862306a36Sopenharmony_ci * @addr: The physical address of the data buffer
53962306a36Sopenharmony_ci * @len:  The length of the data buffer
54062306a36Sopenharmony_ci * @eop:  True if this is the last buffer in the packet
54162306a36Sopenharmony_ci *
54262306a36Sopenharmony_ci * @return 0 on success or -ENOSPC if there are no more descriptors available
54362306a36Sopenharmony_ci */
54462306a36Sopenharmony_cistatic int
54562306a36Sopenharmony_ciartpec6_crypto_setup_out_descr_phys(struct artpec6_crypto_req_common *common,
54662306a36Sopenharmony_ci				    dma_addr_t addr, size_t len, bool eop)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
54962306a36Sopenharmony_ci	struct pdma_descr *d;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	if (dma->out_cnt >= PDMA_DESCR_COUNT ||
55262306a36Sopenharmony_ci	    fault_inject_dma_descr()) {
55362306a36Sopenharmony_ci		pr_err("No free OUT DMA descriptors available!\n");
55462306a36Sopenharmony_ci		return -ENOSPC;
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	d = &dma->out[dma->out_cnt++];
55862306a36Sopenharmony_ci	memset(d, 0, sizeof(*d));
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	d->ctrl.short_descr = 0;
56162306a36Sopenharmony_ci	d->ctrl.eop = eop;
56262306a36Sopenharmony_ci	d->data.len = len;
56362306a36Sopenharmony_ci	d->data.buf = addr;
56462306a36Sopenharmony_ci	return 0;
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci/** artpec6_crypto_setup_out_descr_short - Setup a short out descriptor
56862306a36Sopenharmony_ci *
56962306a36Sopenharmony_ci * @dst: The virtual address of the data
57062306a36Sopenharmony_ci * @len: The length of the data, must be between 1 to 7 bytes
57162306a36Sopenharmony_ci * @eop: True if this is the last buffer in the packet
57262306a36Sopenharmony_ci *
57362306a36Sopenharmony_ci * @return 0 on success
57462306a36Sopenharmony_ci *	-ENOSPC if no more descriptors are available
57562306a36Sopenharmony_ci *	-EINVAL if the data length exceeds 7 bytes
57662306a36Sopenharmony_ci */
57762306a36Sopenharmony_cistatic int
57862306a36Sopenharmony_ciartpec6_crypto_setup_out_descr_short(struct artpec6_crypto_req_common *common,
57962306a36Sopenharmony_ci				     void *dst, unsigned int len, bool eop)
58062306a36Sopenharmony_ci{
58162306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
58262306a36Sopenharmony_ci	struct pdma_descr *d;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (dma->out_cnt >= PDMA_DESCR_COUNT ||
58562306a36Sopenharmony_ci	    fault_inject_dma_descr()) {
58662306a36Sopenharmony_ci		pr_err("No free OUT DMA descriptors available!\n");
58762306a36Sopenharmony_ci		return -ENOSPC;
58862306a36Sopenharmony_ci	} else if (len > 7 || len < 1) {
58962306a36Sopenharmony_ci		return -EINVAL;
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci	d = &dma->out[dma->out_cnt++];
59262306a36Sopenharmony_ci	memset(d, 0, sizeof(*d));
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	d->ctrl.short_descr = 1;
59562306a36Sopenharmony_ci	d->ctrl.short_len = len;
59662306a36Sopenharmony_ci	d->ctrl.eop = eop;
59762306a36Sopenharmony_ci	memcpy(d->shrt.data, dst, len);
59862306a36Sopenharmony_ci	return 0;
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic int artpec6_crypto_dma_map_page(struct artpec6_crypto_req_common *common,
60262306a36Sopenharmony_ci				      struct page *page, size_t offset,
60362306a36Sopenharmony_ci				      size_t size,
60462306a36Sopenharmony_ci				      enum dma_data_direction dir,
60562306a36Sopenharmony_ci				      dma_addr_t *dma_addr_out)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
60862306a36Sopenharmony_ci	struct device *dev = artpec6_crypto_dev;
60962306a36Sopenharmony_ci	struct artpec6_crypto_dma_map *map;
61062306a36Sopenharmony_ci	dma_addr_t dma_addr;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	*dma_addr_out = 0;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (dma->map_count >= ARRAY_SIZE(dma->maps))
61562306a36Sopenharmony_ci		return -ENOMEM;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	dma_addr = dma_map_page(dev, page, offset, size, dir);
61862306a36Sopenharmony_ci	if (dma_mapping_error(dev, dma_addr))
61962306a36Sopenharmony_ci		return -ENOMEM;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	map = &dma->maps[dma->map_count++];
62262306a36Sopenharmony_ci	map->size = size;
62362306a36Sopenharmony_ci	map->dma_addr = dma_addr;
62462306a36Sopenharmony_ci	map->dir = dir;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	*dma_addr_out = dma_addr;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	return 0;
62962306a36Sopenharmony_ci}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_cistatic int
63262306a36Sopenharmony_ciartpec6_crypto_dma_map_single(struct artpec6_crypto_req_common *common,
63362306a36Sopenharmony_ci			      void *ptr, size_t size,
63462306a36Sopenharmony_ci			      enum dma_data_direction dir,
63562306a36Sopenharmony_ci			      dma_addr_t *dma_addr_out)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	struct page *page = virt_to_page(ptr);
63862306a36Sopenharmony_ci	size_t offset = (uintptr_t)ptr & ~PAGE_MASK;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	return artpec6_crypto_dma_map_page(common, page, offset, size, dir,
64162306a36Sopenharmony_ci					  dma_addr_out);
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic int
64562306a36Sopenharmony_ciartpec6_crypto_dma_map_descs(struct artpec6_crypto_req_common *common)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
64862306a36Sopenharmony_ci	int ret;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	ret = artpec6_crypto_dma_map_single(common, dma->in,
65162306a36Sopenharmony_ci				sizeof(dma->in[0]) * dma->in_cnt,
65262306a36Sopenharmony_ci				DMA_TO_DEVICE, &dma->in_dma_addr);
65362306a36Sopenharmony_ci	if (ret)
65462306a36Sopenharmony_ci		return ret;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	ret = artpec6_crypto_dma_map_single(common, dma->out,
65762306a36Sopenharmony_ci				sizeof(dma->out[0]) * dma->out_cnt,
65862306a36Sopenharmony_ci				DMA_TO_DEVICE, &dma->out_dma_addr);
65962306a36Sopenharmony_ci	if (ret)
66062306a36Sopenharmony_ci		return ret;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	/* We only read one stat descriptor */
66362306a36Sopenharmony_ci	dma->stat[dma->in_cnt - 1] = 0;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/*
66662306a36Sopenharmony_ci	 * DMA_BIDIRECTIONAL since we need our zeroing of the stat descriptor
66762306a36Sopenharmony_ci	 * to be written.
66862306a36Sopenharmony_ci	 */
66962306a36Sopenharmony_ci	return artpec6_crypto_dma_map_single(common,
67062306a36Sopenharmony_ci				dma->stat,
67162306a36Sopenharmony_ci				sizeof(dma->stat[0]) * dma->in_cnt,
67262306a36Sopenharmony_ci				DMA_BIDIRECTIONAL,
67362306a36Sopenharmony_ci				&dma->stat_dma_addr);
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cistatic void
67762306a36Sopenharmony_ciartpec6_crypto_dma_unmap_all(struct artpec6_crypto_req_common *common)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
68062306a36Sopenharmony_ci	struct device *dev = artpec6_crypto_dev;
68162306a36Sopenharmony_ci	int i;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	for (i = 0; i < dma->map_count; i++) {
68462306a36Sopenharmony_ci		struct artpec6_crypto_dma_map *map = &dma->maps[i];
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		dma_unmap_page(dev, map->dma_addr, map->size, map->dir);
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	dma->map_count = 0;
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci/** artpec6_crypto_setup_out_descr - Setup an out descriptor
69362306a36Sopenharmony_ci *
69462306a36Sopenharmony_ci * @dst: The virtual address of the data
69562306a36Sopenharmony_ci * @len: The length of the data
69662306a36Sopenharmony_ci * @eop: True if this is the last buffer in the packet
69762306a36Sopenharmony_ci * @use_short: If this is true and the data length is 7 bytes or less then
69862306a36Sopenharmony_ci *	a short descriptor will be used
69962306a36Sopenharmony_ci *
70062306a36Sopenharmony_ci * @return 0 on success
70162306a36Sopenharmony_ci *	Any errors from artpec6_crypto_setup_out_descr_short() or
70262306a36Sopenharmony_ci *	setup_out_descr_phys()
70362306a36Sopenharmony_ci */
70462306a36Sopenharmony_cistatic int
70562306a36Sopenharmony_ciartpec6_crypto_setup_out_descr(struct artpec6_crypto_req_common *common,
70662306a36Sopenharmony_ci			       void *dst, unsigned int len, bool eop,
70762306a36Sopenharmony_ci			       bool use_short)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	if (use_short && len < 7) {
71062306a36Sopenharmony_ci		return artpec6_crypto_setup_out_descr_short(common, dst, len,
71162306a36Sopenharmony_ci							    eop);
71262306a36Sopenharmony_ci	} else {
71362306a36Sopenharmony_ci		int ret;
71462306a36Sopenharmony_ci		dma_addr_t dma_addr;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci		ret = artpec6_crypto_dma_map_single(common, dst, len,
71762306a36Sopenharmony_ci						   DMA_TO_DEVICE,
71862306a36Sopenharmony_ci						   &dma_addr);
71962306a36Sopenharmony_ci		if (ret)
72062306a36Sopenharmony_ci			return ret;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci		return artpec6_crypto_setup_out_descr_phys(common, dma_addr,
72362306a36Sopenharmony_ci							   len, eop);
72462306a36Sopenharmony_ci	}
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci/** artpec6_crypto_setup_in_descr_phys - Setup an in channel with a
72862306a36Sopenharmony_ci *                                       physical address
72962306a36Sopenharmony_ci *
73062306a36Sopenharmony_ci * @addr: The physical address of the data buffer
73162306a36Sopenharmony_ci * @len:  The length of the data buffer
73262306a36Sopenharmony_ci * @intr: True if an interrupt should be fired after HW processing of this
73362306a36Sopenharmony_ci *	  descriptor
73462306a36Sopenharmony_ci *
73562306a36Sopenharmony_ci */
73662306a36Sopenharmony_cistatic int
73762306a36Sopenharmony_ciartpec6_crypto_setup_in_descr_phys(struct artpec6_crypto_req_common *common,
73862306a36Sopenharmony_ci			       dma_addr_t addr, unsigned int len, bool intr)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
74162306a36Sopenharmony_ci	struct pdma_descr *d;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	if (dma->in_cnt >= PDMA_DESCR_COUNT ||
74462306a36Sopenharmony_ci	    fault_inject_dma_descr()) {
74562306a36Sopenharmony_ci		pr_err("No free IN DMA descriptors available!\n");
74662306a36Sopenharmony_ci		return -ENOSPC;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci	d = &dma->in[dma->in_cnt++];
74962306a36Sopenharmony_ci	memset(d, 0, sizeof(*d));
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	d->ctrl.intr = intr;
75262306a36Sopenharmony_ci	d->data.len = len;
75362306a36Sopenharmony_ci	d->data.buf = addr;
75462306a36Sopenharmony_ci	return 0;
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci/** artpec6_crypto_setup_in_descr - Setup an in channel descriptor
75862306a36Sopenharmony_ci *
75962306a36Sopenharmony_ci * @buffer: The virtual address to of the data buffer
76062306a36Sopenharmony_ci * @len:    The length of the data buffer
76162306a36Sopenharmony_ci * @last:   If this is the last data buffer in the request (i.e. an interrupt
76262306a36Sopenharmony_ci *	    is needed
76362306a36Sopenharmony_ci *
76462306a36Sopenharmony_ci * Short descriptors are not used for the in channel
76562306a36Sopenharmony_ci */
76662306a36Sopenharmony_cistatic int
76762306a36Sopenharmony_ciartpec6_crypto_setup_in_descr(struct artpec6_crypto_req_common *common,
76862306a36Sopenharmony_ci			  void *buffer, unsigned int len, bool last)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	dma_addr_t dma_addr;
77162306a36Sopenharmony_ci	int ret;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	ret = artpec6_crypto_dma_map_single(common, buffer, len,
77462306a36Sopenharmony_ci					   DMA_FROM_DEVICE, &dma_addr);
77562306a36Sopenharmony_ci	if (ret)
77662306a36Sopenharmony_ci		return ret;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	return artpec6_crypto_setup_in_descr_phys(common, dma_addr, len, last);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic struct artpec6_crypto_bounce_buffer *
78262306a36Sopenharmony_ciartpec6_crypto_alloc_bounce(gfp_t flags)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	void *base;
78562306a36Sopenharmony_ci	size_t alloc_size = sizeof(struct artpec6_crypto_bounce_buffer) +
78662306a36Sopenharmony_ci			    2 * ARTPEC_CACHE_LINE_MAX;
78762306a36Sopenharmony_ci	struct artpec6_crypto_bounce_buffer *bbuf = kzalloc(alloc_size, flags);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	if (!bbuf)
79062306a36Sopenharmony_ci		return NULL;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	base = bbuf + 1;
79362306a36Sopenharmony_ci	bbuf->buf = PTR_ALIGN(base, ARTPEC_CACHE_LINE_MAX);
79462306a36Sopenharmony_ci	return bbuf;
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic int setup_bounce_buffer_in(struct artpec6_crypto_req_common *common,
79862306a36Sopenharmony_ci				  struct artpec6_crypto_walk *walk, size_t size)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	struct artpec6_crypto_bounce_buffer *bbuf;
80162306a36Sopenharmony_ci	int ret;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	bbuf = artpec6_crypto_alloc_bounce(common->gfp_flags);
80462306a36Sopenharmony_ci	if (!bbuf)
80562306a36Sopenharmony_ci		return -ENOMEM;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	bbuf->length = size;
80862306a36Sopenharmony_ci	bbuf->sg = walk->sg;
80962306a36Sopenharmony_ci	bbuf->offset = walk->offset;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	ret =  artpec6_crypto_setup_in_descr(common, bbuf->buf, size, false);
81262306a36Sopenharmony_ci	if (ret) {
81362306a36Sopenharmony_ci		kfree(bbuf);
81462306a36Sopenharmony_ci		return ret;
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	pr_debug("BOUNCE %zu offset %zu\n", size, walk->offset);
81862306a36Sopenharmony_ci	list_add_tail(&bbuf->list, &common->dma->bounce_buffers);
81962306a36Sopenharmony_ci	return 0;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic int
82362306a36Sopenharmony_ciartpec6_crypto_setup_sg_descrs_in(struct artpec6_crypto_req_common *common,
82462306a36Sopenharmony_ci				  struct artpec6_crypto_walk *walk,
82562306a36Sopenharmony_ci				  size_t count)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	size_t chunk;
82862306a36Sopenharmony_ci	int ret;
82962306a36Sopenharmony_ci	dma_addr_t addr;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	while (walk->sg && count) {
83262306a36Sopenharmony_ci		chunk = min(count, artpec6_crypto_walk_chunklen(walk));
83362306a36Sopenharmony_ci		addr = artpec6_crypto_walk_chunk_phys(walk);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci		/* When destination buffers are not aligned to the cache line
83662306a36Sopenharmony_ci		 * size we need bounce buffers. The DMA-API requires that the
83762306a36Sopenharmony_ci		 * entire line is owned by the DMA buffer and this holds also
83862306a36Sopenharmony_ci		 * for the case when coherent DMA is used.
83962306a36Sopenharmony_ci		 */
84062306a36Sopenharmony_ci		if (!IS_ALIGNED(addr, ARTPEC_CACHE_LINE_MAX)) {
84162306a36Sopenharmony_ci			chunk = min_t(dma_addr_t, chunk,
84262306a36Sopenharmony_ci				      ALIGN(addr, ARTPEC_CACHE_LINE_MAX) -
84362306a36Sopenharmony_ci				      addr);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci			pr_debug("CHUNK-b %pad:%zu\n", &addr, chunk);
84662306a36Sopenharmony_ci			ret = setup_bounce_buffer_in(common, walk, chunk);
84762306a36Sopenharmony_ci		} else if (chunk < ARTPEC_CACHE_LINE_MAX) {
84862306a36Sopenharmony_ci			pr_debug("CHUNK-b %pad:%zu\n", &addr, chunk);
84962306a36Sopenharmony_ci			ret = setup_bounce_buffer_in(common, walk, chunk);
85062306a36Sopenharmony_ci		} else {
85162306a36Sopenharmony_ci			dma_addr_t dma_addr;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci			chunk = chunk & ~(ARTPEC_CACHE_LINE_MAX-1);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci			pr_debug("CHUNK %pad:%zu\n", &addr, chunk);
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci			ret = artpec6_crypto_dma_map_page(common,
85862306a36Sopenharmony_ci							 sg_page(walk->sg),
85962306a36Sopenharmony_ci							 walk->sg->offset +
86062306a36Sopenharmony_ci							 walk->offset,
86162306a36Sopenharmony_ci							 chunk,
86262306a36Sopenharmony_ci							 DMA_FROM_DEVICE,
86362306a36Sopenharmony_ci							 &dma_addr);
86462306a36Sopenharmony_ci			if (ret)
86562306a36Sopenharmony_ci				return ret;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci			ret = artpec6_crypto_setup_in_descr_phys(common,
86862306a36Sopenharmony_ci								 dma_addr,
86962306a36Sopenharmony_ci								 chunk, false);
87062306a36Sopenharmony_ci		}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		if (ret)
87362306a36Sopenharmony_ci			return ret;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci		count = count - chunk;
87662306a36Sopenharmony_ci		artpec6_crypto_walk_advance(walk, chunk);
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (count)
88062306a36Sopenharmony_ci		pr_err("EOL unexpected %zu bytes left\n", count);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	return count ? -EINVAL : 0;
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cistatic int
88662306a36Sopenharmony_ciartpec6_crypto_setup_sg_descrs_out(struct artpec6_crypto_req_common *common,
88762306a36Sopenharmony_ci				   struct artpec6_crypto_walk *walk,
88862306a36Sopenharmony_ci				   size_t count)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	size_t chunk;
89162306a36Sopenharmony_ci	int ret;
89262306a36Sopenharmony_ci	dma_addr_t addr;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	while (walk->sg && count) {
89562306a36Sopenharmony_ci		chunk = min(count, artpec6_crypto_walk_chunklen(walk));
89662306a36Sopenharmony_ci		addr = artpec6_crypto_walk_chunk_phys(walk);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci		pr_debug("OUT-CHUNK %pad:%zu\n", &addr, chunk);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci		if (addr & 3) {
90162306a36Sopenharmony_ci			char buf[3];
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci			chunk = min_t(size_t, chunk, (4-(addr&3)));
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci			sg_pcopy_to_buffer(walk->sg, 1, buf, chunk,
90662306a36Sopenharmony_ci					   walk->offset);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci			ret = artpec6_crypto_setup_out_descr_short(common, buf,
90962306a36Sopenharmony_ci								   chunk,
91062306a36Sopenharmony_ci								   false);
91162306a36Sopenharmony_ci		} else {
91262306a36Sopenharmony_ci			dma_addr_t dma_addr;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci			ret = artpec6_crypto_dma_map_page(common,
91562306a36Sopenharmony_ci							 sg_page(walk->sg),
91662306a36Sopenharmony_ci							 walk->sg->offset +
91762306a36Sopenharmony_ci							 walk->offset,
91862306a36Sopenharmony_ci							 chunk,
91962306a36Sopenharmony_ci							 DMA_TO_DEVICE,
92062306a36Sopenharmony_ci							 &dma_addr);
92162306a36Sopenharmony_ci			if (ret)
92262306a36Sopenharmony_ci				return ret;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci			ret = artpec6_crypto_setup_out_descr_phys(common,
92562306a36Sopenharmony_ci								 dma_addr,
92662306a36Sopenharmony_ci								 chunk, false);
92762306a36Sopenharmony_ci		}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		if (ret)
93062306a36Sopenharmony_ci			return ret;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci		count = count - chunk;
93362306a36Sopenharmony_ci		artpec6_crypto_walk_advance(walk, chunk);
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	if (count)
93762306a36Sopenharmony_ci		pr_err("EOL unexpected %zu bytes left\n", count);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	return count ? -EINVAL : 0;
94062306a36Sopenharmony_ci}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci/** artpec6_crypto_terminate_out_descrs - Set the EOP on the last out descriptor
94462306a36Sopenharmony_ci *
94562306a36Sopenharmony_ci * If the out descriptor list is non-empty, then the eop flag on the
94662306a36Sopenharmony_ci * last used out descriptor will be set.
94762306a36Sopenharmony_ci *
94862306a36Sopenharmony_ci * @return  0 on success
94962306a36Sopenharmony_ci *	-EINVAL if the out descriptor is empty or has overflown
95062306a36Sopenharmony_ci */
95162306a36Sopenharmony_cistatic int
95262306a36Sopenharmony_ciartpec6_crypto_terminate_out_descrs(struct artpec6_crypto_req_common *common)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
95562306a36Sopenharmony_ci	struct pdma_descr *d;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	if (!dma->out_cnt || dma->out_cnt > PDMA_DESCR_COUNT) {
95862306a36Sopenharmony_ci		pr_err("%s: OUT descriptor list is %s\n",
95962306a36Sopenharmony_ci			MODULE_NAME, dma->out_cnt ? "empty" : "full");
96062306a36Sopenharmony_ci		return -EINVAL;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	d = &dma->out[dma->out_cnt-1];
96562306a36Sopenharmony_ci	d->ctrl.eop = 1;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	return 0;
96862306a36Sopenharmony_ci}
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci/** artpec6_crypto_terminate_in_descrs - Set the interrupt flag on the last
97162306a36Sopenharmony_ci *                                       in descriptor
97262306a36Sopenharmony_ci *
97362306a36Sopenharmony_ci * See artpec6_crypto_terminate_out_descrs() for return values
97462306a36Sopenharmony_ci */
97562306a36Sopenharmony_cistatic int
97662306a36Sopenharmony_ciartpec6_crypto_terminate_in_descrs(struct artpec6_crypto_req_common *common)
97762306a36Sopenharmony_ci{
97862306a36Sopenharmony_ci	struct artpec6_crypto_dma_descriptors *dma = common->dma;
97962306a36Sopenharmony_ci	struct pdma_descr *d;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	if (!dma->in_cnt || dma->in_cnt > PDMA_DESCR_COUNT) {
98262306a36Sopenharmony_ci		pr_err("%s: IN descriptor list is %s\n",
98362306a36Sopenharmony_ci			MODULE_NAME, dma->in_cnt ? "empty" : "full");
98462306a36Sopenharmony_ci		return -EINVAL;
98562306a36Sopenharmony_ci	}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	d = &dma->in[dma->in_cnt-1];
98862306a36Sopenharmony_ci	d->ctrl.intr = 1;
98962306a36Sopenharmony_ci	return 0;
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci/** create_hash_pad - Create a Secure Hash conformant pad
99362306a36Sopenharmony_ci *
99462306a36Sopenharmony_ci * @dst:      The destination buffer to write the pad. Must be at least 64 bytes
99562306a36Sopenharmony_ci * @dgstlen:  The total length of the hash digest in bytes
99662306a36Sopenharmony_ci * @bitcount: The total length of the digest in bits
99762306a36Sopenharmony_ci *
99862306a36Sopenharmony_ci * @return The total number of padding bytes written to @dst
99962306a36Sopenharmony_ci */
100062306a36Sopenharmony_cistatic size_t
100162306a36Sopenharmony_cicreate_hash_pad(int oper, unsigned char *dst, u64 dgstlen, u64 bitcount)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	unsigned int mod, target, diff, pad_bytes, size_bytes;
100462306a36Sopenharmony_ci	__be64 bits = __cpu_to_be64(bitcount);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	switch (oper) {
100762306a36Sopenharmony_ci	case regk_crypto_sha1:
100862306a36Sopenharmony_ci	case regk_crypto_sha256:
100962306a36Sopenharmony_ci	case regk_crypto_hmac_sha1:
101062306a36Sopenharmony_ci	case regk_crypto_hmac_sha256:
101162306a36Sopenharmony_ci		target = 448 / 8;
101262306a36Sopenharmony_ci		mod = 512 / 8;
101362306a36Sopenharmony_ci		size_bytes = 8;
101462306a36Sopenharmony_ci		break;
101562306a36Sopenharmony_ci	default:
101662306a36Sopenharmony_ci		target = 896 / 8;
101762306a36Sopenharmony_ci		mod = 1024 / 8;
101862306a36Sopenharmony_ci		size_bytes = 16;
101962306a36Sopenharmony_ci		break;
102062306a36Sopenharmony_ci	}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	target -= 1;
102362306a36Sopenharmony_ci	diff = dgstlen & (mod - 1);
102462306a36Sopenharmony_ci	pad_bytes = diff > target ? target + mod - diff : target - diff;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	memset(dst + 1, 0, pad_bytes);
102762306a36Sopenharmony_ci	dst[0] = 0x80;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	if (size_bytes == 16) {
103062306a36Sopenharmony_ci		memset(dst + 1 + pad_bytes, 0, 8);
103162306a36Sopenharmony_ci		memcpy(dst + 1 + pad_bytes + 8, &bits, 8);
103262306a36Sopenharmony_ci	} else {
103362306a36Sopenharmony_ci		memcpy(dst + 1 + pad_bytes, &bits, 8);
103462306a36Sopenharmony_ci	}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	return pad_bytes + size_bytes + 1;
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic int artpec6_crypto_common_init(struct artpec6_crypto_req_common *common,
104062306a36Sopenharmony_ci		struct crypto_async_request *parent,
104162306a36Sopenharmony_ci		void (*complete)(struct crypto_async_request *req),
104262306a36Sopenharmony_ci		struct scatterlist *dstsg, unsigned int nbytes)
104362306a36Sopenharmony_ci{
104462306a36Sopenharmony_ci	gfp_t flags;
104562306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	flags = (parent->flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
104862306a36Sopenharmony_ci		 GFP_KERNEL : GFP_ATOMIC;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	common->gfp_flags = flags;
105162306a36Sopenharmony_ci	common->dma = kmem_cache_alloc(ac->dma_cache, flags);
105262306a36Sopenharmony_ci	if (!common->dma)
105362306a36Sopenharmony_ci		return -ENOMEM;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	common->req = parent;
105662306a36Sopenharmony_ci	common->complete = complete;
105762306a36Sopenharmony_ci	return 0;
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_cistatic void
106162306a36Sopenharmony_ciartpec6_crypto_bounce_destroy(struct artpec6_crypto_dma_descriptors *dma)
106262306a36Sopenharmony_ci{
106362306a36Sopenharmony_ci	struct artpec6_crypto_bounce_buffer *b;
106462306a36Sopenharmony_ci	struct artpec6_crypto_bounce_buffer *next;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	list_for_each_entry_safe(b, next, &dma->bounce_buffers, list) {
106762306a36Sopenharmony_ci		kfree(b);
106862306a36Sopenharmony_ci	}
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_cistatic int
107262306a36Sopenharmony_ciartpec6_crypto_common_destroy(struct artpec6_crypto_req_common *common)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	artpec6_crypto_dma_unmap_all(common);
107762306a36Sopenharmony_ci	artpec6_crypto_bounce_destroy(common->dma);
107862306a36Sopenharmony_ci	kmem_cache_free(ac->dma_cache, common->dma);
107962306a36Sopenharmony_ci	common->dma = NULL;
108062306a36Sopenharmony_ci	return 0;
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci/*
108462306a36Sopenharmony_ci * Ciphering functions.
108562306a36Sopenharmony_ci */
108662306a36Sopenharmony_cistatic int artpec6_crypto_encrypt(struct skcipher_request *req)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req);
108962306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher);
109062306a36Sopenharmony_ci	struct artpec6_crypto_request_context *req_ctx = NULL;
109162306a36Sopenharmony_ci	void (*complete)(struct crypto_async_request *req);
109262306a36Sopenharmony_ci	int ret;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	req_ctx = skcipher_request_ctx(req);
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	switch (ctx->crypto_type) {
109762306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_CBC:
109862306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_ECB:
109962306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_XTS:
110062306a36Sopenharmony_ci		req_ctx->decrypt = 0;
110162306a36Sopenharmony_ci		break;
110262306a36Sopenharmony_ci	default:
110362306a36Sopenharmony_ci		break;
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	switch (ctx->crypto_type) {
110762306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_CBC:
110862306a36Sopenharmony_ci		complete = artpec6_crypto_complete_cbc_encrypt;
110962306a36Sopenharmony_ci		break;
111062306a36Sopenharmony_ci	default:
111162306a36Sopenharmony_ci		complete = artpec6_crypto_complete_crypto;
111262306a36Sopenharmony_ci		break;
111362306a36Sopenharmony_ci	}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	ret = artpec6_crypto_common_init(&req_ctx->common,
111662306a36Sopenharmony_ci				  &req->base,
111762306a36Sopenharmony_ci				  complete,
111862306a36Sopenharmony_ci				  req->dst, req->cryptlen);
111962306a36Sopenharmony_ci	if (ret)
112062306a36Sopenharmony_ci		return ret;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	ret = artpec6_crypto_prepare_crypto(req);
112362306a36Sopenharmony_ci	if (ret) {
112462306a36Sopenharmony_ci		artpec6_crypto_common_destroy(&req_ctx->common);
112562306a36Sopenharmony_ci		return ret;
112662306a36Sopenharmony_ci	}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	return artpec6_crypto_submit(&req_ctx->common);
112962306a36Sopenharmony_ci}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_cistatic int artpec6_crypto_decrypt(struct skcipher_request *req)
113262306a36Sopenharmony_ci{
113362306a36Sopenharmony_ci	int ret;
113462306a36Sopenharmony_ci	struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req);
113562306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher);
113662306a36Sopenharmony_ci	struct artpec6_crypto_request_context *req_ctx = NULL;
113762306a36Sopenharmony_ci	void (*complete)(struct crypto_async_request *req);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	req_ctx = skcipher_request_ctx(req);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	switch (ctx->crypto_type) {
114262306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_CBC:
114362306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_ECB:
114462306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_XTS:
114562306a36Sopenharmony_ci		req_ctx->decrypt = 1;
114662306a36Sopenharmony_ci		break;
114762306a36Sopenharmony_ci	default:
114862306a36Sopenharmony_ci		break;
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	switch (ctx->crypto_type) {
115362306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_CBC:
115462306a36Sopenharmony_ci		complete = artpec6_crypto_complete_cbc_decrypt;
115562306a36Sopenharmony_ci		break;
115662306a36Sopenharmony_ci	default:
115762306a36Sopenharmony_ci		complete = artpec6_crypto_complete_crypto;
115862306a36Sopenharmony_ci		break;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	ret = artpec6_crypto_common_init(&req_ctx->common, &req->base,
116262306a36Sopenharmony_ci				  complete,
116362306a36Sopenharmony_ci				  req->dst, req->cryptlen);
116462306a36Sopenharmony_ci	if (ret)
116562306a36Sopenharmony_ci		return ret;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	ret = artpec6_crypto_prepare_crypto(req);
116862306a36Sopenharmony_ci	if (ret) {
116962306a36Sopenharmony_ci		artpec6_crypto_common_destroy(&req_ctx->common);
117062306a36Sopenharmony_ci		return ret;
117162306a36Sopenharmony_ci	}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	return artpec6_crypto_submit(&req_ctx->common);
117462306a36Sopenharmony_ci}
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_cistatic int
117762306a36Sopenharmony_ciartpec6_crypto_ctr_crypt(struct skcipher_request *req, bool encrypt)
117862306a36Sopenharmony_ci{
117962306a36Sopenharmony_ci	struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req);
118062306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher);
118162306a36Sopenharmony_ci	size_t iv_len = crypto_skcipher_ivsize(cipher);
118262306a36Sopenharmony_ci	unsigned int counter = be32_to_cpup((__be32 *)
118362306a36Sopenharmony_ci					    (req->iv + iv_len - 4));
118462306a36Sopenharmony_ci	unsigned int nblks = ALIGN(req->cryptlen, AES_BLOCK_SIZE) /
118562306a36Sopenharmony_ci			     AES_BLOCK_SIZE;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	/*
118862306a36Sopenharmony_ci	 * The hardware uses only the last 32-bits as the counter while the
118962306a36Sopenharmony_ci	 * kernel tests (aes_ctr_enc_tv_template[4] for example) expect that
119062306a36Sopenharmony_ci	 * the whole IV is a counter.  So fallback if the counter is going to
119162306a36Sopenharmony_ci	 * overlow.
119262306a36Sopenharmony_ci	 */
119362306a36Sopenharmony_ci	if (counter + nblks < counter) {
119462306a36Sopenharmony_ci		int ret;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		pr_debug("counter %x will overflow (nblks %u), falling back\n",
119762306a36Sopenharmony_ci			 counter, counter + nblks);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci		ret = crypto_sync_skcipher_setkey(ctx->fallback, ctx->aes_key,
120062306a36Sopenharmony_ci						  ctx->key_length);
120162306a36Sopenharmony_ci		if (ret)
120262306a36Sopenharmony_ci			return ret;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci		{
120562306a36Sopenharmony_ci			SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback);
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci			skcipher_request_set_sync_tfm(subreq, ctx->fallback);
120862306a36Sopenharmony_ci			skcipher_request_set_callback(subreq, req->base.flags,
120962306a36Sopenharmony_ci						      NULL, NULL);
121062306a36Sopenharmony_ci			skcipher_request_set_crypt(subreq, req->src, req->dst,
121162306a36Sopenharmony_ci						   req->cryptlen, req->iv);
121262306a36Sopenharmony_ci			ret = encrypt ? crypto_skcipher_encrypt(subreq)
121362306a36Sopenharmony_ci				      : crypto_skcipher_decrypt(subreq);
121462306a36Sopenharmony_ci			skcipher_request_zero(subreq);
121562306a36Sopenharmony_ci		}
121662306a36Sopenharmony_ci		return ret;
121762306a36Sopenharmony_ci	}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	return encrypt ? artpec6_crypto_encrypt(req)
122062306a36Sopenharmony_ci		       : artpec6_crypto_decrypt(req);
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic int artpec6_crypto_ctr_encrypt(struct skcipher_request *req)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	return artpec6_crypto_ctr_crypt(req, true);
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic int artpec6_crypto_ctr_decrypt(struct skcipher_request *req)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	return artpec6_crypto_ctr_crypt(req, false);
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci/*
123462306a36Sopenharmony_ci * AEAD functions
123562306a36Sopenharmony_ci */
123662306a36Sopenharmony_cistatic int artpec6_crypto_aead_init(struct crypto_aead *tfm)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *tfm_ctx = crypto_aead_ctx(tfm);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	memset(tfm_ctx, 0, sizeof(*tfm_ctx));
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	crypto_aead_set_reqsize(tfm,
124362306a36Sopenharmony_ci				sizeof(struct artpec6_crypto_aead_req_ctx));
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	return 0;
124662306a36Sopenharmony_ci}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_cistatic int artpec6_crypto_aead_set_key(struct crypto_aead *tfm, const u8 *key,
124962306a36Sopenharmony_ci			       unsigned int len)
125062306a36Sopenharmony_ci{
125162306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_tfm_ctx(&tfm->base);
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	if (len != 16 && len != 24 && len != 32)
125462306a36Sopenharmony_ci		return -EINVAL;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	ctx->key_length = len;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	memcpy(ctx->aes_key, key, len);
125962306a36Sopenharmony_ci	return 0;
126062306a36Sopenharmony_ci}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_cistatic int artpec6_crypto_aead_encrypt(struct aead_request *req)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	int ret;
126562306a36Sopenharmony_ci	struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(req);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	req_ctx->decrypt = false;
126862306a36Sopenharmony_ci	ret = artpec6_crypto_common_init(&req_ctx->common, &req->base,
126962306a36Sopenharmony_ci				  artpec6_crypto_complete_aead,
127062306a36Sopenharmony_ci				  NULL, 0);
127162306a36Sopenharmony_ci	if (ret)
127262306a36Sopenharmony_ci		return ret;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	ret = artpec6_crypto_prepare_aead(req);
127562306a36Sopenharmony_ci	if (ret) {
127662306a36Sopenharmony_ci		artpec6_crypto_common_destroy(&req_ctx->common);
127762306a36Sopenharmony_ci		return ret;
127862306a36Sopenharmony_ci	}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	return artpec6_crypto_submit(&req_ctx->common);
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic int artpec6_crypto_aead_decrypt(struct aead_request *req)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	int ret;
128662306a36Sopenharmony_ci	struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(req);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	req_ctx->decrypt = true;
128962306a36Sopenharmony_ci	if (req->cryptlen < AES_BLOCK_SIZE)
129062306a36Sopenharmony_ci		return -EINVAL;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	ret = artpec6_crypto_common_init(&req_ctx->common,
129362306a36Sopenharmony_ci				  &req->base,
129462306a36Sopenharmony_ci				  artpec6_crypto_complete_aead,
129562306a36Sopenharmony_ci				  NULL, 0);
129662306a36Sopenharmony_ci	if (ret)
129762306a36Sopenharmony_ci		return ret;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	ret = artpec6_crypto_prepare_aead(req);
130062306a36Sopenharmony_ci	if (ret) {
130162306a36Sopenharmony_ci		artpec6_crypto_common_destroy(&req_ctx->common);
130262306a36Sopenharmony_ci		return ret;
130362306a36Sopenharmony_ci	}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	return artpec6_crypto_submit(&req_ctx->common);
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic int artpec6_crypto_prepare_hash(struct ahash_request *areq)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	struct artpec6_hashalg_context *ctx = crypto_tfm_ctx(areq->base.tfm);
131162306a36Sopenharmony_ci	struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(areq);
131262306a36Sopenharmony_ci	size_t digestsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(areq));
131362306a36Sopenharmony_ci	size_t contextsize = digestsize;
131462306a36Sopenharmony_ci	size_t blocksize = crypto_tfm_alg_blocksize(
131562306a36Sopenharmony_ci		crypto_ahash_tfm(crypto_ahash_reqtfm(areq)));
131662306a36Sopenharmony_ci	struct artpec6_crypto_req_common *common = &req_ctx->common;
131762306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
131862306a36Sopenharmony_ci	enum artpec6_crypto_variant variant = ac->variant;
131962306a36Sopenharmony_ci	u32 sel_ctx;
132062306a36Sopenharmony_ci	bool ext_ctx = false;
132162306a36Sopenharmony_ci	bool run_hw = false;
132262306a36Sopenharmony_ci	int error = 0;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	artpec6_crypto_init_dma_operation(common);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	/* Upload HMAC key, must be first the first packet */
132762306a36Sopenharmony_ci	if (req_ctx->hash_flags & HASH_FLAG_HMAC) {
132862306a36Sopenharmony_ci		if (variant == ARTPEC6_CRYPTO) {
132962306a36Sopenharmony_ci			req_ctx->key_md = FIELD_PREP(A6_CRY_MD_OPER,
133062306a36Sopenharmony_ci						     a6_regk_crypto_dlkey);
133162306a36Sopenharmony_ci		} else {
133262306a36Sopenharmony_ci			req_ctx->key_md = FIELD_PREP(A7_CRY_MD_OPER,
133362306a36Sopenharmony_ci						     a7_regk_crypto_dlkey);
133462306a36Sopenharmony_ci		}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci		/* Copy and pad up the key */
133762306a36Sopenharmony_ci		memcpy(req_ctx->key_buffer, ctx->hmac_key,
133862306a36Sopenharmony_ci		       ctx->hmac_key_length);
133962306a36Sopenharmony_ci		memset(req_ctx->key_buffer + ctx->hmac_key_length, 0,
134062306a36Sopenharmony_ci		       blocksize - ctx->hmac_key_length);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci		error = artpec6_crypto_setup_out_descr(common,
134362306a36Sopenharmony_ci					(void *)&req_ctx->key_md,
134462306a36Sopenharmony_ci					sizeof(req_ctx->key_md), false, false);
134562306a36Sopenharmony_ci		if (error)
134662306a36Sopenharmony_ci			return error;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci		error = artpec6_crypto_setup_out_descr(common,
134962306a36Sopenharmony_ci					req_ctx->key_buffer, blocksize,
135062306a36Sopenharmony_ci					true, false);
135162306a36Sopenharmony_ci		if (error)
135262306a36Sopenharmony_ci			return error;
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	if (!(req_ctx->hash_flags & HASH_FLAG_INIT_CTX)) {
135662306a36Sopenharmony_ci		/* Restore context */
135762306a36Sopenharmony_ci		sel_ctx = regk_crypto_ext;
135862306a36Sopenharmony_ci		ext_ctx = true;
135962306a36Sopenharmony_ci	} else {
136062306a36Sopenharmony_ci		sel_ctx = regk_crypto_init;
136162306a36Sopenharmony_ci	}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO) {
136462306a36Sopenharmony_ci		req_ctx->hash_md &= ~A6_CRY_MD_HASH_SEL_CTX;
136562306a36Sopenharmony_ci		req_ctx->hash_md |= FIELD_PREP(A6_CRY_MD_HASH_SEL_CTX, sel_ctx);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci		/* If this is the final round, set the final flag */
136862306a36Sopenharmony_ci		if (req_ctx->hash_flags & HASH_FLAG_FINALIZE)
136962306a36Sopenharmony_ci			req_ctx->hash_md |= A6_CRY_MD_HASH_HMAC_FIN;
137062306a36Sopenharmony_ci	} else {
137162306a36Sopenharmony_ci		req_ctx->hash_md &= ~A7_CRY_MD_HASH_SEL_CTX;
137262306a36Sopenharmony_ci		req_ctx->hash_md |= FIELD_PREP(A7_CRY_MD_HASH_SEL_CTX, sel_ctx);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci		/* If this is the final round, set the final flag */
137562306a36Sopenharmony_ci		if (req_ctx->hash_flags & HASH_FLAG_FINALIZE)
137662306a36Sopenharmony_ci			req_ctx->hash_md |= A7_CRY_MD_HASH_HMAC_FIN;
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	/* Setup up metadata descriptors */
138062306a36Sopenharmony_ci	error = artpec6_crypto_setup_out_descr(common,
138162306a36Sopenharmony_ci				(void *)&req_ctx->hash_md,
138262306a36Sopenharmony_ci				sizeof(req_ctx->hash_md), false, false);
138362306a36Sopenharmony_ci	if (error)
138462306a36Sopenharmony_ci		return error;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	error = artpec6_crypto_setup_in_descr(common, ac->pad_buffer, 4, false);
138762306a36Sopenharmony_ci	if (error)
138862306a36Sopenharmony_ci		return error;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	if (ext_ctx) {
139162306a36Sopenharmony_ci		error = artpec6_crypto_setup_out_descr(common,
139262306a36Sopenharmony_ci					req_ctx->digeststate,
139362306a36Sopenharmony_ci					contextsize, false, false);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci		if (error)
139662306a36Sopenharmony_ci			return error;
139762306a36Sopenharmony_ci	}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	if (req_ctx->hash_flags & HASH_FLAG_UPDATE) {
140062306a36Sopenharmony_ci		size_t done_bytes = 0;
140162306a36Sopenharmony_ci		size_t total_bytes = areq->nbytes + req_ctx->partial_bytes;
140262306a36Sopenharmony_ci		size_t ready_bytes = round_down(total_bytes, blocksize);
140362306a36Sopenharmony_ci		struct artpec6_crypto_walk walk;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci		run_hw = ready_bytes > 0;
140662306a36Sopenharmony_ci		if (req_ctx->partial_bytes && ready_bytes) {
140762306a36Sopenharmony_ci			/* We have a partial buffer and will at least some bytes
140862306a36Sopenharmony_ci			 * to the HW. Empty this partial buffer before tackling
140962306a36Sopenharmony_ci			 * the SG lists
141062306a36Sopenharmony_ci			 */
141162306a36Sopenharmony_ci			memcpy(req_ctx->partial_buffer_out,
141262306a36Sopenharmony_ci				req_ctx->partial_buffer,
141362306a36Sopenharmony_ci				req_ctx->partial_bytes);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci			error = artpec6_crypto_setup_out_descr(common,
141662306a36Sopenharmony_ci						req_ctx->partial_buffer_out,
141762306a36Sopenharmony_ci						req_ctx->partial_bytes,
141862306a36Sopenharmony_ci						false, true);
141962306a36Sopenharmony_ci			if (error)
142062306a36Sopenharmony_ci				return error;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci			/* Reset partial buffer */
142362306a36Sopenharmony_ci			done_bytes += req_ctx->partial_bytes;
142462306a36Sopenharmony_ci			req_ctx->partial_bytes = 0;
142562306a36Sopenharmony_ci		}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci		artpec6_crypto_walk_init(&walk, areq->src);
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci		error = artpec6_crypto_setup_sg_descrs_out(common, &walk,
143062306a36Sopenharmony_ci							   ready_bytes -
143162306a36Sopenharmony_ci							   done_bytes);
143262306a36Sopenharmony_ci		if (error)
143362306a36Sopenharmony_ci			return error;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci		if (walk.sg) {
143662306a36Sopenharmony_ci			size_t sg_skip = ready_bytes - done_bytes;
143762306a36Sopenharmony_ci			size_t sg_rem = areq->nbytes - sg_skip;
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci			sg_pcopy_to_buffer(areq->src, sg_nents(areq->src),
144062306a36Sopenharmony_ci					   req_ctx->partial_buffer +
144162306a36Sopenharmony_ci					   req_ctx->partial_bytes,
144262306a36Sopenharmony_ci					   sg_rem, sg_skip);
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci			req_ctx->partial_bytes += sg_rem;
144562306a36Sopenharmony_ci		}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci		req_ctx->digcnt += ready_bytes;
144862306a36Sopenharmony_ci		req_ctx->hash_flags &= ~(HASH_FLAG_UPDATE);
144962306a36Sopenharmony_ci	}
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	/* Finalize */
145262306a36Sopenharmony_ci	if (req_ctx->hash_flags & HASH_FLAG_FINALIZE) {
145362306a36Sopenharmony_ci		size_t hash_pad_len;
145462306a36Sopenharmony_ci		u64 digest_bits;
145562306a36Sopenharmony_ci		u32 oper;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci		if (variant == ARTPEC6_CRYPTO)
145862306a36Sopenharmony_ci			oper = FIELD_GET(A6_CRY_MD_OPER, req_ctx->hash_md);
145962306a36Sopenharmony_ci		else
146062306a36Sopenharmony_ci			oper = FIELD_GET(A7_CRY_MD_OPER, req_ctx->hash_md);
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci		/* Write out the partial buffer if present */
146362306a36Sopenharmony_ci		if (req_ctx->partial_bytes) {
146462306a36Sopenharmony_ci			memcpy(req_ctx->partial_buffer_out,
146562306a36Sopenharmony_ci			       req_ctx->partial_buffer,
146662306a36Sopenharmony_ci			       req_ctx->partial_bytes);
146762306a36Sopenharmony_ci			error = artpec6_crypto_setup_out_descr(common,
146862306a36Sopenharmony_ci						req_ctx->partial_buffer_out,
146962306a36Sopenharmony_ci						req_ctx->partial_bytes,
147062306a36Sopenharmony_ci						false, true);
147162306a36Sopenharmony_ci			if (error)
147262306a36Sopenharmony_ci				return error;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci			req_ctx->digcnt += req_ctx->partial_bytes;
147562306a36Sopenharmony_ci			req_ctx->partial_bytes = 0;
147662306a36Sopenharmony_ci		}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci		if (req_ctx->hash_flags & HASH_FLAG_HMAC)
147962306a36Sopenharmony_ci			digest_bits = 8 * (req_ctx->digcnt + blocksize);
148062306a36Sopenharmony_ci		else
148162306a36Sopenharmony_ci			digest_bits = 8 * req_ctx->digcnt;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci		/* Add the hash pad */
148462306a36Sopenharmony_ci		hash_pad_len = create_hash_pad(oper, req_ctx->pad_buffer,
148562306a36Sopenharmony_ci					       req_ctx->digcnt, digest_bits);
148662306a36Sopenharmony_ci		error = artpec6_crypto_setup_out_descr(common,
148762306a36Sopenharmony_ci						      req_ctx->pad_buffer,
148862306a36Sopenharmony_ci						      hash_pad_len, false,
148962306a36Sopenharmony_ci						      true);
149062306a36Sopenharmony_ci		req_ctx->digcnt = 0;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci		if (error)
149362306a36Sopenharmony_ci			return error;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci		/* Descriptor for the final result */
149662306a36Sopenharmony_ci		error = artpec6_crypto_setup_in_descr(common, areq->result,
149762306a36Sopenharmony_ci						      digestsize,
149862306a36Sopenharmony_ci						      true);
149962306a36Sopenharmony_ci		if (error)
150062306a36Sopenharmony_ci			return error;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	} else { /* This is not the final operation for this request */
150362306a36Sopenharmony_ci		if (!run_hw)
150462306a36Sopenharmony_ci			return ARTPEC6_CRYPTO_PREPARE_HASH_NO_START;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci		/* Save the result to the context */
150762306a36Sopenharmony_ci		error = artpec6_crypto_setup_in_descr(common,
150862306a36Sopenharmony_ci						      req_ctx->digeststate,
150962306a36Sopenharmony_ci						      contextsize, false);
151062306a36Sopenharmony_ci		if (error)
151162306a36Sopenharmony_ci			return error;
151262306a36Sopenharmony_ci		/* fall through */
151362306a36Sopenharmony_ci	}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	req_ctx->hash_flags &= ~(HASH_FLAG_INIT_CTX | HASH_FLAG_UPDATE |
151662306a36Sopenharmony_ci				 HASH_FLAG_FINALIZE);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	error = artpec6_crypto_terminate_in_descrs(common);
151962306a36Sopenharmony_ci	if (error)
152062306a36Sopenharmony_ci		return error;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	error = artpec6_crypto_terminate_out_descrs(common);
152362306a36Sopenharmony_ci	if (error)
152462306a36Sopenharmony_ci		return error;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	error = artpec6_crypto_dma_map_descs(common);
152762306a36Sopenharmony_ci	if (error)
152862306a36Sopenharmony_ci		return error;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	return ARTPEC6_CRYPTO_PREPARE_HASH_START;
153162306a36Sopenharmony_ci}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_cistatic int artpec6_crypto_aes_ecb_init(struct crypto_skcipher *tfm)
153562306a36Sopenharmony_ci{
153662306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	tfm->reqsize = sizeof(struct artpec6_crypto_request_context);
153962306a36Sopenharmony_ci	ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_ECB;
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci	return 0;
154262306a36Sopenharmony_ci}
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_cistatic int artpec6_crypto_aes_ctr_init(struct crypto_skcipher *tfm)
154562306a36Sopenharmony_ci{
154662306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm);
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	ctx->fallback =
154962306a36Sopenharmony_ci		crypto_alloc_sync_skcipher(crypto_tfm_alg_name(&tfm->base),
155062306a36Sopenharmony_ci					   0, CRYPTO_ALG_NEED_FALLBACK);
155162306a36Sopenharmony_ci	if (IS_ERR(ctx->fallback))
155262306a36Sopenharmony_ci		return PTR_ERR(ctx->fallback);
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	tfm->reqsize = sizeof(struct artpec6_crypto_request_context);
155562306a36Sopenharmony_ci	ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_CTR;
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	return 0;
155862306a36Sopenharmony_ci}
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_cistatic int artpec6_crypto_aes_cbc_init(struct crypto_skcipher *tfm)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	tfm->reqsize = sizeof(struct artpec6_crypto_request_context);
156562306a36Sopenharmony_ci	ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_CBC;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	return 0;
156862306a36Sopenharmony_ci}
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_cistatic int artpec6_crypto_aes_xts_init(struct crypto_skcipher *tfm)
157162306a36Sopenharmony_ci{
157262306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	tfm->reqsize = sizeof(struct artpec6_crypto_request_context);
157562306a36Sopenharmony_ci	ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_XTS;
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	return 0;
157862306a36Sopenharmony_ci}
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_cistatic void artpec6_crypto_aes_exit(struct crypto_skcipher *tfm)
158162306a36Sopenharmony_ci{
158262306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm);
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	memset(ctx, 0, sizeof(*ctx));
158562306a36Sopenharmony_ci}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_cistatic void artpec6_crypto_aes_ctr_exit(struct crypto_skcipher *tfm)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm);
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	crypto_free_sync_skcipher(ctx->fallback);
159262306a36Sopenharmony_ci	artpec6_crypto_aes_exit(tfm);
159362306a36Sopenharmony_ci}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_cistatic int
159662306a36Sopenharmony_ciartpec6_crypto_cipher_set_key(struct crypto_skcipher *cipher, const u8 *key,
159762306a36Sopenharmony_ci			      unsigned int keylen)
159862306a36Sopenharmony_ci{
159962306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx =
160062306a36Sopenharmony_ci		crypto_skcipher_ctx(cipher);
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	switch (keylen) {
160362306a36Sopenharmony_ci	case 16:
160462306a36Sopenharmony_ci	case 24:
160562306a36Sopenharmony_ci	case 32:
160662306a36Sopenharmony_ci		break;
160762306a36Sopenharmony_ci	default:
160862306a36Sopenharmony_ci		return -EINVAL;
160962306a36Sopenharmony_ci	}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	memcpy(ctx->aes_key, key, keylen);
161262306a36Sopenharmony_ci	ctx->key_length = keylen;
161362306a36Sopenharmony_ci	return 0;
161462306a36Sopenharmony_ci}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_cistatic int
161762306a36Sopenharmony_ciartpec6_crypto_xts_set_key(struct crypto_skcipher *cipher, const u8 *key,
161862306a36Sopenharmony_ci			      unsigned int keylen)
161962306a36Sopenharmony_ci{
162062306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx =
162162306a36Sopenharmony_ci		crypto_skcipher_ctx(cipher);
162262306a36Sopenharmony_ci	int ret;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	ret = xts_verify_key(cipher, key, keylen);
162562306a36Sopenharmony_ci	if (ret)
162662306a36Sopenharmony_ci		return ret;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	switch (keylen) {
162962306a36Sopenharmony_ci	case 32:
163062306a36Sopenharmony_ci	case 48:
163162306a36Sopenharmony_ci	case 64:
163262306a36Sopenharmony_ci		break;
163362306a36Sopenharmony_ci	default:
163462306a36Sopenharmony_ci		return -EINVAL;
163562306a36Sopenharmony_ci	}
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	memcpy(ctx->aes_key, key, keylen);
163862306a36Sopenharmony_ci	ctx->key_length = keylen;
163962306a36Sopenharmony_ci	return 0;
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci/** artpec6_crypto_process_crypto - Prepare an async block cipher crypto request
164362306a36Sopenharmony_ci *
164462306a36Sopenharmony_ci * @req: The asynch request to process
164562306a36Sopenharmony_ci *
164662306a36Sopenharmony_ci * @return 0 if the dma job was successfully prepared
164762306a36Sopenharmony_ci *	  <0 on error
164862306a36Sopenharmony_ci *
164962306a36Sopenharmony_ci * This function sets up the PDMA descriptors for a block cipher request.
165062306a36Sopenharmony_ci *
165162306a36Sopenharmony_ci * The required padding is added for AES-CTR using a statically defined
165262306a36Sopenharmony_ci * buffer.
165362306a36Sopenharmony_ci *
165462306a36Sopenharmony_ci * The PDMA descriptor list will be as follows:
165562306a36Sopenharmony_ci *
165662306a36Sopenharmony_ci * OUT: [KEY_MD][KEY][EOP]<CIPHER_MD>[IV]<data_0>...[data_n][AES-CTR_pad]<eop>
165762306a36Sopenharmony_ci * IN:  <CIPHER_MD><data_0>...[data_n]<intr>
165862306a36Sopenharmony_ci *
165962306a36Sopenharmony_ci */
166062306a36Sopenharmony_cistatic int artpec6_crypto_prepare_crypto(struct skcipher_request *areq)
166162306a36Sopenharmony_ci{
166262306a36Sopenharmony_ci	int ret;
166362306a36Sopenharmony_ci	struct artpec6_crypto_walk walk;
166462306a36Sopenharmony_ci	struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(areq);
166562306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher);
166662306a36Sopenharmony_ci	struct artpec6_crypto_request_context *req_ctx = NULL;
166762306a36Sopenharmony_ci	size_t iv_len = crypto_skcipher_ivsize(cipher);
166862306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
166962306a36Sopenharmony_ci	enum artpec6_crypto_variant variant = ac->variant;
167062306a36Sopenharmony_ci	struct artpec6_crypto_req_common *common;
167162306a36Sopenharmony_ci	bool cipher_decr = false;
167262306a36Sopenharmony_ci	size_t cipher_klen;
167362306a36Sopenharmony_ci	u32 cipher_len = 0; /* Same as regk_crypto_key_128 for NULL crypto */
167462306a36Sopenharmony_ci	u32 oper;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	req_ctx = skcipher_request_ctx(areq);
167762306a36Sopenharmony_ci	common = &req_ctx->common;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	artpec6_crypto_init_dma_operation(common);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO)
168262306a36Sopenharmony_ci		ctx->key_md = FIELD_PREP(A6_CRY_MD_OPER, a6_regk_crypto_dlkey);
168362306a36Sopenharmony_ci	else
168462306a36Sopenharmony_ci		ctx->key_md = FIELD_PREP(A7_CRY_MD_OPER, a7_regk_crypto_dlkey);
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	ret = artpec6_crypto_setup_out_descr(common, (void *)&ctx->key_md,
168762306a36Sopenharmony_ci					     sizeof(ctx->key_md), false, false);
168862306a36Sopenharmony_ci	if (ret)
168962306a36Sopenharmony_ci		return ret;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	ret = artpec6_crypto_setup_out_descr(common, ctx->aes_key,
169262306a36Sopenharmony_ci					      ctx->key_length, true, false);
169362306a36Sopenharmony_ci	if (ret)
169462306a36Sopenharmony_ci		return ret;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	req_ctx->cipher_md = 0;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	if (ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_XTS)
169962306a36Sopenharmony_ci		cipher_klen = ctx->key_length/2;
170062306a36Sopenharmony_ci	else
170162306a36Sopenharmony_ci		cipher_klen =  ctx->key_length;
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	/* Metadata */
170462306a36Sopenharmony_ci	switch (cipher_klen) {
170562306a36Sopenharmony_ci	case 16:
170662306a36Sopenharmony_ci		cipher_len = regk_crypto_key_128;
170762306a36Sopenharmony_ci		break;
170862306a36Sopenharmony_ci	case 24:
170962306a36Sopenharmony_ci		cipher_len = regk_crypto_key_192;
171062306a36Sopenharmony_ci		break;
171162306a36Sopenharmony_ci	case 32:
171262306a36Sopenharmony_ci		cipher_len = regk_crypto_key_256;
171362306a36Sopenharmony_ci		break;
171462306a36Sopenharmony_ci	default:
171562306a36Sopenharmony_ci		pr_err("%s: Invalid key length %zu!\n",
171662306a36Sopenharmony_ci			MODULE_NAME, ctx->key_length);
171762306a36Sopenharmony_ci		return -EINVAL;
171862306a36Sopenharmony_ci	}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	switch (ctx->crypto_type) {
172162306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_ECB:
172262306a36Sopenharmony_ci		oper = regk_crypto_aes_ecb;
172362306a36Sopenharmony_ci		cipher_decr = req_ctx->decrypt;
172462306a36Sopenharmony_ci		break;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_CBC:
172762306a36Sopenharmony_ci		oper = regk_crypto_aes_cbc;
172862306a36Sopenharmony_ci		cipher_decr = req_ctx->decrypt;
172962306a36Sopenharmony_ci		break;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_CTR:
173262306a36Sopenharmony_ci		oper = regk_crypto_aes_ctr;
173362306a36Sopenharmony_ci		cipher_decr = false;
173462306a36Sopenharmony_ci		break;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_CIPHER_AES_XTS:
173762306a36Sopenharmony_ci		oper = regk_crypto_aes_xts;
173862306a36Sopenharmony_ci		cipher_decr = req_ctx->decrypt;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci		if (variant == ARTPEC6_CRYPTO)
174162306a36Sopenharmony_ci			req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DSEQ;
174262306a36Sopenharmony_ci		else
174362306a36Sopenharmony_ci			req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DSEQ;
174462306a36Sopenharmony_ci		break;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	default:
174762306a36Sopenharmony_ci		pr_err("%s: Invalid cipher mode %d!\n",
174862306a36Sopenharmony_ci			MODULE_NAME, ctx->crypto_type);
174962306a36Sopenharmony_ci		return -EINVAL;
175062306a36Sopenharmony_ci	}
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO) {
175362306a36Sopenharmony_ci		req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_OPER, oper);
175462306a36Sopenharmony_ci		req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_CIPHER_LEN,
175562306a36Sopenharmony_ci						 cipher_len);
175662306a36Sopenharmony_ci		if (cipher_decr)
175762306a36Sopenharmony_ci			req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DECR;
175862306a36Sopenharmony_ci	} else {
175962306a36Sopenharmony_ci		req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_OPER, oper);
176062306a36Sopenharmony_ci		req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_CIPHER_LEN,
176162306a36Sopenharmony_ci						 cipher_len);
176262306a36Sopenharmony_ci		if (cipher_decr)
176362306a36Sopenharmony_ci			req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DECR;
176462306a36Sopenharmony_ci	}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	ret = artpec6_crypto_setup_out_descr(common,
176762306a36Sopenharmony_ci					    &req_ctx->cipher_md,
176862306a36Sopenharmony_ci					    sizeof(req_ctx->cipher_md),
176962306a36Sopenharmony_ci					    false, false);
177062306a36Sopenharmony_ci	if (ret)
177162306a36Sopenharmony_ci		return ret;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	ret = artpec6_crypto_setup_in_descr(common, ac->pad_buffer, 4, false);
177462306a36Sopenharmony_ci	if (ret)
177562306a36Sopenharmony_ci		return ret;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	if (iv_len) {
177862306a36Sopenharmony_ci		ret = artpec6_crypto_setup_out_descr(common, areq->iv, iv_len,
177962306a36Sopenharmony_ci						     false, false);
178062306a36Sopenharmony_ci		if (ret)
178162306a36Sopenharmony_ci			return ret;
178262306a36Sopenharmony_ci	}
178362306a36Sopenharmony_ci	/* Data out */
178462306a36Sopenharmony_ci	artpec6_crypto_walk_init(&walk, areq->src);
178562306a36Sopenharmony_ci	ret = artpec6_crypto_setup_sg_descrs_out(common, &walk, areq->cryptlen);
178662306a36Sopenharmony_ci	if (ret)
178762306a36Sopenharmony_ci		return ret;
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	/* Data in */
179062306a36Sopenharmony_ci	artpec6_crypto_walk_init(&walk, areq->dst);
179162306a36Sopenharmony_ci	ret = artpec6_crypto_setup_sg_descrs_in(common, &walk, areq->cryptlen);
179262306a36Sopenharmony_ci	if (ret)
179362306a36Sopenharmony_ci		return ret;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	/* CTR-mode padding required by the HW. */
179662306a36Sopenharmony_ci	if (ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_CTR ||
179762306a36Sopenharmony_ci	    ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_XTS) {
179862306a36Sopenharmony_ci		size_t pad = ALIGN(areq->cryptlen, AES_BLOCK_SIZE) -
179962306a36Sopenharmony_ci			     areq->cryptlen;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci		if (pad) {
180262306a36Sopenharmony_ci			ret = artpec6_crypto_setup_out_descr(common,
180362306a36Sopenharmony_ci							     ac->pad_buffer,
180462306a36Sopenharmony_ci							     pad, false, false);
180562306a36Sopenharmony_ci			if (ret)
180662306a36Sopenharmony_ci				return ret;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci			ret = artpec6_crypto_setup_in_descr(common,
180962306a36Sopenharmony_ci							    ac->pad_buffer, pad,
181062306a36Sopenharmony_ci							    false);
181162306a36Sopenharmony_ci			if (ret)
181262306a36Sopenharmony_ci				return ret;
181362306a36Sopenharmony_ci		}
181462306a36Sopenharmony_ci	}
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	ret = artpec6_crypto_terminate_out_descrs(common);
181762306a36Sopenharmony_ci	if (ret)
181862306a36Sopenharmony_ci		return ret;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	ret = artpec6_crypto_terminate_in_descrs(common);
182162306a36Sopenharmony_ci	if (ret)
182262306a36Sopenharmony_ci		return ret;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	return artpec6_crypto_dma_map_descs(common);
182562306a36Sopenharmony_ci}
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_cistatic int artpec6_crypto_prepare_aead(struct aead_request *areq)
182862306a36Sopenharmony_ci{
182962306a36Sopenharmony_ci	size_t count;
183062306a36Sopenharmony_ci	int ret;
183162306a36Sopenharmony_ci	size_t input_length;
183262306a36Sopenharmony_ci	struct artpec6_cryptotfm_context *ctx = crypto_tfm_ctx(areq->base.tfm);
183362306a36Sopenharmony_ci	struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(areq);
183462306a36Sopenharmony_ci	struct crypto_aead *cipher = crypto_aead_reqtfm(areq);
183562306a36Sopenharmony_ci	struct artpec6_crypto_req_common *common = &req_ctx->common;
183662306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
183762306a36Sopenharmony_ci	enum artpec6_crypto_variant variant = ac->variant;
183862306a36Sopenharmony_ci	u32 md_cipher_len;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	artpec6_crypto_init_dma_operation(common);
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	/* Key */
184362306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO) {
184462306a36Sopenharmony_ci		ctx->key_md = FIELD_PREP(A6_CRY_MD_OPER,
184562306a36Sopenharmony_ci					 a6_regk_crypto_dlkey);
184662306a36Sopenharmony_ci	} else {
184762306a36Sopenharmony_ci		ctx->key_md = FIELD_PREP(A7_CRY_MD_OPER,
184862306a36Sopenharmony_ci					 a7_regk_crypto_dlkey);
184962306a36Sopenharmony_ci	}
185062306a36Sopenharmony_ci	ret = artpec6_crypto_setup_out_descr(common, (void *)&ctx->key_md,
185162306a36Sopenharmony_ci					     sizeof(ctx->key_md), false, false);
185262306a36Sopenharmony_ci	if (ret)
185362306a36Sopenharmony_ci		return ret;
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	ret = artpec6_crypto_setup_out_descr(common, ctx->aes_key,
185662306a36Sopenharmony_ci					     ctx->key_length, true, false);
185762306a36Sopenharmony_ci	if (ret)
185862306a36Sopenharmony_ci		return ret;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	req_ctx->cipher_md = 0;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	switch (ctx->key_length) {
186362306a36Sopenharmony_ci	case 16:
186462306a36Sopenharmony_ci		md_cipher_len = regk_crypto_key_128;
186562306a36Sopenharmony_ci		break;
186662306a36Sopenharmony_ci	case 24:
186762306a36Sopenharmony_ci		md_cipher_len = regk_crypto_key_192;
186862306a36Sopenharmony_ci		break;
186962306a36Sopenharmony_ci	case 32:
187062306a36Sopenharmony_ci		md_cipher_len = regk_crypto_key_256;
187162306a36Sopenharmony_ci		break;
187262306a36Sopenharmony_ci	default:
187362306a36Sopenharmony_ci		return -EINVAL;
187462306a36Sopenharmony_ci	}
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO) {
187762306a36Sopenharmony_ci		req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_OPER,
187862306a36Sopenharmony_ci						 regk_crypto_aes_gcm);
187962306a36Sopenharmony_ci		req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_CIPHER_LEN,
188062306a36Sopenharmony_ci						 md_cipher_len);
188162306a36Sopenharmony_ci		if (req_ctx->decrypt)
188262306a36Sopenharmony_ci			req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DECR;
188362306a36Sopenharmony_ci	} else {
188462306a36Sopenharmony_ci		req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_OPER,
188562306a36Sopenharmony_ci						 regk_crypto_aes_gcm);
188662306a36Sopenharmony_ci		req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_CIPHER_LEN,
188762306a36Sopenharmony_ci						 md_cipher_len);
188862306a36Sopenharmony_ci		if (req_ctx->decrypt)
188962306a36Sopenharmony_ci			req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DECR;
189062306a36Sopenharmony_ci	}
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	ret = artpec6_crypto_setup_out_descr(common,
189362306a36Sopenharmony_ci					    (void *) &req_ctx->cipher_md,
189462306a36Sopenharmony_ci					    sizeof(req_ctx->cipher_md), false,
189562306a36Sopenharmony_ci					    false);
189662306a36Sopenharmony_ci	if (ret)
189762306a36Sopenharmony_ci		return ret;
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	ret = artpec6_crypto_setup_in_descr(common, ac->pad_buffer, 4, false);
190062306a36Sopenharmony_ci	if (ret)
190162306a36Sopenharmony_ci		return ret;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	/* For the decryption, cryptlen includes the tag. */
190462306a36Sopenharmony_ci	input_length = areq->cryptlen;
190562306a36Sopenharmony_ci	if (req_ctx->decrypt)
190662306a36Sopenharmony_ci		input_length -= crypto_aead_authsize(cipher);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	/* Prepare the context buffer */
190962306a36Sopenharmony_ci	req_ctx->hw_ctx.aad_length_bits =
191062306a36Sopenharmony_ci		__cpu_to_be64(8*areq->assoclen);
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	req_ctx->hw_ctx.text_length_bits =
191362306a36Sopenharmony_ci		__cpu_to_be64(8*input_length);
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	memcpy(req_ctx->hw_ctx.J0, areq->iv, crypto_aead_ivsize(cipher));
191662306a36Sopenharmony_ci	// The HW omits the initial increment of the counter field.
191762306a36Sopenharmony_ci	memcpy(req_ctx->hw_ctx.J0 + GCM_AES_IV_SIZE, "\x00\x00\x00\x01", 4);
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	ret = artpec6_crypto_setup_out_descr(common, &req_ctx->hw_ctx,
192062306a36Sopenharmony_ci		sizeof(struct artpec6_crypto_aead_hw_ctx), false, false);
192162306a36Sopenharmony_ci	if (ret)
192262306a36Sopenharmony_ci		return ret;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	{
192562306a36Sopenharmony_ci		struct artpec6_crypto_walk walk;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci		artpec6_crypto_walk_init(&walk, areq->src);
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci		/* Associated data */
193062306a36Sopenharmony_ci		count = areq->assoclen;
193162306a36Sopenharmony_ci		ret = artpec6_crypto_setup_sg_descrs_out(common, &walk, count);
193262306a36Sopenharmony_ci		if (ret)
193362306a36Sopenharmony_ci			return ret;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci		if (!IS_ALIGNED(areq->assoclen, 16)) {
193662306a36Sopenharmony_ci			size_t assoc_pad = 16 - (areq->assoclen % 16);
193762306a36Sopenharmony_ci			/* The HW mandates zero padding here */
193862306a36Sopenharmony_ci			ret = artpec6_crypto_setup_out_descr(common,
193962306a36Sopenharmony_ci							     ac->zero_buffer,
194062306a36Sopenharmony_ci							     assoc_pad, false,
194162306a36Sopenharmony_ci							     false);
194262306a36Sopenharmony_ci			if (ret)
194362306a36Sopenharmony_ci				return ret;
194462306a36Sopenharmony_ci		}
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci		/* Data to crypto */
194762306a36Sopenharmony_ci		count = input_length;
194862306a36Sopenharmony_ci		ret = artpec6_crypto_setup_sg_descrs_out(common, &walk, count);
194962306a36Sopenharmony_ci		if (ret)
195062306a36Sopenharmony_ci			return ret;
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci		if (!IS_ALIGNED(input_length, 16)) {
195362306a36Sopenharmony_ci			size_t crypto_pad = 16 - (input_length % 16);
195462306a36Sopenharmony_ci			/* The HW mandates zero padding here */
195562306a36Sopenharmony_ci			ret = artpec6_crypto_setup_out_descr(common,
195662306a36Sopenharmony_ci							     ac->zero_buffer,
195762306a36Sopenharmony_ci							     crypto_pad,
195862306a36Sopenharmony_ci							     false,
195962306a36Sopenharmony_ci							     false);
196062306a36Sopenharmony_ci			if (ret)
196162306a36Sopenharmony_ci				return ret;
196262306a36Sopenharmony_ci		}
196362306a36Sopenharmony_ci	}
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	/* Data from crypto */
196662306a36Sopenharmony_ci	{
196762306a36Sopenharmony_ci		struct artpec6_crypto_walk walk;
196862306a36Sopenharmony_ci		size_t output_len = areq->cryptlen;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci		if (req_ctx->decrypt)
197162306a36Sopenharmony_ci			output_len -= crypto_aead_authsize(cipher);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci		artpec6_crypto_walk_init(&walk, areq->dst);
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci		/* skip associated data in the output */
197662306a36Sopenharmony_ci		count = artpec6_crypto_walk_advance(&walk, areq->assoclen);
197762306a36Sopenharmony_ci		if (count)
197862306a36Sopenharmony_ci			return -EINVAL;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci		count = output_len;
198162306a36Sopenharmony_ci		ret = artpec6_crypto_setup_sg_descrs_in(common, &walk, count);
198262306a36Sopenharmony_ci		if (ret)
198362306a36Sopenharmony_ci			return ret;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci		/* Put padding between the cryptotext and the auth tag */
198662306a36Sopenharmony_ci		if (!IS_ALIGNED(output_len, 16)) {
198762306a36Sopenharmony_ci			size_t crypto_pad = 16 - (output_len % 16);
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci			ret = artpec6_crypto_setup_in_descr(common,
199062306a36Sopenharmony_ci							    ac->pad_buffer,
199162306a36Sopenharmony_ci							    crypto_pad, false);
199262306a36Sopenharmony_ci			if (ret)
199362306a36Sopenharmony_ci				return ret;
199462306a36Sopenharmony_ci		}
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci		/* The authentication tag shall follow immediately after
199762306a36Sopenharmony_ci		 * the output ciphertext. For decryption it is put in a context
199862306a36Sopenharmony_ci		 * buffer for later compare against the input tag.
199962306a36Sopenharmony_ci		 */
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci		if (req_ctx->decrypt) {
200262306a36Sopenharmony_ci			ret = artpec6_crypto_setup_in_descr(common,
200362306a36Sopenharmony_ci				req_ctx->decryption_tag, AES_BLOCK_SIZE, false);
200462306a36Sopenharmony_ci			if (ret)
200562306a36Sopenharmony_ci				return ret;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci		} else {
200862306a36Sopenharmony_ci			/* For encryption the requested tag size may be smaller
200962306a36Sopenharmony_ci			 * than the hardware's generated tag.
201062306a36Sopenharmony_ci			 */
201162306a36Sopenharmony_ci			size_t authsize = crypto_aead_authsize(cipher);
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci			ret = artpec6_crypto_setup_sg_descrs_in(common, &walk,
201462306a36Sopenharmony_ci								authsize);
201562306a36Sopenharmony_ci			if (ret)
201662306a36Sopenharmony_ci				return ret;
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci			if (authsize < AES_BLOCK_SIZE) {
201962306a36Sopenharmony_ci				count = AES_BLOCK_SIZE - authsize;
202062306a36Sopenharmony_ci				ret = artpec6_crypto_setup_in_descr(common,
202162306a36Sopenharmony_ci					ac->pad_buffer,
202262306a36Sopenharmony_ci					count, false);
202362306a36Sopenharmony_ci				if (ret)
202462306a36Sopenharmony_ci					return ret;
202562306a36Sopenharmony_ci			}
202662306a36Sopenharmony_ci		}
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	ret = artpec6_crypto_terminate_in_descrs(common);
203162306a36Sopenharmony_ci	if (ret)
203262306a36Sopenharmony_ci		return ret;
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	ret = artpec6_crypto_terminate_out_descrs(common);
203562306a36Sopenharmony_ci	if (ret)
203662306a36Sopenharmony_ci		return ret;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	return artpec6_crypto_dma_map_descs(common);
203962306a36Sopenharmony_ci}
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_cistatic void artpec6_crypto_process_queue(struct artpec6_crypto *ac,
204262306a36Sopenharmony_ci	    struct list_head *completions)
204362306a36Sopenharmony_ci{
204462306a36Sopenharmony_ci	struct artpec6_crypto_req_common *req;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	while (!list_empty(&ac->queue) && !artpec6_crypto_busy()) {
204762306a36Sopenharmony_ci		req = list_first_entry(&ac->queue,
204862306a36Sopenharmony_ci				       struct artpec6_crypto_req_common,
204962306a36Sopenharmony_ci				       list);
205062306a36Sopenharmony_ci		list_move_tail(&req->list, &ac->pending);
205162306a36Sopenharmony_ci		artpec6_crypto_start_dma(req);
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci		list_add_tail(&req->complete_in_progress, completions);
205462306a36Sopenharmony_ci	}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	/*
205762306a36Sopenharmony_ci	 * In some cases, the hardware can raise an in_eop_flush interrupt
205862306a36Sopenharmony_ci	 * before actually updating the status, so we have an timer which will
205962306a36Sopenharmony_ci	 * recheck the status on timeout.  Since the cases are expected to be
206062306a36Sopenharmony_ci	 * very rare, we use a relatively large timeout value.  There should be
206162306a36Sopenharmony_ci	 * no noticeable negative effect if we timeout spuriously.
206262306a36Sopenharmony_ci	 */
206362306a36Sopenharmony_ci	if (ac->pending_count)
206462306a36Sopenharmony_ci		mod_timer(&ac->timer, jiffies + msecs_to_jiffies(100));
206562306a36Sopenharmony_ci	else
206662306a36Sopenharmony_ci		del_timer(&ac->timer);
206762306a36Sopenharmony_ci}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_cistatic void artpec6_crypto_timeout(struct timer_list *t)
207062306a36Sopenharmony_ci{
207162306a36Sopenharmony_ci	struct artpec6_crypto *ac = from_timer(ac, t, timer);
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci	dev_info_ratelimited(artpec6_crypto_dev, "timeout\n");
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci	tasklet_schedule(&ac->task);
207662306a36Sopenharmony_ci}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_cistatic void artpec6_crypto_task(unsigned long data)
207962306a36Sopenharmony_ci{
208062306a36Sopenharmony_ci	struct artpec6_crypto *ac = (struct artpec6_crypto *)data;
208162306a36Sopenharmony_ci	struct artpec6_crypto_req_common *req;
208262306a36Sopenharmony_ci	struct artpec6_crypto_req_common *n;
208362306a36Sopenharmony_ci	struct list_head complete_done;
208462306a36Sopenharmony_ci	struct list_head complete_in_progress;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	INIT_LIST_HEAD(&complete_done);
208762306a36Sopenharmony_ci	INIT_LIST_HEAD(&complete_in_progress);
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	if (list_empty(&ac->pending)) {
209062306a36Sopenharmony_ci		pr_debug("Spurious IRQ\n");
209162306a36Sopenharmony_ci		return;
209262306a36Sopenharmony_ci	}
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	spin_lock(&ac->queue_lock);
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	list_for_each_entry_safe(req, n, &ac->pending, list) {
209762306a36Sopenharmony_ci		struct artpec6_crypto_dma_descriptors *dma = req->dma;
209862306a36Sopenharmony_ci		u32 stat;
209962306a36Sopenharmony_ci		dma_addr_t stataddr;
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci		stataddr = dma->stat_dma_addr + 4 * (req->dma->in_cnt - 1);
210262306a36Sopenharmony_ci		dma_sync_single_for_cpu(artpec6_crypto_dev,
210362306a36Sopenharmony_ci					stataddr,
210462306a36Sopenharmony_ci					4,
210562306a36Sopenharmony_ci					DMA_BIDIRECTIONAL);
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci		stat = req->dma->stat[req->dma->in_cnt-1];
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci		/* A non-zero final status descriptor indicates
211062306a36Sopenharmony_ci		 * this job has finished.
211162306a36Sopenharmony_ci		 */
211262306a36Sopenharmony_ci		pr_debug("Request %p status is %X\n", req, stat);
211362306a36Sopenharmony_ci		if (!stat)
211462306a36Sopenharmony_ci			break;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci		/* Allow testing of timeout handling with fault injection */
211762306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION
211862306a36Sopenharmony_ci		if (should_fail(&artpec6_crypto_fail_status_read, 1))
211962306a36Sopenharmony_ci			continue;
212062306a36Sopenharmony_ci#endif
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci		pr_debug("Completing request %p\n", req);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci		list_move_tail(&req->list, &complete_done);
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci		ac->pending_count--;
212762306a36Sopenharmony_ci	}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	artpec6_crypto_process_queue(ac, &complete_in_progress);
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	spin_unlock(&ac->queue_lock);
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	/* Perform the completion callbacks without holding the queue lock
213462306a36Sopenharmony_ci	 * to allow new request submissions from the callbacks.
213562306a36Sopenharmony_ci	 */
213662306a36Sopenharmony_ci	list_for_each_entry_safe(req, n, &complete_done, list) {
213762306a36Sopenharmony_ci		artpec6_crypto_dma_unmap_all(req);
213862306a36Sopenharmony_ci		artpec6_crypto_copy_bounce_buffers(req);
213962306a36Sopenharmony_ci		artpec6_crypto_common_destroy(req);
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci		req->complete(req->req);
214262306a36Sopenharmony_ci	}
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	list_for_each_entry_safe(req, n, &complete_in_progress,
214562306a36Sopenharmony_ci				 complete_in_progress) {
214662306a36Sopenharmony_ci		crypto_request_complete(req->req, -EINPROGRESS);
214762306a36Sopenharmony_ci	}
214862306a36Sopenharmony_ci}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_cistatic void artpec6_crypto_complete_crypto(struct crypto_async_request *req)
215162306a36Sopenharmony_ci{
215262306a36Sopenharmony_ci	crypto_request_complete(req, 0);
215362306a36Sopenharmony_ci}
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_cistatic void
215662306a36Sopenharmony_ciartpec6_crypto_complete_cbc_decrypt(struct crypto_async_request *req)
215762306a36Sopenharmony_ci{
215862306a36Sopenharmony_ci	struct skcipher_request *cipher_req = container_of(req,
215962306a36Sopenharmony_ci		struct skcipher_request, base);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	scatterwalk_map_and_copy(cipher_req->iv, cipher_req->src,
216262306a36Sopenharmony_ci				 cipher_req->cryptlen - AES_BLOCK_SIZE,
216362306a36Sopenharmony_ci				 AES_BLOCK_SIZE, 0);
216462306a36Sopenharmony_ci	skcipher_request_complete(cipher_req, 0);
216562306a36Sopenharmony_ci}
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_cistatic void
216862306a36Sopenharmony_ciartpec6_crypto_complete_cbc_encrypt(struct crypto_async_request *req)
216962306a36Sopenharmony_ci{
217062306a36Sopenharmony_ci	struct skcipher_request *cipher_req = container_of(req,
217162306a36Sopenharmony_ci		struct skcipher_request, base);
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	scatterwalk_map_and_copy(cipher_req->iv, cipher_req->dst,
217462306a36Sopenharmony_ci				 cipher_req->cryptlen - AES_BLOCK_SIZE,
217562306a36Sopenharmony_ci				 AES_BLOCK_SIZE, 0);
217662306a36Sopenharmony_ci	skcipher_request_complete(cipher_req, 0);
217762306a36Sopenharmony_ci}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_cistatic void artpec6_crypto_complete_aead(struct crypto_async_request *req)
218062306a36Sopenharmony_ci{
218162306a36Sopenharmony_ci	int result = 0;
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	/* Verify GCM hashtag. */
218462306a36Sopenharmony_ci	struct aead_request *areq = container_of(req,
218562306a36Sopenharmony_ci		struct aead_request, base);
218662306a36Sopenharmony_ci	struct crypto_aead *aead = crypto_aead_reqtfm(areq);
218762306a36Sopenharmony_ci	struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(areq);
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci	if (req_ctx->decrypt) {
219062306a36Sopenharmony_ci		u8 input_tag[AES_BLOCK_SIZE];
219162306a36Sopenharmony_ci		unsigned int authsize = crypto_aead_authsize(aead);
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci		sg_pcopy_to_buffer(areq->src,
219462306a36Sopenharmony_ci				   sg_nents(areq->src),
219562306a36Sopenharmony_ci				   input_tag,
219662306a36Sopenharmony_ci				   authsize,
219762306a36Sopenharmony_ci				   areq->assoclen + areq->cryptlen -
219862306a36Sopenharmony_ci				   authsize);
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci		if (crypto_memneq(req_ctx->decryption_tag,
220162306a36Sopenharmony_ci				  input_tag,
220262306a36Sopenharmony_ci				  authsize)) {
220362306a36Sopenharmony_ci			pr_debug("***EBADMSG:\n");
220462306a36Sopenharmony_ci			print_hex_dump_debug("ref:", DUMP_PREFIX_ADDRESS, 32, 1,
220562306a36Sopenharmony_ci					     input_tag, authsize, true);
220662306a36Sopenharmony_ci			print_hex_dump_debug("out:", DUMP_PREFIX_ADDRESS, 32, 1,
220762306a36Sopenharmony_ci					     req_ctx->decryption_tag,
220862306a36Sopenharmony_ci					     authsize, true);
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci			result = -EBADMSG;
221162306a36Sopenharmony_ci		}
221262306a36Sopenharmony_ci	}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	aead_request_complete(areq, result);
221562306a36Sopenharmony_ci}
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_cistatic void artpec6_crypto_complete_hash(struct crypto_async_request *req)
221862306a36Sopenharmony_ci{
221962306a36Sopenharmony_ci	crypto_request_complete(req, 0);
222062306a36Sopenharmony_ci}
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci/*------------------- Hash functions -----------------------------------------*/
222462306a36Sopenharmony_cistatic int
222562306a36Sopenharmony_ciartpec6_crypto_hash_set_key(struct crypto_ahash *tfm,
222662306a36Sopenharmony_ci		    const u8 *key, unsigned int keylen)
222762306a36Sopenharmony_ci{
222862306a36Sopenharmony_ci	struct artpec6_hashalg_context *tfm_ctx = crypto_tfm_ctx(&tfm->base);
222962306a36Sopenharmony_ci	size_t blocksize;
223062306a36Sopenharmony_ci	int ret;
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_ci	if (!keylen) {
223362306a36Sopenharmony_ci		pr_err("Invalid length (%d) of HMAC key\n",
223462306a36Sopenharmony_ci			keylen);
223562306a36Sopenharmony_ci		return -EINVAL;
223662306a36Sopenharmony_ci	}
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	memset(tfm_ctx->hmac_key, 0, sizeof(tfm_ctx->hmac_key));
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	if (keylen > blocksize) {
224362306a36Sopenharmony_ci		tfm_ctx->hmac_key_length = blocksize;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci		ret = crypto_shash_tfm_digest(tfm_ctx->child_hash, key, keylen,
224662306a36Sopenharmony_ci					      tfm_ctx->hmac_key);
224762306a36Sopenharmony_ci		if (ret)
224862306a36Sopenharmony_ci			return ret;
224962306a36Sopenharmony_ci	} else {
225062306a36Sopenharmony_ci		memcpy(tfm_ctx->hmac_key, key, keylen);
225162306a36Sopenharmony_ci		tfm_ctx->hmac_key_length = keylen;
225262306a36Sopenharmony_ci	}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	return 0;
225562306a36Sopenharmony_ci}
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_cistatic int
225862306a36Sopenharmony_ciartpec6_crypto_init_hash(struct ahash_request *req, u8 type, int hmac)
225962306a36Sopenharmony_ci{
226062306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
226162306a36Sopenharmony_ci	enum artpec6_crypto_variant variant = ac->variant;
226262306a36Sopenharmony_ci	struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req);
226362306a36Sopenharmony_ci	u32 oper;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci	memset(req_ctx, 0, sizeof(*req_ctx));
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	req_ctx->hash_flags = HASH_FLAG_INIT_CTX;
226862306a36Sopenharmony_ci	if (hmac)
226962306a36Sopenharmony_ci		req_ctx->hash_flags |= (HASH_FLAG_HMAC | HASH_FLAG_UPDATE_KEY);
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	switch (type) {
227262306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_HASH_SHA1:
227362306a36Sopenharmony_ci		oper = hmac ? regk_crypto_hmac_sha1 : regk_crypto_sha1;
227462306a36Sopenharmony_ci		break;
227562306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_HASH_SHA256:
227662306a36Sopenharmony_ci		oper = hmac ? regk_crypto_hmac_sha256 : regk_crypto_sha256;
227762306a36Sopenharmony_ci		break;
227862306a36Sopenharmony_ci	default:
227962306a36Sopenharmony_ci		pr_err("%s: Unsupported hash type 0x%x\n", MODULE_NAME, type);
228062306a36Sopenharmony_ci		return -EINVAL;
228162306a36Sopenharmony_ci	}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO)
228462306a36Sopenharmony_ci		req_ctx->hash_md = FIELD_PREP(A6_CRY_MD_OPER, oper);
228562306a36Sopenharmony_ci	else
228662306a36Sopenharmony_ci		req_ctx->hash_md = FIELD_PREP(A7_CRY_MD_OPER, oper);
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	return 0;
228962306a36Sopenharmony_ci}
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_cistatic int artpec6_crypto_prepare_submit_hash(struct ahash_request *req)
229262306a36Sopenharmony_ci{
229362306a36Sopenharmony_ci	struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req);
229462306a36Sopenharmony_ci	int ret;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	if (!req_ctx->common.dma) {
229762306a36Sopenharmony_ci		ret = artpec6_crypto_common_init(&req_ctx->common,
229862306a36Sopenharmony_ci					  &req->base,
229962306a36Sopenharmony_ci					  artpec6_crypto_complete_hash,
230062306a36Sopenharmony_ci					  NULL, 0);
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci		if (ret)
230362306a36Sopenharmony_ci			return ret;
230462306a36Sopenharmony_ci	}
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	ret = artpec6_crypto_prepare_hash(req);
230762306a36Sopenharmony_ci	switch (ret) {
230862306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_PREPARE_HASH_START:
230962306a36Sopenharmony_ci		ret = artpec6_crypto_submit(&req_ctx->common);
231062306a36Sopenharmony_ci		break;
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	case ARTPEC6_CRYPTO_PREPARE_HASH_NO_START:
231362306a36Sopenharmony_ci		ret = 0;
231462306a36Sopenharmony_ci		fallthrough;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	default:
231762306a36Sopenharmony_ci		artpec6_crypto_common_destroy(&req_ctx->common);
231862306a36Sopenharmony_ci		break;
231962306a36Sopenharmony_ci	}
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	return ret;
232262306a36Sopenharmony_ci}
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_cistatic int artpec6_crypto_hash_final(struct ahash_request *req)
232562306a36Sopenharmony_ci{
232662306a36Sopenharmony_ci	struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req);
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	req_ctx->hash_flags |= HASH_FLAG_FINALIZE;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	return artpec6_crypto_prepare_submit_hash(req);
233162306a36Sopenharmony_ci}
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_cistatic int artpec6_crypto_hash_update(struct ahash_request *req)
233462306a36Sopenharmony_ci{
233562306a36Sopenharmony_ci	struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req);
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	req_ctx->hash_flags |= HASH_FLAG_UPDATE;
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	return artpec6_crypto_prepare_submit_hash(req);
234062306a36Sopenharmony_ci}
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_cistatic int artpec6_crypto_sha1_init(struct ahash_request *req)
234362306a36Sopenharmony_ci{
234462306a36Sopenharmony_ci	return artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA1, 0);
234562306a36Sopenharmony_ci}
234662306a36Sopenharmony_ci
234762306a36Sopenharmony_cistatic int artpec6_crypto_sha1_digest(struct ahash_request *req)
234862306a36Sopenharmony_ci{
234962306a36Sopenharmony_ci	struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req);
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA1, 0);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	req_ctx->hash_flags |= HASH_FLAG_UPDATE | HASH_FLAG_FINALIZE;
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	return artpec6_crypto_prepare_submit_hash(req);
235662306a36Sopenharmony_ci}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_cistatic int artpec6_crypto_sha256_init(struct ahash_request *req)
235962306a36Sopenharmony_ci{
236062306a36Sopenharmony_ci	return artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 0);
236162306a36Sopenharmony_ci}
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_cistatic int artpec6_crypto_sha256_digest(struct ahash_request *req)
236462306a36Sopenharmony_ci{
236562306a36Sopenharmony_ci	struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req);
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 0);
236862306a36Sopenharmony_ci	req_ctx->hash_flags |= HASH_FLAG_UPDATE | HASH_FLAG_FINALIZE;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	return artpec6_crypto_prepare_submit_hash(req);
237162306a36Sopenharmony_ci}
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_cistatic int artpec6_crypto_hmac_sha256_init(struct ahash_request *req)
237462306a36Sopenharmony_ci{
237562306a36Sopenharmony_ci	return artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 1);
237662306a36Sopenharmony_ci}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_cistatic int artpec6_crypto_hmac_sha256_digest(struct ahash_request *req)
237962306a36Sopenharmony_ci{
238062306a36Sopenharmony_ci	struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req);
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci	artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 1);
238362306a36Sopenharmony_ci	req_ctx->hash_flags |= HASH_FLAG_UPDATE | HASH_FLAG_FINALIZE;
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci	return artpec6_crypto_prepare_submit_hash(req);
238662306a36Sopenharmony_ci}
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_cistatic int artpec6_crypto_ahash_init_common(struct crypto_tfm *tfm,
238962306a36Sopenharmony_ci				    const char *base_hash_name)
239062306a36Sopenharmony_ci{
239162306a36Sopenharmony_ci	struct artpec6_hashalg_context *tfm_ctx = crypto_tfm_ctx(tfm);
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
239462306a36Sopenharmony_ci				 sizeof(struct artpec6_hash_request_context));
239562306a36Sopenharmony_ci	memset(tfm_ctx, 0, sizeof(*tfm_ctx));
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	if (base_hash_name) {
239862306a36Sopenharmony_ci		struct crypto_shash *child;
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci		child = crypto_alloc_shash(base_hash_name, 0,
240162306a36Sopenharmony_ci					   CRYPTO_ALG_NEED_FALLBACK);
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_ci		if (IS_ERR(child))
240462306a36Sopenharmony_ci			return PTR_ERR(child);
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci		tfm_ctx->child_hash = child;
240762306a36Sopenharmony_ci	}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci	return 0;
241062306a36Sopenharmony_ci}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_cistatic int artpec6_crypto_ahash_init(struct crypto_tfm *tfm)
241362306a36Sopenharmony_ci{
241462306a36Sopenharmony_ci	return artpec6_crypto_ahash_init_common(tfm, NULL);
241562306a36Sopenharmony_ci}
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_cistatic int artpec6_crypto_ahash_init_hmac_sha256(struct crypto_tfm *tfm)
241862306a36Sopenharmony_ci{
241962306a36Sopenharmony_ci	return artpec6_crypto_ahash_init_common(tfm, "sha256");
242062306a36Sopenharmony_ci}
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_cistatic void artpec6_crypto_ahash_exit(struct crypto_tfm *tfm)
242362306a36Sopenharmony_ci{
242462306a36Sopenharmony_ci	struct artpec6_hashalg_context *tfm_ctx = crypto_tfm_ctx(tfm);
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	if (tfm_ctx->child_hash)
242762306a36Sopenharmony_ci		crypto_free_shash(tfm_ctx->child_hash);
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	memset(tfm_ctx->hmac_key, 0, sizeof(tfm_ctx->hmac_key));
243062306a36Sopenharmony_ci	tfm_ctx->hmac_key_length = 0;
243162306a36Sopenharmony_ci}
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_cistatic int artpec6_crypto_hash_export(struct ahash_request *req, void *out)
243462306a36Sopenharmony_ci{
243562306a36Sopenharmony_ci	const struct artpec6_hash_request_context *ctx = ahash_request_ctx(req);
243662306a36Sopenharmony_ci	struct artpec6_hash_export_state *state = out;
243762306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
243862306a36Sopenharmony_ci	enum artpec6_crypto_variant variant = ac->variant;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(state->partial_buffer) !=
244162306a36Sopenharmony_ci		     sizeof(ctx->partial_buffer));
244262306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(state->digeststate) != sizeof(ctx->digeststate));
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	state->digcnt = ctx->digcnt;
244562306a36Sopenharmony_ci	state->partial_bytes = ctx->partial_bytes;
244662306a36Sopenharmony_ci	state->hash_flags = ctx->hash_flags;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO)
244962306a36Sopenharmony_ci		state->oper = FIELD_GET(A6_CRY_MD_OPER, ctx->hash_md);
245062306a36Sopenharmony_ci	else
245162306a36Sopenharmony_ci		state->oper = FIELD_GET(A7_CRY_MD_OPER, ctx->hash_md);
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci	memcpy(state->partial_buffer, ctx->partial_buffer,
245462306a36Sopenharmony_ci	       sizeof(state->partial_buffer));
245562306a36Sopenharmony_ci	memcpy(state->digeststate, ctx->digeststate,
245662306a36Sopenharmony_ci	       sizeof(state->digeststate));
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	return 0;
245962306a36Sopenharmony_ci}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_cistatic int artpec6_crypto_hash_import(struct ahash_request *req, const void *in)
246262306a36Sopenharmony_ci{
246362306a36Sopenharmony_ci	struct artpec6_hash_request_context *ctx = ahash_request_ctx(req);
246462306a36Sopenharmony_ci	const struct artpec6_hash_export_state *state = in;
246562306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev);
246662306a36Sopenharmony_ci	enum artpec6_crypto_variant variant = ac->variant;
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	memset(ctx, 0, sizeof(*ctx));
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	ctx->digcnt = state->digcnt;
247162306a36Sopenharmony_ci	ctx->partial_bytes = state->partial_bytes;
247262306a36Sopenharmony_ci	ctx->hash_flags = state->hash_flags;
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO)
247562306a36Sopenharmony_ci		ctx->hash_md = FIELD_PREP(A6_CRY_MD_OPER, state->oper);
247662306a36Sopenharmony_ci	else
247762306a36Sopenharmony_ci		ctx->hash_md = FIELD_PREP(A7_CRY_MD_OPER, state->oper);
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	memcpy(ctx->partial_buffer, state->partial_buffer,
248062306a36Sopenharmony_ci	       sizeof(state->partial_buffer));
248162306a36Sopenharmony_ci	memcpy(ctx->digeststate, state->digeststate,
248262306a36Sopenharmony_ci	       sizeof(state->digeststate));
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	return 0;
248562306a36Sopenharmony_ci}
248662306a36Sopenharmony_ci
248762306a36Sopenharmony_cistatic int init_crypto_hw(struct artpec6_crypto *ac)
248862306a36Sopenharmony_ci{
248962306a36Sopenharmony_ci	enum artpec6_crypto_variant variant = ac->variant;
249062306a36Sopenharmony_ci	void __iomem *base = ac->base;
249162306a36Sopenharmony_ci	u32 out_descr_buf_size;
249262306a36Sopenharmony_ci	u32 out_data_buf_size;
249362306a36Sopenharmony_ci	u32 in_data_buf_size;
249462306a36Sopenharmony_ci	u32 in_descr_buf_size;
249562306a36Sopenharmony_ci	u32 in_stat_buf_size;
249662306a36Sopenharmony_ci	u32 in, out;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	/*
249962306a36Sopenharmony_ci	 * The PDMA unit contains 1984 bytes of internal memory for the OUT
250062306a36Sopenharmony_ci	 * channels and 1024 bytes for the IN channel. This is an elastic
250162306a36Sopenharmony_ci	 * memory used to internally store the descriptors and data. The values
250262306a36Sopenharmony_ci	 * ares specified in 64 byte incremements.  Trustzone buffers are not
250362306a36Sopenharmony_ci	 * used at this stage.
250462306a36Sopenharmony_ci	 */
250562306a36Sopenharmony_ci	out_data_buf_size = 16;  /* 1024 bytes for data */
250662306a36Sopenharmony_ci	out_descr_buf_size = 15; /* 960 bytes for descriptors */
250762306a36Sopenharmony_ci	in_data_buf_size = 8;    /* 512 bytes for data */
250862306a36Sopenharmony_ci	in_descr_buf_size = 4;   /* 256 bytes for descriptors */
250962306a36Sopenharmony_ci	in_stat_buf_size = 4;   /* 256 bytes for stat descrs */
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	BUILD_BUG_ON_MSG((out_data_buf_size
251262306a36Sopenharmony_ci				+ out_descr_buf_size) * 64 > 1984,
251362306a36Sopenharmony_ci			  "Invalid OUT configuration");
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	BUILD_BUG_ON_MSG((in_data_buf_size
251662306a36Sopenharmony_ci				+ in_descr_buf_size
251762306a36Sopenharmony_ci				+ in_stat_buf_size) * 64 > 1024,
251862306a36Sopenharmony_ci			  "Invalid IN configuration");
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	in = FIELD_PREP(PDMA_IN_BUF_CFG_DATA_BUF_SIZE, in_data_buf_size) |
252162306a36Sopenharmony_ci	     FIELD_PREP(PDMA_IN_BUF_CFG_DESCR_BUF_SIZE, in_descr_buf_size) |
252262306a36Sopenharmony_ci	     FIELD_PREP(PDMA_IN_BUF_CFG_STAT_BUF_SIZE, in_stat_buf_size);
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci	out = FIELD_PREP(PDMA_OUT_BUF_CFG_DATA_BUF_SIZE, out_data_buf_size) |
252562306a36Sopenharmony_ci	      FIELD_PREP(PDMA_OUT_BUF_CFG_DESCR_BUF_SIZE, out_descr_buf_size);
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	writel_relaxed(out, base + PDMA_OUT_BUF_CFG);
252862306a36Sopenharmony_ci	writel_relaxed(PDMA_OUT_CFG_EN, base + PDMA_OUT_CFG);
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO) {
253162306a36Sopenharmony_ci		writel_relaxed(in, base + A6_PDMA_IN_BUF_CFG);
253262306a36Sopenharmony_ci		writel_relaxed(PDMA_IN_CFG_EN, base + A6_PDMA_IN_CFG);
253362306a36Sopenharmony_ci		writel_relaxed(A6_PDMA_INTR_MASK_IN_DATA |
253462306a36Sopenharmony_ci			       A6_PDMA_INTR_MASK_IN_EOP_FLUSH,
253562306a36Sopenharmony_ci			       base + A6_PDMA_INTR_MASK);
253662306a36Sopenharmony_ci	} else {
253762306a36Sopenharmony_ci		writel_relaxed(in, base + A7_PDMA_IN_BUF_CFG);
253862306a36Sopenharmony_ci		writel_relaxed(PDMA_IN_CFG_EN, base + A7_PDMA_IN_CFG);
253962306a36Sopenharmony_ci		writel_relaxed(A7_PDMA_INTR_MASK_IN_DATA |
254062306a36Sopenharmony_ci			       A7_PDMA_INTR_MASK_IN_EOP_FLUSH,
254162306a36Sopenharmony_ci			       base + A7_PDMA_INTR_MASK);
254262306a36Sopenharmony_ci	}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci	return 0;
254562306a36Sopenharmony_ci}
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_cistatic void artpec6_crypto_disable_hw(struct artpec6_crypto *ac)
254862306a36Sopenharmony_ci{
254962306a36Sopenharmony_ci	enum artpec6_crypto_variant variant = ac->variant;
255062306a36Sopenharmony_ci	void __iomem *base = ac->base;
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO) {
255362306a36Sopenharmony_ci		writel_relaxed(A6_PDMA_IN_CMD_STOP, base + A6_PDMA_IN_CMD);
255462306a36Sopenharmony_ci		writel_relaxed(0, base + A6_PDMA_IN_CFG);
255562306a36Sopenharmony_ci		writel_relaxed(A6_PDMA_OUT_CMD_STOP, base + PDMA_OUT_CMD);
255662306a36Sopenharmony_ci	} else {
255762306a36Sopenharmony_ci		writel_relaxed(A7_PDMA_IN_CMD_STOP, base + A7_PDMA_IN_CMD);
255862306a36Sopenharmony_ci		writel_relaxed(0, base + A7_PDMA_IN_CFG);
255962306a36Sopenharmony_ci		writel_relaxed(A7_PDMA_OUT_CMD_STOP, base + PDMA_OUT_CMD);
256062306a36Sopenharmony_ci	}
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_ci	writel_relaxed(0, base + PDMA_OUT_CFG);
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci}
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_cistatic irqreturn_t artpec6_crypto_irq(int irq, void *dev_id)
256762306a36Sopenharmony_ci{
256862306a36Sopenharmony_ci	struct artpec6_crypto *ac = dev_id;
256962306a36Sopenharmony_ci	enum artpec6_crypto_variant variant = ac->variant;
257062306a36Sopenharmony_ci	void __iomem *base = ac->base;
257162306a36Sopenharmony_ci	u32 mask_in_data, mask_in_eop_flush;
257262306a36Sopenharmony_ci	u32 in_cmd_flush_stat, in_cmd_reg;
257362306a36Sopenharmony_ci	u32 ack_intr_reg;
257462306a36Sopenharmony_ci	u32 ack = 0;
257562306a36Sopenharmony_ci	u32 intr;
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	if (variant == ARTPEC6_CRYPTO) {
257862306a36Sopenharmony_ci		intr = readl_relaxed(base + A6_PDMA_MASKED_INTR);
257962306a36Sopenharmony_ci		mask_in_data = A6_PDMA_INTR_MASK_IN_DATA;
258062306a36Sopenharmony_ci		mask_in_eop_flush = A6_PDMA_INTR_MASK_IN_EOP_FLUSH;
258162306a36Sopenharmony_ci		in_cmd_flush_stat = A6_PDMA_IN_CMD_FLUSH_STAT;
258262306a36Sopenharmony_ci		in_cmd_reg = A6_PDMA_IN_CMD;
258362306a36Sopenharmony_ci		ack_intr_reg = A6_PDMA_ACK_INTR;
258462306a36Sopenharmony_ci	} else {
258562306a36Sopenharmony_ci		intr = readl_relaxed(base + A7_PDMA_MASKED_INTR);
258662306a36Sopenharmony_ci		mask_in_data = A7_PDMA_INTR_MASK_IN_DATA;
258762306a36Sopenharmony_ci		mask_in_eop_flush = A7_PDMA_INTR_MASK_IN_EOP_FLUSH;
258862306a36Sopenharmony_ci		in_cmd_flush_stat = A7_PDMA_IN_CMD_FLUSH_STAT;
258962306a36Sopenharmony_ci		in_cmd_reg = A7_PDMA_IN_CMD;
259062306a36Sopenharmony_ci		ack_intr_reg = A7_PDMA_ACK_INTR;
259162306a36Sopenharmony_ci	}
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	/* We get two interrupt notifications from each job.
259462306a36Sopenharmony_ci	 * The in_data means all data was sent to memory and then
259562306a36Sopenharmony_ci	 * we request a status flush command to write the per-job
259662306a36Sopenharmony_ci	 * status to its status vector. This ensures that the
259762306a36Sopenharmony_ci	 * tasklet can detect exactly how many submitted jobs
259862306a36Sopenharmony_ci	 * that have finished.
259962306a36Sopenharmony_ci	 */
260062306a36Sopenharmony_ci	if (intr & mask_in_data)
260162306a36Sopenharmony_ci		ack |= mask_in_data;
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	if (intr & mask_in_eop_flush)
260462306a36Sopenharmony_ci		ack |= mask_in_eop_flush;
260562306a36Sopenharmony_ci	else
260662306a36Sopenharmony_ci		writel_relaxed(in_cmd_flush_stat, base + in_cmd_reg);
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ci	writel_relaxed(ack, base + ack_intr_reg);
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	if (intr & mask_in_eop_flush)
261162306a36Sopenharmony_ci		tasklet_schedule(&ac->task);
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	return IRQ_HANDLED;
261462306a36Sopenharmony_ci}
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci/*------------------- Algorithm definitions ----------------------------------*/
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci/* Hashes */
261962306a36Sopenharmony_cistatic struct ahash_alg hash_algos[] = {
262062306a36Sopenharmony_ci	/* SHA-1 */
262162306a36Sopenharmony_ci	{
262262306a36Sopenharmony_ci		.init = artpec6_crypto_sha1_init,
262362306a36Sopenharmony_ci		.update = artpec6_crypto_hash_update,
262462306a36Sopenharmony_ci		.final = artpec6_crypto_hash_final,
262562306a36Sopenharmony_ci		.digest = artpec6_crypto_sha1_digest,
262662306a36Sopenharmony_ci		.import = artpec6_crypto_hash_import,
262762306a36Sopenharmony_ci		.export = artpec6_crypto_hash_export,
262862306a36Sopenharmony_ci		.halg.digestsize = SHA1_DIGEST_SIZE,
262962306a36Sopenharmony_ci		.halg.statesize = sizeof(struct artpec6_hash_export_state),
263062306a36Sopenharmony_ci		.halg.base = {
263162306a36Sopenharmony_ci			.cra_name = "sha1",
263262306a36Sopenharmony_ci			.cra_driver_name = "artpec-sha1",
263362306a36Sopenharmony_ci			.cra_priority = 300,
263462306a36Sopenharmony_ci			.cra_flags = CRYPTO_ALG_ASYNC |
263562306a36Sopenharmony_ci				     CRYPTO_ALG_ALLOCATES_MEMORY,
263662306a36Sopenharmony_ci			.cra_blocksize = SHA1_BLOCK_SIZE,
263762306a36Sopenharmony_ci			.cra_ctxsize = sizeof(struct artpec6_hashalg_context),
263862306a36Sopenharmony_ci			.cra_alignmask = 3,
263962306a36Sopenharmony_ci			.cra_module = THIS_MODULE,
264062306a36Sopenharmony_ci			.cra_init = artpec6_crypto_ahash_init,
264162306a36Sopenharmony_ci			.cra_exit = artpec6_crypto_ahash_exit,
264262306a36Sopenharmony_ci		}
264362306a36Sopenharmony_ci	},
264462306a36Sopenharmony_ci	/* SHA-256 */
264562306a36Sopenharmony_ci	{
264662306a36Sopenharmony_ci		.init = artpec6_crypto_sha256_init,
264762306a36Sopenharmony_ci		.update = artpec6_crypto_hash_update,
264862306a36Sopenharmony_ci		.final = artpec6_crypto_hash_final,
264962306a36Sopenharmony_ci		.digest = artpec6_crypto_sha256_digest,
265062306a36Sopenharmony_ci		.import = artpec6_crypto_hash_import,
265162306a36Sopenharmony_ci		.export = artpec6_crypto_hash_export,
265262306a36Sopenharmony_ci		.halg.digestsize = SHA256_DIGEST_SIZE,
265362306a36Sopenharmony_ci		.halg.statesize = sizeof(struct artpec6_hash_export_state),
265462306a36Sopenharmony_ci		.halg.base = {
265562306a36Sopenharmony_ci			.cra_name = "sha256",
265662306a36Sopenharmony_ci			.cra_driver_name = "artpec-sha256",
265762306a36Sopenharmony_ci			.cra_priority = 300,
265862306a36Sopenharmony_ci			.cra_flags = CRYPTO_ALG_ASYNC |
265962306a36Sopenharmony_ci				     CRYPTO_ALG_ALLOCATES_MEMORY,
266062306a36Sopenharmony_ci			.cra_blocksize = SHA256_BLOCK_SIZE,
266162306a36Sopenharmony_ci			.cra_ctxsize = sizeof(struct artpec6_hashalg_context),
266262306a36Sopenharmony_ci			.cra_alignmask = 3,
266362306a36Sopenharmony_ci			.cra_module = THIS_MODULE,
266462306a36Sopenharmony_ci			.cra_init = artpec6_crypto_ahash_init,
266562306a36Sopenharmony_ci			.cra_exit = artpec6_crypto_ahash_exit,
266662306a36Sopenharmony_ci		}
266762306a36Sopenharmony_ci	},
266862306a36Sopenharmony_ci	/* HMAC SHA-256 */
266962306a36Sopenharmony_ci	{
267062306a36Sopenharmony_ci		.init = artpec6_crypto_hmac_sha256_init,
267162306a36Sopenharmony_ci		.update = artpec6_crypto_hash_update,
267262306a36Sopenharmony_ci		.final = artpec6_crypto_hash_final,
267362306a36Sopenharmony_ci		.digest = artpec6_crypto_hmac_sha256_digest,
267462306a36Sopenharmony_ci		.import = artpec6_crypto_hash_import,
267562306a36Sopenharmony_ci		.export = artpec6_crypto_hash_export,
267662306a36Sopenharmony_ci		.setkey = artpec6_crypto_hash_set_key,
267762306a36Sopenharmony_ci		.halg.digestsize = SHA256_DIGEST_SIZE,
267862306a36Sopenharmony_ci		.halg.statesize = sizeof(struct artpec6_hash_export_state),
267962306a36Sopenharmony_ci		.halg.base = {
268062306a36Sopenharmony_ci			.cra_name = "hmac(sha256)",
268162306a36Sopenharmony_ci			.cra_driver_name = "artpec-hmac-sha256",
268262306a36Sopenharmony_ci			.cra_priority = 300,
268362306a36Sopenharmony_ci			.cra_flags = CRYPTO_ALG_ASYNC |
268462306a36Sopenharmony_ci				     CRYPTO_ALG_ALLOCATES_MEMORY,
268562306a36Sopenharmony_ci			.cra_blocksize = SHA256_BLOCK_SIZE,
268662306a36Sopenharmony_ci			.cra_ctxsize = sizeof(struct artpec6_hashalg_context),
268762306a36Sopenharmony_ci			.cra_alignmask = 3,
268862306a36Sopenharmony_ci			.cra_module = THIS_MODULE,
268962306a36Sopenharmony_ci			.cra_init = artpec6_crypto_ahash_init_hmac_sha256,
269062306a36Sopenharmony_ci			.cra_exit = artpec6_crypto_ahash_exit,
269162306a36Sopenharmony_ci		}
269262306a36Sopenharmony_ci	},
269362306a36Sopenharmony_ci};
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci/* Crypto */
269662306a36Sopenharmony_cistatic struct skcipher_alg crypto_algos[] = {
269762306a36Sopenharmony_ci	/* AES - ECB */
269862306a36Sopenharmony_ci	{
269962306a36Sopenharmony_ci		.base = {
270062306a36Sopenharmony_ci			.cra_name = "ecb(aes)",
270162306a36Sopenharmony_ci			.cra_driver_name = "artpec6-ecb-aes",
270262306a36Sopenharmony_ci			.cra_priority = 300,
270362306a36Sopenharmony_ci			.cra_flags = CRYPTO_ALG_ASYNC |
270462306a36Sopenharmony_ci				     CRYPTO_ALG_ALLOCATES_MEMORY,
270562306a36Sopenharmony_ci			.cra_blocksize = AES_BLOCK_SIZE,
270662306a36Sopenharmony_ci			.cra_ctxsize = sizeof(struct artpec6_cryptotfm_context),
270762306a36Sopenharmony_ci			.cra_alignmask = 3,
270862306a36Sopenharmony_ci			.cra_module = THIS_MODULE,
270962306a36Sopenharmony_ci		},
271062306a36Sopenharmony_ci		.min_keysize = AES_MIN_KEY_SIZE,
271162306a36Sopenharmony_ci		.max_keysize = AES_MAX_KEY_SIZE,
271262306a36Sopenharmony_ci		.setkey = artpec6_crypto_cipher_set_key,
271362306a36Sopenharmony_ci		.encrypt = artpec6_crypto_encrypt,
271462306a36Sopenharmony_ci		.decrypt = artpec6_crypto_decrypt,
271562306a36Sopenharmony_ci		.init = artpec6_crypto_aes_ecb_init,
271662306a36Sopenharmony_ci		.exit = artpec6_crypto_aes_exit,
271762306a36Sopenharmony_ci	},
271862306a36Sopenharmony_ci	/* AES - CTR */
271962306a36Sopenharmony_ci	{
272062306a36Sopenharmony_ci		.base = {
272162306a36Sopenharmony_ci			.cra_name = "ctr(aes)",
272262306a36Sopenharmony_ci			.cra_driver_name = "artpec6-ctr-aes",
272362306a36Sopenharmony_ci			.cra_priority = 300,
272462306a36Sopenharmony_ci			.cra_flags = CRYPTO_ALG_ASYNC |
272562306a36Sopenharmony_ci				     CRYPTO_ALG_ALLOCATES_MEMORY |
272662306a36Sopenharmony_ci				     CRYPTO_ALG_NEED_FALLBACK,
272762306a36Sopenharmony_ci			.cra_blocksize = 1,
272862306a36Sopenharmony_ci			.cra_ctxsize = sizeof(struct artpec6_cryptotfm_context),
272962306a36Sopenharmony_ci			.cra_alignmask = 3,
273062306a36Sopenharmony_ci			.cra_module = THIS_MODULE,
273162306a36Sopenharmony_ci		},
273262306a36Sopenharmony_ci		.min_keysize = AES_MIN_KEY_SIZE,
273362306a36Sopenharmony_ci		.max_keysize = AES_MAX_KEY_SIZE,
273462306a36Sopenharmony_ci		.ivsize = AES_BLOCK_SIZE,
273562306a36Sopenharmony_ci		.setkey = artpec6_crypto_cipher_set_key,
273662306a36Sopenharmony_ci		.encrypt = artpec6_crypto_ctr_encrypt,
273762306a36Sopenharmony_ci		.decrypt = artpec6_crypto_ctr_decrypt,
273862306a36Sopenharmony_ci		.init = artpec6_crypto_aes_ctr_init,
273962306a36Sopenharmony_ci		.exit = artpec6_crypto_aes_ctr_exit,
274062306a36Sopenharmony_ci	},
274162306a36Sopenharmony_ci	/* AES - CBC */
274262306a36Sopenharmony_ci	{
274362306a36Sopenharmony_ci		.base = {
274462306a36Sopenharmony_ci			.cra_name = "cbc(aes)",
274562306a36Sopenharmony_ci			.cra_driver_name = "artpec6-cbc-aes",
274662306a36Sopenharmony_ci			.cra_priority = 300,
274762306a36Sopenharmony_ci			.cra_flags = CRYPTO_ALG_ASYNC |
274862306a36Sopenharmony_ci				     CRYPTO_ALG_ALLOCATES_MEMORY,
274962306a36Sopenharmony_ci			.cra_blocksize = AES_BLOCK_SIZE,
275062306a36Sopenharmony_ci			.cra_ctxsize = sizeof(struct artpec6_cryptotfm_context),
275162306a36Sopenharmony_ci			.cra_alignmask = 3,
275262306a36Sopenharmony_ci			.cra_module = THIS_MODULE,
275362306a36Sopenharmony_ci		},
275462306a36Sopenharmony_ci		.min_keysize = AES_MIN_KEY_SIZE,
275562306a36Sopenharmony_ci		.max_keysize = AES_MAX_KEY_SIZE,
275662306a36Sopenharmony_ci		.ivsize = AES_BLOCK_SIZE,
275762306a36Sopenharmony_ci		.setkey = artpec6_crypto_cipher_set_key,
275862306a36Sopenharmony_ci		.encrypt = artpec6_crypto_encrypt,
275962306a36Sopenharmony_ci		.decrypt = artpec6_crypto_decrypt,
276062306a36Sopenharmony_ci		.init = artpec6_crypto_aes_cbc_init,
276162306a36Sopenharmony_ci		.exit = artpec6_crypto_aes_exit
276262306a36Sopenharmony_ci	},
276362306a36Sopenharmony_ci	/* AES - XTS */
276462306a36Sopenharmony_ci	{
276562306a36Sopenharmony_ci		.base = {
276662306a36Sopenharmony_ci			.cra_name = "xts(aes)",
276762306a36Sopenharmony_ci			.cra_driver_name = "artpec6-xts-aes",
276862306a36Sopenharmony_ci			.cra_priority = 300,
276962306a36Sopenharmony_ci			.cra_flags = CRYPTO_ALG_ASYNC |
277062306a36Sopenharmony_ci				     CRYPTO_ALG_ALLOCATES_MEMORY,
277162306a36Sopenharmony_ci			.cra_blocksize = 1,
277262306a36Sopenharmony_ci			.cra_ctxsize = sizeof(struct artpec6_cryptotfm_context),
277362306a36Sopenharmony_ci			.cra_alignmask = 3,
277462306a36Sopenharmony_ci			.cra_module = THIS_MODULE,
277562306a36Sopenharmony_ci		},
277662306a36Sopenharmony_ci		.min_keysize = 2*AES_MIN_KEY_SIZE,
277762306a36Sopenharmony_ci		.max_keysize = 2*AES_MAX_KEY_SIZE,
277862306a36Sopenharmony_ci		.ivsize = 16,
277962306a36Sopenharmony_ci		.setkey = artpec6_crypto_xts_set_key,
278062306a36Sopenharmony_ci		.encrypt = artpec6_crypto_encrypt,
278162306a36Sopenharmony_ci		.decrypt = artpec6_crypto_decrypt,
278262306a36Sopenharmony_ci		.init = artpec6_crypto_aes_xts_init,
278362306a36Sopenharmony_ci		.exit = artpec6_crypto_aes_exit,
278462306a36Sopenharmony_ci	},
278562306a36Sopenharmony_ci};
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_cistatic struct aead_alg aead_algos[] = {
278862306a36Sopenharmony_ci	{
278962306a36Sopenharmony_ci		.init   = artpec6_crypto_aead_init,
279062306a36Sopenharmony_ci		.setkey = artpec6_crypto_aead_set_key,
279162306a36Sopenharmony_ci		.encrypt = artpec6_crypto_aead_encrypt,
279262306a36Sopenharmony_ci		.decrypt = artpec6_crypto_aead_decrypt,
279362306a36Sopenharmony_ci		.ivsize = GCM_AES_IV_SIZE,
279462306a36Sopenharmony_ci		.maxauthsize = AES_BLOCK_SIZE,
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci		.base = {
279762306a36Sopenharmony_ci			.cra_name = "gcm(aes)",
279862306a36Sopenharmony_ci			.cra_driver_name = "artpec-gcm-aes",
279962306a36Sopenharmony_ci			.cra_priority = 300,
280062306a36Sopenharmony_ci			.cra_flags = CRYPTO_ALG_ASYNC |
280162306a36Sopenharmony_ci				     CRYPTO_ALG_ALLOCATES_MEMORY |
280262306a36Sopenharmony_ci				     CRYPTO_ALG_KERN_DRIVER_ONLY,
280362306a36Sopenharmony_ci			.cra_blocksize = 1,
280462306a36Sopenharmony_ci			.cra_ctxsize = sizeof(struct artpec6_cryptotfm_context),
280562306a36Sopenharmony_ci			.cra_alignmask = 3,
280662306a36Sopenharmony_ci			.cra_module = THIS_MODULE,
280762306a36Sopenharmony_ci		},
280862306a36Sopenharmony_ci	}
280962306a36Sopenharmony_ci};
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_cistruct dbgfs_u32 {
281462306a36Sopenharmony_ci	char *name;
281562306a36Sopenharmony_ci	mode_t mode;
281662306a36Sopenharmony_ci	u32 *flag;
281762306a36Sopenharmony_ci	char *desc;
281862306a36Sopenharmony_ci};
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_cistatic struct dentry *dbgfs_root;
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_cistatic void artpec6_crypto_init_debugfs(void)
282362306a36Sopenharmony_ci{
282462306a36Sopenharmony_ci	dbgfs_root = debugfs_create_dir("artpec6_crypto", NULL);
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION
282762306a36Sopenharmony_ci	fault_create_debugfs_attr("fail_status_read", dbgfs_root,
282862306a36Sopenharmony_ci				  &artpec6_crypto_fail_status_read);
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci	fault_create_debugfs_attr("fail_dma_array_full", dbgfs_root,
283162306a36Sopenharmony_ci				  &artpec6_crypto_fail_dma_array_full);
283262306a36Sopenharmony_ci#endif
283362306a36Sopenharmony_ci}
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_cistatic void artpec6_crypto_free_debugfs(void)
283662306a36Sopenharmony_ci{
283762306a36Sopenharmony_ci	debugfs_remove_recursive(dbgfs_root);
283862306a36Sopenharmony_ci	dbgfs_root = NULL;
283962306a36Sopenharmony_ci}
284062306a36Sopenharmony_ci#endif
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_cistatic const struct of_device_id artpec6_crypto_of_match[] = {
284362306a36Sopenharmony_ci	{ .compatible = "axis,artpec6-crypto", .data = (void *)ARTPEC6_CRYPTO },
284462306a36Sopenharmony_ci	{ .compatible = "axis,artpec7-crypto", .data = (void *)ARTPEC7_CRYPTO },
284562306a36Sopenharmony_ci	{}
284662306a36Sopenharmony_ci};
284762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, artpec6_crypto_of_match);
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_cistatic int artpec6_crypto_probe(struct platform_device *pdev)
285062306a36Sopenharmony_ci{
285162306a36Sopenharmony_ci	const struct of_device_id *match;
285262306a36Sopenharmony_ci	enum artpec6_crypto_variant variant;
285362306a36Sopenharmony_ci	struct artpec6_crypto *ac;
285462306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
285562306a36Sopenharmony_ci	void __iomem *base;
285662306a36Sopenharmony_ci	int irq;
285762306a36Sopenharmony_ci	int err;
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci	if (artpec6_crypto_dev)
286062306a36Sopenharmony_ci		return -ENODEV;
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci	match = of_match_node(artpec6_crypto_of_match, dev->of_node);
286362306a36Sopenharmony_ci	if (!match)
286462306a36Sopenharmony_ci		return -EINVAL;
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	variant = (enum artpec6_crypto_variant)match->data;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
286962306a36Sopenharmony_ci	if (IS_ERR(base))
287062306a36Sopenharmony_ci		return PTR_ERR(base);
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
287362306a36Sopenharmony_ci	if (irq < 0)
287462306a36Sopenharmony_ci		return -ENODEV;
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci	ac = devm_kzalloc(&pdev->dev, sizeof(struct artpec6_crypto),
287762306a36Sopenharmony_ci			  GFP_KERNEL);
287862306a36Sopenharmony_ci	if (!ac)
287962306a36Sopenharmony_ci		return -ENOMEM;
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	platform_set_drvdata(pdev, ac);
288262306a36Sopenharmony_ci	ac->variant = variant;
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	spin_lock_init(&ac->queue_lock);
288562306a36Sopenharmony_ci	INIT_LIST_HEAD(&ac->queue);
288662306a36Sopenharmony_ci	INIT_LIST_HEAD(&ac->pending);
288762306a36Sopenharmony_ci	timer_setup(&ac->timer, artpec6_crypto_timeout, 0);
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	ac->base = base;
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_ci	ac->dma_cache = kmem_cache_create("artpec6_crypto_dma",
289262306a36Sopenharmony_ci		sizeof(struct artpec6_crypto_dma_descriptors),
289362306a36Sopenharmony_ci		64,
289462306a36Sopenharmony_ci		0,
289562306a36Sopenharmony_ci		NULL);
289662306a36Sopenharmony_ci	if (!ac->dma_cache)
289762306a36Sopenharmony_ci		return -ENOMEM;
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
290062306a36Sopenharmony_ci	artpec6_crypto_init_debugfs();
290162306a36Sopenharmony_ci#endif
290262306a36Sopenharmony_ci
290362306a36Sopenharmony_ci	tasklet_init(&ac->task, artpec6_crypto_task,
290462306a36Sopenharmony_ci		     (unsigned long)ac);
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	ac->pad_buffer = devm_kzalloc(&pdev->dev, 2 * ARTPEC_CACHE_LINE_MAX,
290762306a36Sopenharmony_ci				      GFP_KERNEL);
290862306a36Sopenharmony_ci	if (!ac->pad_buffer)
290962306a36Sopenharmony_ci		return -ENOMEM;
291062306a36Sopenharmony_ci	ac->pad_buffer = PTR_ALIGN(ac->pad_buffer, ARTPEC_CACHE_LINE_MAX);
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	ac->zero_buffer = devm_kzalloc(&pdev->dev, 2 * ARTPEC_CACHE_LINE_MAX,
291362306a36Sopenharmony_ci				      GFP_KERNEL);
291462306a36Sopenharmony_ci	if (!ac->zero_buffer)
291562306a36Sopenharmony_ci		return -ENOMEM;
291662306a36Sopenharmony_ci	ac->zero_buffer = PTR_ALIGN(ac->zero_buffer, ARTPEC_CACHE_LINE_MAX);
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_ci	err = init_crypto_hw(ac);
291962306a36Sopenharmony_ci	if (err)
292062306a36Sopenharmony_ci		goto free_cache;
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	err = devm_request_irq(&pdev->dev, irq, artpec6_crypto_irq, 0,
292362306a36Sopenharmony_ci			       "artpec6-crypto", ac);
292462306a36Sopenharmony_ci	if (err)
292562306a36Sopenharmony_ci		goto disable_hw;
292662306a36Sopenharmony_ci
292762306a36Sopenharmony_ci	artpec6_crypto_dev = &pdev->dev;
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci	err = crypto_register_ahashes(hash_algos, ARRAY_SIZE(hash_algos));
293062306a36Sopenharmony_ci	if (err) {
293162306a36Sopenharmony_ci		dev_err(dev, "Failed to register ahashes\n");
293262306a36Sopenharmony_ci		goto disable_hw;
293362306a36Sopenharmony_ci	}
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	err = crypto_register_skciphers(crypto_algos, ARRAY_SIZE(crypto_algos));
293662306a36Sopenharmony_ci	if (err) {
293762306a36Sopenharmony_ci		dev_err(dev, "Failed to register ciphers\n");
293862306a36Sopenharmony_ci		goto unregister_ahashes;
293962306a36Sopenharmony_ci	}
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci	err = crypto_register_aeads(aead_algos, ARRAY_SIZE(aead_algos));
294262306a36Sopenharmony_ci	if (err) {
294362306a36Sopenharmony_ci		dev_err(dev, "Failed to register aeads\n");
294462306a36Sopenharmony_ci		goto unregister_algs;
294562306a36Sopenharmony_ci	}
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci	return 0;
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ciunregister_algs:
295062306a36Sopenharmony_ci	crypto_unregister_skciphers(crypto_algos, ARRAY_SIZE(crypto_algos));
295162306a36Sopenharmony_ciunregister_ahashes:
295262306a36Sopenharmony_ci	crypto_unregister_ahashes(hash_algos, ARRAY_SIZE(hash_algos));
295362306a36Sopenharmony_cidisable_hw:
295462306a36Sopenharmony_ci	artpec6_crypto_disable_hw(ac);
295562306a36Sopenharmony_cifree_cache:
295662306a36Sopenharmony_ci	kmem_cache_destroy(ac->dma_cache);
295762306a36Sopenharmony_ci	return err;
295862306a36Sopenharmony_ci}
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_cistatic int artpec6_crypto_remove(struct platform_device *pdev)
296162306a36Sopenharmony_ci{
296262306a36Sopenharmony_ci	struct artpec6_crypto *ac = platform_get_drvdata(pdev);
296362306a36Sopenharmony_ci	int irq = platform_get_irq(pdev, 0);
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_ci	crypto_unregister_ahashes(hash_algos, ARRAY_SIZE(hash_algos));
296662306a36Sopenharmony_ci	crypto_unregister_skciphers(crypto_algos, ARRAY_SIZE(crypto_algos));
296762306a36Sopenharmony_ci	crypto_unregister_aeads(aead_algos, ARRAY_SIZE(aead_algos));
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci	tasklet_disable(&ac->task);
297062306a36Sopenharmony_ci	devm_free_irq(&pdev->dev, irq, ac);
297162306a36Sopenharmony_ci	tasklet_kill(&ac->task);
297262306a36Sopenharmony_ci	del_timer_sync(&ac->timer);
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	artpec6_crypto_disable_hw(ac);
297562306a36Sopenharmony_ci
297662306a36Sopenharmony_ci	kmem_cache_destroy(ac->dma_cache);
297762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
297862306a36Sopenharmony_ci	artpec6_crypto_free_debugfs();
297962306a36Sopenharmony_ci#endif
298062306a36Sopenharmony_ci	return 0;
298162306a36Sopenharmony_ci}
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_cistatic struct platform_driver artpec6_crypto_driver = {
298462306a36Sopenharmony_ci	.probe   = artpec6_crypto_probe,
298562306a36Sopenharmony_ci	.remove  = artpec6_crypto_remove,
298662306a36Sopenharmony_ci	.driver  = {
298762306a36Sopenharmony_ci		.name  = "artpec6-crypto",
298862306a36Sopenharmony_ci		.of_match_table = artpec6_crypto_of_match,
298962306a36Sopenharmony_ci	},
299062306a36Sopenharmony_ci};
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_cimodule_platform_driver(artpec6_crypto_driver);
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ciMODULE_AUTHOR("Axis Communications AB");
299562306a36Sopenharmony_ciMODULE_DESCRIPTION("ARTPEC-6 Crypto driver");
299662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2997