162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Cryptographic API.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Support for OMAP SHA1/MD5 HW acceleration.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2010 Nokia Corporation
862306a36Sopenharmony_ci * Author: Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
962306a36Sopenharmony_ci * Copyright (c) 2011 Texas Instruments Incorporated
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Some ideas are from old omap-sha1-md5.c driver.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <crypto/engine.h>
1762306a36Sopenharmony_ci#include <crypto/hmac.h>
1862306a36Sopenharmony_ci#include <crypto/internal/hash.h>
1962306a36Sopenharmony_ci#include <crypto/scatterwalk.h>
2062306a36Sopenharmony_ci#include <crypto/sha1.h>
2162306a36Sopenharmony_ci#include <crypto/sha2.h>
2262306a36Sopenharmony_ci#include <linux/err.h>
2362306a36Sopenharmony_ci#include <linux/device.h>
2462306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2562306a36Sopenharmony_ci#include <linux/dmaengine.h>
2662306a36Sopenharmony_ci#include <linux/init.h>
2762306a36Sopenharmony_ci#include <linux/interrupt.h>
2862306a36Sopenharmony_ci#include <linux/io.h>
2962306a36Sopenharmony_ci#include <linux/irq.h>
3062306a36Sopenharmony_ci#include <linux/kernel.h>
3162306a36Sopenharmony_ci#include <linux/module.h>
3262306a36Sopenharmony_ci#include <linux/of.h>
3362306a36Sopenharmony_ci#include <linux/of_address.h>
3462306a36Sopenharmony_ci#include <linux/of_irq.h>
3562306a36Sopenharmony_ci#include <linux/platform_device.h>
3662306a36Sopenharmony_ci#include <linux/pm_runtime.h>
3762306a36Sopenharmony_ci#include <linux/scatterlist.h>
3862306a36Sopenharmony_ci#include <linux/slab.h>
3962306a36Sopenharmony_ci#include <linux/string.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define MD5_DIGEST_SIZE			16
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define SHA_REG_IDIGEST(dd, x)		((dd)->pdata->idigest_ofs + ((x)*0x04))
4462306a36Sopenharmony_ci#define SHA_REG_DIN(dd, x)		((dd)->pdata->din_ofs + ((x) * 0x04))
4562306a36Sopenharmony_ci#define SHA_REG_DIGCNT(dd)		((dd)->pdata->digcnt_ofs)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define SHA_REG_ODIGEST(dd, x)		((dd)->pdata->odigest_ofs + (x * 0x04))
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define SHA_REG_CTRL			0x18
5062306a36Sopenharmony_ci#define SHA_REG_CTRL_LENGTH		(0xFFFFFFFF << 5)
5162306a36Sopenharmony_ci#define SHA_REG_CTRL_CLOSE_HASH		(1 << 4)
5262306a36Sopenharmony_ci#define SHA_REG_CTRL_ALGO_CONST		(1 << 3)
5362306a36Sopenharmony_ci#define SHA_REG_CTRL_ALGO		(1 << 2)
5462306a36Sopenharmony_ci#define SHA_REG_CTRL_INPUT_READY	(1 << 1)
5562306a36Sopenharmony_ci#define SHA_REG_CTRL_OUTPUT_READY	(1 << 0)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define SHA_REG_REV(dd)			((dd)->pdata->rev_ofs)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define SHA_REG_MASK(dd)		((dd)->pdata->mask_ofs)
6062306a36Sopenharmony_ci#define SHA_REG_MASK_DMA_EN		(1 << 3)
6162306a36Sopenharmony_ci#define SHA_REG_MASK_IT_EN		(1 << 2)
6262306a36Sopenharmony_ci#define SHA_REG_MASK_SOFTRESET		(1 << 1)
6362306a36Sopenharmony_ci#define SHA_REG_AUTOIDLE		(1 << 0)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define SHA_REG_SYSSTATUS(dd)		((dd)->pdata->sysstatus_ofs)
6662306a36Sopenharmony_ci#define SHA_REG_SYSSTATUS_RESETDONE	(1 << 0)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define SHA_REG_MODE(dd)		((dd)->pdata->mode_ofs)
6962306a36Sopenharmony_ci#define SHA_REG_MODE_HMAC_OUTER_HASH	(1 << 7)
7062306a36Sopenharmony_ci#define SHA_REG_MODE_HMAC_KEY_PROC	(1 << 5)
7162306a36Sopenharmony_ci#define SHA_REG_MODE_CLOSE_HASH		(1 << 4)
7262306a36Sopenharmony_ci#define SHA_REG_MODE_ALGO_CONSTANT	(1 << 3)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define SHA_REG_MODE_ALGO_MASK		(7 << 0)
7562306a36Sopenharmony_ci#define SHA_REG_MODE_ALGO_MD5_128	(0 << 1)
7662306a36Sopenharmony_ci#define SHA_REG_MODE_ALGO_SHA1_160	(1 << 1)
7762306a36Sopenharmony_ci#define SHA_REG_MODE_ALGO_SHA2_224	(2 << 1)
7862306a36Sopenharmony_ci#define SHA_REG_MODE_ALGO_SHA2_256	(3 << 1)
7962306a36Sopenharmony_ci#define SHA_REG_MODE_ALGO_SHA2_384	(1 << 0)
8062306a36Sopenharmony_ci#define SHA_REG_MODE_ALGO_SHA2_512	(3 << 0)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define SHA_REG_LENGTH(dd)		((dd)->pdata->length_ofs)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci#define SHA_REG_IRQSTATUS		0x118
8562306a36Sopenharmony_ci#define SHA_REG_IRQSTATUS_CTX_RDY	(1 << 3)
8662306a36Sopenharmony_ci#define SHA_REG_IRQSTATUS_PARTHASH_RDY (1 << 2)
8762306a36Sopenharmony_ci#define SHA_REG_IRQSTATUS_INPUT_RDY	(1 << 1)
8862306a36Sopenharmony_ci#define SHA_REG_IRQSTATUS_OUTPUT_RDY	(1 << 0)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define SHA_REG_IRQENA			0x11C
9162306a36Sopenharmony_ci#define SHA_REG_IRQENA_CTX_RDY		(1 << 3)
9262306a36Sopenharmony_ci#define SHA_REG_IRQENA_PARTHASH_RDY	(1 << 2)
9362306a36Sopenharmony_ci#define SHA_REG_IRQENA_INPUT_RDY	(1 << 1)
9462306a36Sopenharmony_ci#define SHA_REG_IRQENA_OUTPUT_RDY	(1 << 0)
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define DEFAULT_TIMEOUT_INTERVAL	HZ
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define DEFAULT_AUTOSUSPEND_DELAY	1000
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* mostly device flags */
10162306a36Sopenharmony_ci#define FLAGS_FINAL		1
10262306a36Sopenharmony_ci#define FLAGS_DMA_ACTIVE	2
10362306a36Sopenharmony_ci#define FLAGS_OUTPUT_READY	3
10462306a36Sopenharmony_ci#define FLAGS_CPU		5
10562306a36Sopenharmony_ci#define FLAGS_DMA_READY		6
10662306a36Sopenharmony_ci#define FLAGS_AUTO_XOR		7
10762306a36Sopenharmony_ci#define FLAGS_BE32_SHA1		8
10862306a36Sopenharmony_ci#define FLAGS_SGS_COPIED	9
10962306a36Sopenharmony_ci#define FLAGS_SGS_ALLOCED	10
11062306a36Sopenharmony_ci#define FLAGS_HUGE		11
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/* context flags */
11362306a36Sopenharmony_ci#define FLAGS_FINUP		16
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#define FLAGS_MODE_SHIFT	18
11662306a36Sopenharmony_ci#define FLAGS_MODE_MASK		(SHA_REG_MODE_ALGO_MASK	<< FLAGS_MODE_SHIFT)
11762306a36Sopenharmony_ci#define FLAGS_MODE_MD5		(SHA_REG_MODE_ALGO_MD5_128 << FLAGS_MODE_SHIFT)
11862306a36Sopenharmony_ci#define FLAGS_MODE_SHA1		(SHA_REG_MODE_ALGO_SHA1_160 << FLAGS_MODE_SHIFT)
11962306a36Sopenharmony_ci#define FLAGS_MODE_SHA224	(SHA_REG_MODE_ALGO_SHA2_224 << FLAGS_MODE_SHIFT)
12062306a36Sopenharmony_ci#define FLAGS_MODE_SHA256	(SHA_REG_MODE_ALGO_SHA2_256 << FLAGS_MODE_SHIFT)
12162306a36Sopenharmony_ci#define FLAGS_MODE_SHA384	(SHA_REG_MODE_ALGO_SHA2_384 << FLAGS_MODE_SHIFT)
12262306a36Sopenharmony_ci#define FLAGS_MODE_SHA512	(SHA_REG_MODE_ALGO_SHA2_512 << FLAGS_MODE_SHIFT)
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define FLAGS_HMAC		21
12562306a36Sopenharmony_ci#define FLAGS_ERROR		22
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#define OP_UPDATE		1
12862306a36Sopenharmony_ci#define OP_FINAL		2
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci#define OMAP_ALIGN_MASK		(sizeof(u32)-1)
13162306a36Sopenharmony_ci#define OMAP_ALIGNED		__attribute__((aligned(sizeof(u32))))
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci#define BUFLEN			SHA512_BLOCK_SIZE
13462306a36Sopenharmony_ci#define OMAP_SHA_DMA_THRESHOLD	256
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci#define OMAP_SHA_MAX_DMA_LEN	(1024 * 2048)
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistruct omap_sham_dev;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistruct omap_sham_reqctx {
14162306a36Sopenharmony_ci	struct omap_sham_dev	*dd;
14262306a36Sopenharmony_ci	unsigned long		flags;
14362306a36Sopenharmony_ci	u8			op;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	u8			digest[SHA512_DIGEST_SIZE] OMAP_ALIGNED;
14662306a36Sopenharmony_ci	size_t			digcnt;
14762306a36Sopenharmony_ci	size_t			bufcnt;
14862306a36Sopenharmony_ci	size_t			buflen;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* walk state */
15162306a36Sopenharmony_ci	struct scatterlist	*sg;
15262306a36Sopenharmony_ci	struct scatterlist	sgl[2];
15362306a36Sopenharmony_ci	int			offset;	/* offset in current sg */
15462306a36Sopenharmony_ci	int			sg_len;
15562306a36Sopenharmony_ci	unsigned int		total;	/* total request */
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	u8			buffer[] OMAP_ALIGNED;
15862306a36Sopenharmony_ci};
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistruct omap_sham_hmac_ctx {
16162306a36Sopenharmony_ci	struct crypto_shash	*shash;
16262306a36Sopenharmony_ci	u8			ipad[SHA512_BLOCK_SIZE] OMAP_ALIGNED;
16362306a36Sopenharmony_ci	u8			opad[SHA512_BLOCK_SIZE] OMAP_ALIGNED;
16462306a36Sopenharmony_ci};
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistruct omap_sham_ctx {
16762306a36Sopenharmony_ci	unsigned long		flags;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* fallback stuff */
17062306a36Sopenharmony_ci	struct crypto_shash	*fallback;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	struct omap_sham_hmac_ctx base[];
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci#define OMAP_SHAM_QUEUE_LENGTH	10
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistruct omap_sham_algs_info {
17862306a36Sopenharmony_ci	struct ahash_engine_alg	*algs_list;
17962306a36Sopenharmony_ci	unsigned int		size;
18062306a36Sopenharmony_ci	unsigned int		registered;
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistruct omap_sham_pdata {
18462306a36Sopenharmony_ci	struct omap_sham_algs_info	*algs_info;
18562306a36Sopenharmony_ci	unsigned int	algs_info_size;
18662306a36Sopenharmony_ci	unsigned long	flags;
18762306a36Sopenharmony_ci	int		digest_size;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	void		(*copy_hash)(struct ahash_request *req, int out);
19062306a36Sopenharmony_ci	void		(*write_ctrl)(struct omap_sham_dev *dd, size_t length,
19162306a36Sopenharmony_ci				      int final, int dma);
19262306a36Sopenharmony_ci	void		(*trigger)(struct omap_sham_dev *dd, size_t length);
19362306a36Sopenharmony_ci	int		(*poll_irq)(struct omap_sham_dev *dd);
19462306a36Sopenharmony_ci	irqreturn_t	(*intr_hdlr)(int irq, void *dev_id);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	u32		odigest_ofs;
19762306a36Sopenharmony_ci	u32		idigest_ofs;
19862306a36Sopenharmony_ci	u32		din_ofs;
19962306a36Sopenharmony_ci	u32		digcnt_ofs;
20062306a36Sopenharmony_ci	u32		rev_ofs;
20162306a36Sopenharmony_ci	u32		mask_ofs;
20262306a36Sopenharmony_ci	u32		sysstatus_ofs;
20362306a36Sopenharmony_ci	u32		mode_ofs;
20462306a36Sopenharmony_ci	u32		length_ofs;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	u32		major_mask;
20762306a36Sopenharmony_ci	u32		major_shift;
20862306a36Sopenharmony_ci	u32		minor_mask;
20962306a36Sopenharmony_ci	u32		minor_shift;
21062306a36Sopenharmony_ci};
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistruct omap_sham_dev {
21362306a36Sopenharmony_ci	struct list_head	list;
21462306a36Sopenharmony_ci	unsigned long		phys_base;
21562306a36Sopenharmony_ci	struct device		*dev;
21662306a36Sopenharmony_ci	void __iomem		*io_base;
21762306a36Sopenharmony_ci	int			irq;
21862306a36Sopenharmony_ci	int			err;
21962306a36Sopenharmony_ci	struct dma_chan		*dma_lch;
22062306a36Sopenharmony_ci	struct tasklet_struct	done_task;
22162306a36Sopenharmony_ci	u8			polling_mode;
22262306a36Sopenharmony_ci	u8			xmit_buf[BUFLEN] OMAP_ALIGNED;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	unsigned long		flags;
22562306a36Sopenharmony_ci	int			fallback_sz;
22662306a36Sopenharmony_ci	struct crypto_queue	queue;
22762306a36Sopenharmony_ci	struct ahash_request	*req;
22862306a36Sopenharmony_ci	struct crypto_engine	*engine;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	const struct omap_sham_pdata	*pdata;
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistruct omap_sham_drv {
23462306a36Sopenharmony_ci	struct list_head	dev_list;
23562306a36Sopenharmony_ci	spinlock_t		lock;
23662306a36Sopenharmony_ci	unsigned long		flags;
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic struct omap_sham_drv sham = {
24062306a36Sopenharmony_ci	.dev_list = LIST_HEAD_INIT(sham.dev_list),
24162306a36Sopenharmony_ci	.lock = __SPIN_LOCK_UNLOCKED(sham.lock),
24262306a36Sopenharmony_ci};
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int omap_sham_enqueue(struct ahash_request *req, unsigned int op);
24562306a36Sopenharmony_cistatic void omap_sham_finish_req(struct ahash_request *req, int err);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic inline u32 omap_sham_read(struct omap_sham_dev *dd, u32 offset)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	return __raw_readl(dd->io_base + offset);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic inline void omap_sham_write(struct omap_sham_dev *dd,
25362306a36Sopenharmony_ci					u32 offset, u32 value)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	__raw_writel(value, dd->io_base + offset);
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic inline void omap_sham_write_mask(struct omap_sham_dev *dd, u32 address,
25962306a36Sopenharmony_ci					u32 value, u32 mask)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	u32 val;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	val = omap_sham_read(dd, address);
26462306a36Sopenharmony_ci	val &= ~mask;
26562306a36Sopenharmony_ci	val |= value;
26662306a36Sopenharmony_ci	omap_sham_write(dd, address, val);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic inline int omap_sham_wait(struct omap_sham_dev *dd, u32 offset, u32 bit)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	unsigned long timeout = jiffies + DEFAULT_TIMEOUT_INTERVAL;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	while (!(omap_sham_read(dd, offset) & bit)) {
27462306a36Sopenharmony_ci		if (time_is_before_jiffies(timeout))
27562306a36Sopenharmony_ci			return -ETIMEDOUT;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic void omap_sham_copy_hash_omap2(struct ahash_request *req, int out)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
28462306a36Sopenharmony_ci	struct omap_sham_dev *dd = ctx->dd;
28562306a36Sopenharmony_ci	u32 *hash = (u32 *)ctx->digest;
28662306a36Sopenharmony_ci	int i;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	for (i = 0; i < dd->pdata->digest_size / sizeof(u32); i++) {
28962306a36Sopenharmony_ci		if (out)
29062306a36Sopenharmony_ci			hash[i] = omap_sham_read(dd, SHA_REG_IDIGEST(dd, i));
29162306a36Sopenharmony_ci		else
29262306a36Sopenharmony_ci			omap_sham_write(dd, SHA_REG_IDIGEST(dd, i), hash[i]);
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void omap_sham_copy_hash_omap4(struct ahash_request *req, int out)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
29962306a36Sopenharmony_ci	struct omap_sham_dev *dd = ctx->dd;
30062306a36Sopenharmony_ci	int i;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (ctx->flags & BIT(FLAGS_HMAC)) {
30362306a36Sopenharmony_ci		struct crypto_ahash *tfm = crypto_ahash_reqtfm(dd->req);
30462306a36Sopenharmony_ci		struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
30562306a36Sopenharmony_ci		struct omap_sham_hmac_ctx *bctx = tctx->base;
30662306a36Sopenharmony_ci		u32 *opad = (u32 *)bctx->opad;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci		for (i = 0; i < dd->pdata->digest_size / sizeof(u32); i++) {
30962306a36Sopenharmony_ci			if (out)
31062306a36Sopenharmony_ci				opad[i] = omap_sham_read(dd,
31162306a36Sopenharmony_ci						SHA_REG_ODIGEST(dd, i));
31262306a36Sopenharmony_ci			else
31362306a36Sopenharmony_ci				omap_sham_write(dd, SHA_REG_ODIGEST(dd, i),
31462306a36Sopenharmony_ci						opad[i]);
31562306a36Sopenharmony_ci		}
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	omap_sham_copy_hash_omap2(req, out);
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic void omap_sham_copy_ready_hash(struct ahash_request *req)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
32462306a36Sopenharmony_ci	u32 *in = (u32 *)ctx->digest;
32562306a36Sopenharmony_ci	u32 *hash = (u32 *)req->result;
32662306a36Sopenharmony_ci	int i, d, big_endian = 0;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (!hash)
32962306a36Sopenharmony_ci		return;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	switch (ctx->flags & FLAGS_MODE_MASK) {
33262306a36Sopenharmony_ci	case FLAGS_MODE_MD5:
33362306a36Sopenharmony_ci		d = MD5_DIGEST_SIZE / sizeof(u32);
33462306a36Sopenharmony_ci		break;
33562306a36Sopenharmony_ci	case FLAGS_MODE_SHA1:
33662306a36Sopenharmony_ci		/* OMAP2 SHA1 is big endian */
33762306a36Sopenharmony_ci		if (test_bit(FLAGS_BE32_SHA1, &ctx->dd->flags))
33862306a36Sopenharmony_ci			big_endian = 1;
33962306a36Sopenharmony_ci		d = SHA1_DIGEST_SIZE / sizeof(u32);
34062306a36Sopenharmony_ci		break;
34162306a36Sopenharmony_ci	case FLAGS_MODE_SHA224:
34262306a36Sopenharmony_ci		d = SHA224_DIGEST_SIZE / sizeof(u32);
34362306a36Sopenharmony_ci		break;
34462306a36Sopenharmony_ci	case FLAGS_MODE_SHA256:
34562306a36Sopenharmony_ci		d = SHA256_DIGEST_SIZE / sizeof(u32);
34662306a36Sopenharmony_ci		break;
34762306a36Sopenharmony_ci	case FLAGS_MODE_SHA384:
34862306a36Sopenharmony_ci		d = SHA384_DIGEST_SIZE / sizeof(u32);
34962306a36Sopenharmony_ci		break;
35062306a36Sopenharmony_ci	case FLAGS_MODE_SHA512:
35162306a36Sopenharmony_ci		d = SHA512_DIGEST_SIZE / sizeof(u32);
35262306a36Sopenharmony_ci		break;
35362306a36Sopenharmony_ci	default:
35462306a36Sopenharmony_ci		d = 0;
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (big_endian)
35862306a36Sopenharmony_ci		for (i = 0; i < d; i++)
35962306a36Sopenharmony_ci			hash[i] = be32_to_cpup((__be32 *)in + i);
36062306a36Sopenharmony_ci	else
36162306a36Sopenharmony_ci		for (i = 0; i < d; i++)
36262306a36Sopenharmony_ci			hash[i] = le32_to_cpup((__le32 *)in + i);
36362306a36Sopenharmony_ci}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic void omap_sham_write_ctrl_omap2(struct omap_sham_dev *dd, size_t length,
36662306a36Sopenharmony_ci				 int final, int dma)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
36962306a36Sopenharmony_ci	u32 val = length << 5, mask;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (likely(ctx->digcnt))
37262306a36Sopenharmony_ci		omap_sham_write(dd, SHA_REG_DIGCNT(dd), ctx->digcnt);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	omap_sham_write_mask(dd, SHA_REG_MASK(dd),
37562306a36Sopenharmony_ci		SHA_REG_MASK_IT_EN | (dma ? SHA_REG_MASK_DMA_EN : 0),
37662306a36Sopenharmony_ci		SHA_REG_MASK_IT_EN | SHA_REG_MASK_DMA_EN);
37762306a36Sopenharmony_ci	/*
37862306a36Sopenharmony_ci	 * Setting ALGO_CONST only for the first iteration
37962306a36Sopenharmony_ci	 * and CLOSE_HASH only for the last one.
38062306a36Sopenharmony_ci	 */
38162306a36Sopenharmony_ci	if ((ctx->flags & FLAGS_MODE_MASK) == FLAGS_MODE_SHA1)
38262306a36Sopenharmony_ci		val |= SHA_REG_CTRL_ALGO;
38362306a36Sopenharmony_ci	if (!ctx->digcnt)
38462306a36Sopenharmony_ci		val |= SHA_REG_CTRL_ALGO_CONST;
38562306a36Sopenharmony_ci	if (final)
38662306a36Sopenharmony_ci		val |= SHA_REG_CTRL_CLOSE_HASH;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	mask = SHA_REG_CTRL_ALGO_CONST | SHA_REG_CTRL_CLOSE_HASH |
38962306a36Sopenharmony_ci			SHA_REG_CTRL_ALGO | SHA_REG_CTRL_LENGTH;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	omap_sham_write_mask(dd, SHA_REG_CTRL, val, mask);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic void omap_sham_trigger_omap2(struct omap_sham_dev *dd, size_t length)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic int omap_sham_poll_irq_omap2(struct omap_sham_dev *dd)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	return omap_sham_wait(dd, SHA_REG_CTRL, SHA_REG_CTRL_INPUT_READY);
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int get_block_size(struct omap_sham_reqctx *ctx)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	int d;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	switch (ctx->flags & FLAGS_MODE_MASK) {
40862306a36Sopenharmony_ci	case FLAGS_MODE_MD5:
40962306a36Sopenharmony_ci	case FLAGS_MODE_SHA1:
41062306a36Sopenharmony_ci		d = SHA1_BLOCK_SIZE;
41162306a36Sopenharmony_ci		break;
41262306a36Sopenharmony_ci	case FLAGS_MODE_SHA224:
41362306a36Sopenharmony_ci	case FLAGS_MODE_SHA256:
41462306a36Sopenharmony_ci		d = SHA256_BLOCK_SIZE;
41562306a36Sopenharmony_ci		break;
41662306a36Sopenharmony_ci	case FLAGS_MODE_SHA384:
41762306a36Sopenharmony_ci	case FLAGS_MODE_SHA512:
41862306a36Sopenharmony_ci		d = SHA512_BLOCK_SIZE;
41962306a36Sopenharmony_ci		break;
42062306a36Sopenharmony_ci	default:
42162306a36Sopenharmony_ci		d = 0;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return d;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic void omap_sham_write_n(struct omap_sham_dev *dd, u32 offset,
42862306a36Sopenharmony_ci				    u32 *value, int count)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	for (; count--; value++, offset += 4)
43162306a36Sopenharmony_ci		omap_sham_write(dd, offset, *value);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic void omap_sham_write_ctrl_omap4(struct omap_sham_dev *dd, size_t length,
43562306a36Sopenharmony_ci				 int final, int dma)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
43862306a36Sopenharmony_ci	u32 val, mask;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	if (likely(ctx->digcnt))
44162306a36Sopenharmony_ci		omap_sham_write(dd, SHA_REG_DIGCNT(dd), ctx->digcnt);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	/*
44462306a36Sopenharmony_ci	 * Setting ALGO_CONST only for the first iteration and
44562306a36Sopenharmony_ci	 * CLOSE_HASH only for the last one. Note that flags mode bits
44662306a36Sopenharmony_ci	 * correspond to algorithm encoding in mode register.
44762306a36Sopenharmony_ci	 */
44862306a36Sopenharmony_ci	val = (ctx->flags & FLAGS_MODE_MASK) >> (FLAGS_MODE_SHIFT);
44962306a36Sopenharmony_ci	if (!ctx->digcnt) {
45062306a36Sopenharmony_ci		struct crypto_ahash *tfm = crypto_ahash_reqtfm(dd->req);
45162306a36Sopenharmony_ci		struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
45262306a36Sopenharmony_ci		struct omap_sham_hmac_ctx *bctx = tctx->base;
45362306a36Sopenharmony_ci		int bs, nr_dr;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		val |= SHA_REG_MODE_ALGO_CONSTANT;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		if (ctx->flags & BIT(FLAGS_HMAC)) {
45862306a36Sopenharmony_ci			bs = get_block_size(ctx);
45962306a36Sopenharmony_ci			nr_dr = bs / (2 * sizeof(u32));
46062306a36Sopenharmony_ci			val |= SHA_REG_MODE_HMAC_KEY_PROC;
46162306a36Sopenharmony_ci			omap_sham_write_n(dd, SHA_REG_ODIGEST(dd, 0),
46262306a36Sopenharmony_ci					  (u32 *)bctx->ipad, nr_dr);
46362306a36Sopenharmony_ci			omap_sham_write_n(dd, SHA_REG_IDIGEST(dd, 0),
46462306a36Sopenharmony_ci					  (u32 *)bctx->ipad + nr_dr, nr_dr);
46562306a36Sopenharmony_ci			ctx->digcnt += bs;
46662306a36Sopenharmony_ci		}
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (final) {
47062306a36Sopenharmony_ci		val |= SHA_REG_MODE_CLOSE_HASH;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		if (ctx->flags & BIT(FLAGS_HMAC))
47362306a36Sopenharmony_ci			val |= SHA_REG_MODE_HMAC_OUTER_HASH;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	mask = SHA_REG_MODE_ALGO_CONSTANT | SHA_REG_MODE_CLOSE_HASH |
47762306a36Sopenharmony_ci	       SHA_REG_MODE_ALGO_MASK | SHA_REG_MODE_HMAC_OUTER_HASH |
47862306a36Sopenharmony_ci	       SHA_REG_MODE_HMAC_KEY_PROC;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	dev_dbg(dd->dev, "ctrl: %08x, flags: %08lx\n", val, ctx->flags);
48162306a36Sopenharmony_ci	omap_sham_write_mask(dd, SHA_REG_MODE(dd), val, mask);
48262306a36Sopenharmony_ci	omap_sham_write(dd, SHA_REG_IRQENA, SHA_REG_IRQENA_OUTPUT_RDY);
48362306a36Sopenharmony_ci	omap_sham_write_mask(dd, SHA_REG_MASK(dd),
48462306a36Sopenharmony_ci			     SHA_REG_MASK_IT_EN |
48562306a36Sopenharmony_ci				     (dma ? SHA_REG_MASK_DMA_EN : 0),
48662306a36Sopenharmony_ci			     SHA_REG_MASK_IT_EN | SHA_REG_MASK_DMA_EN);
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic void omap_sham_trigger_omap4(struct omap_sham_dev *dd, size_t length)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	omap_sham_write(dd, SHA_REG_LENGTH(dd), length);
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic int omap_sham_poll_irq_omap4(struct omap_sham_dev *dd)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	return omap_sham_wait(dd, SHA_REG_IRQSTATUS,
49762306a36Sopenharmony_ci			      SHA_REG_IRQSTATUS_INPUT_RDY);
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic int omap_sham_xmit_cpu(struct omap_sham_dev *dd, size_t length,
50162306a36Sopenharmony_ci			      int final)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
50462306a36Sopenharmony_ci	int count, len32, bs32, offset = 0;
50562306a36Sopenharmony_ci	const u32 *buffer;
50662306a36Sopenharmony_ci	int mlen;
50762306a36Sopenharmony_ci	struct sg_mapping_iter mi;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	dev_dbg(dd->dev, "xmit_cpu: digcnt: %zd, length: %zd, final: %d\n",
51062306a36Sopenharmony_ci						ctx->digcnt, length, final);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	dd->pdata->write_ctrl(dd, length, final, 0);
51362306a36Sopenharmony_ci	dd->pdata->trigger(dd, length);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	/* should be non-zero before next lines to disable clocks later */
51662306a36Sopenharmony_ci	ctx->digcnt += length;
51762306a36Sopenharmony_ci	ctx->total -= length;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (final)
52062306a36Sopenharmony_ci		set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	set_bit(FLAGS_CPU, &dd->flags);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	len32 = DIV_ROUND_UP(length, sizeof(u32));
52562306a36Sopenharmony_ci	bs32 = get_block_size(ctx) / sizeof(u32);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	sg_miter_start(&mi, ctx->sg, ctx->sg_len,
52862306a36Sopenharmony_ci		       SG_MITER_FROM_SG | SG_MITER_ATOMIC);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	mlen = 0;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	while (len32) {
53362306a36Sopenharmony_ci		if (dd->pdata->poll_irq(dd))
53462306a36Sopenharmony_ci			return -ETIMEDOUT;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		for (count = 0; count < min(len32, bs32); count++, offset++) {
53762306a36Sopenharmony_ci			if (!mlen) {
53862306a36Sopenharmony_ci				sg_miter_next(&mi);
53962306a36Sopenharmony_ci				mlen = mi.length;
54062306a36Sopenharmony_ci				if (!mlen) {
54162306a36Sopenharmony_ci					pr_err("sg miter failure.\n");
54262306a36Sopenharmony_ci					return -EINVAL;
54362306a36Sopenharmony_ci				}
54462306a36Sopenharmony_ci				offset = 0;
54562306a36Sopenharmony_ci				buffer = mi.addr;
54662306a36Sopenharmony_ci			}
54762306a36Sopenharmony_ci			omap_sham_write(dd, SHA_REG_DIN(dd, count),
54862306a36Sopenharmony_ci					buffer[offset]);
54962306a36Sopenharmony_ci			mlen -= 4;
55062306a36Sopenharmony_ci		}
55162306a36Sopenharmony_ci		len32 -= min(len32, bs32);
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	sg_miter_stop(&mi);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	return -EINPROGRESS;
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic void omap_sham_dma_callback(void *param)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct omap_sham_dev *dd = param;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	set_bit(FLAGS_DMA_READY, &dd->flags);
56462306a36Sopenharmony_ci	tasklet_schedule(&dd->done_task);
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic int omap_sham_xmit_dma(struct omap_sham_dev *dd, size_t length,
56862306a36Sopenharmony_ci			      int final)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
57162306a36Sopenharmony_ci	struct dma_async_tx_descriptor *tx;
57262306a36Sopenharmony_ci	struct dma_slave_config cfg;
57362306a36Sopenharmony_ci	int ret;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	dev_dbg(dd->dev, "xmit_dma: digcnt: %zd, length: %zd, final: %d\n",
57662306a36Sopenharmony_ci						ctx->digcnt, length, final);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	if (!dma_map_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE)) {
57962306a36Sopenharmony_ci		dev_err(dd->dev, "dma_map_sg error\n");
58062306a36Sopenharmony_ci		return -EINVAL;
58162306a36Sopenharmony_ci	}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	memset(&cfg, 0, sizeof(cfg));
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	cfg.dst_addr = dd->phys_base + SHA_REG_DIN(dd, 0);
58662306a36Sopenharmony_ci	cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
58762306a36Sopenharmony_ci	cfg.dst_maxburst = get_block_size(ctx) / DMA_SLAVE_BUSWIDTH_4_BYTES;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	ret = dmaengine_slave_config(dd->dma_lch, &cfg);
59062306a36Sopenharmony_ci	if (ret) {
59162306a36Sopenharmony_ci		pr_err("omap-sham: can't configure dmaengine slave: %d\n", ret);
59262306a36Sopenharmony_ci		return ret;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	tx = dmaengine_prep_slave_sg(dd->dma_lch, ctx->sg, ctx->sg_len,
59662306a36Sopenharmony_ci				     DMA_MEM_TO_DEV,
59762306a36Sopenharmony_ci				     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	if (!tx) {
60062306a36Sopenharmony_ci		dev_err(dd->dev, "prep_slave_sg failed\n");
60162306a36Sopenharmony_ci		return -EINVAL;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	tx->callback = omap_sham_dma_callback;
60562306a36Sopenharmony_ci	tx->callback_param = dd;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	dd->pdata->write_ctrl(dd, length, final, 1);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	ctx->digcnt += length;
61062306a36Sopenharmony_ci	ctx->total -= length;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	if (final)
61362306a36Sopenharmony_ci		set_bit(FLAGS_FINAL, &dd->flags); /* catch last interrupt */
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	set_bit(FLAGS_DMA_ACTIVE, &dd->flags);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	dmaengine_submit(tx);
61862306a36Sopenharmony_ci	dma_async_issue_pending(dd->dma_lch);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	dd->pdata->trigger(dd, length);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	return -EINPROGRESS;
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic int omap_sham_copy_sg_lists(struct omap_sham_reqctx *ctx,
62662306a36Sopenharmony_ci				   struct scatterlist *sg, int bs, int new_len)
62762306a36Sopenharmony_ci{
62862306a36Sopenharmony_ci	int n = sg_nents(sg);
62962306a36Sopenharmony_ci	struct scatterlist *tmp;
63062306a36Sopenharmony_ci	int offset = ctx->offset;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	ctx->total = new_len;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (ctx->bufcnt)
63562306a36Sopenharmony_ci		n++;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	ctx->sg = kmalloc_array(n, sizeof(*sg), GFP_KERNEL);
63862306a36Sopenharmony_ci	if (!ctx->sg)
63962306a36Sopenharmony_ci		return -ENOMEM;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	sg_init_table(ctx->sg, n);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	tmp = ctx->sg;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	ctx->sg_len = 0;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	if (ctx->bufcnt) {
64862306a36Sopenharmony_ci		sg_set_buf(tmp, ctx->dd->xmit_buf, ctx->bufcnt);
64962306a36Sopenharmony_ci		tmp = sg_next(tmp);
65062306a36Sopenharmony_ci		ctx->sg_len++;
65162306a36Sopenharmony_ci		new_len -= ctx->bufcnt;
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	while (sg && new_len) {
65562306a36Sopenharmony_ci		int len = sg->length - offset;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci		if (len <= 0) {
65862306a36Sopenharmony_ci			offset -= sg->length;
65962306a36Sopenharmony_ci			sg = sg_next(sg);
66062306a36Sopenharmony_ci			continue;
66162306a36Sopenharmony_ci		}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci		if (new_len < len)
66462306a36Sopenharmony_ci			len = new_len;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		if (len > 0) {
66762306a36Sopenharmony_ci			new_len -= len;
66862306a36Sopenharmony_ci			sg_set_page(tmp, sg_page(sg), len, sg->offset + offset);
66962306a36Sopenharmony_ci			offset = 0;
67062306a36Sopenharmony_ci			ctx->offset = 0;
67162306a36Sopenharmony_ci			ctx->sg_len++;
67262306a36Sopenharmony_ci			if (new_len <= 0)
67362306a36Sopenharmony_ci				break;
67462306a36Sopenharmony_ci			tmp = sg_next(tmp);
67562306a36Sopenharmony_ci		}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci		sg = sg_next(sg);
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (tmp)
68162306a36Sopenharmony_ci		sg_mark_end(tmp);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	set_bit(FLAGS_SGS_ALLOCED, &ctx->dd->flags);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	ctx->offset += new_len - ctx->bufcnt;
68662306a36Sopenharmony_ci	ctx->bufcnt = 0;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	return 0;
68962306a36Sopenharmony_ci}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic int omap_sham_copy_sgs(struct omap_sham_reqctx *ctx,
69262306a36Sopenharmony_ci			      struct scatterlist *sg, int bs,
69362306a36Sopenharmony_ci			      unsigned int new_len)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	int pages;
69662306a36Sopenharmony_ci	void *buf;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	pages = get_order(new_len);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	buf = (void *)__get_free_pages(GFP_ATOMIC, pages);
70162306a36Sopenharmony_ci	if (!buf) {
70262306a36Sopenharmony_ci		pr_err("Couldn't allocate pages for unaligned cases.\n");
70362306a36Sopenharmony_ci		return -ENOMEM;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if (ctx->bufcnt)
70762306a36Sopenharmony_ci		memcpy(buf, ctx->dd->xmit_buf, ctx->bufcnt);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	scatterwalk_map_and_copy(buf + ctx->bufcnt, sg, ctx->offset,
71062306a36Sopenharmony_ci				 min(new_len, ctx->total) - ctx->bufcnt, 0);
71162306a36Sopenharmony_ci	sg_init_table(ctx->sgl, 1);
71262306a36Sopenharmony_ci	sg_set_buf(ctx->sgl, buf, new_len);
71362306a36Sopenharmony_ci	ctx->sg = ctx->sgl;
71462306a36Sopenharmony_ci	set_bit(FLAGS_SGS_COPIED, &ctx->dd->flags);
71562306a36Sopenharmony_ci	ctx->sg_len = 1;
71662306a36Sopenharmony_ci	ctx->offset += new_len - ctx->bufcnt;
71762306a36Sopenharmony_ci	ctx->bufcnt = 0;
71862306a36Sopenharmony_ci	ctx->total = new_len;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return 0;
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic int omap_sham_align_sgs(struct scatterlist *sg,
72462306a36Sopenharmony_ci			       int nbytes, int bs, bool final,
72562306a36Sopenharmony_ci			       struct omap_sham_reqctx *rctx)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	int n = 0;
72862306a36Sopenharmony_ci	bool aligned = true;
72962306a36Sopenharmony_ci	bool list_ok = true;
73062306a36Sopenharmony_ci	struct scatterlist *sg_tmp = sg;
73162306a36Sopenharmony_ci	int new_len;
73262306a36Sopenharmony_ci	int offset = rctx->offset;
73362306a36Sopenharmony_ci	int bufcnt = rctx->bufcnt;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	if (!sg || !sg->length || !nbytes) {
73662306a36Sopenharmony_ci		if (bufcnt) {
73762306a36Sopenharmony_ci			bufcnt = DIV_ROUND_UP(bufcnt, bs) * bs;
73862306a36Sopenharmony_ci			sg_init_table(rctx->sgl, 1);
73962306a36Sopenharmony_ci			sg_set_buf(rctx->sgl, rctx->dd->xmit_buf, bufcnt);
74062306a36Sopenharmony_ci			rctx->sg = rctx->sgl;
74162306a36Sopenharmony_ci			rctx->sg_len = 1;
74262306a36Sopenharmony_ci		}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci		return 0;
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	new_len = nbytes;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	if (offset)
75062306a36Sopenharmony_ci		list_ok = false;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	if (final)
75362306a36Sopenharmony_ci		new_len = DIV_ROUND_UP(new_len, bs) * bs;
75462306a36Sopenharmony_ci	else
75562306a36Sopenharmony_ci		new_len = (new_len - 1) / bs * bs;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (!new_len)
75862306a36Sopenharmony_ci		return 0;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (nbytes != new_len)
76162306a36Sopenharmony_ci		list_ok = false;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	while (nbytes > 0 && sg_tmp) {
76462306a36Sopenharmony_ci		n++;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci		if (bufcnt) {
76762306a36Sopenharmony_ci			if (!IS_ALIGNED(bufcnt, bs)) {
76862306a36Sopenharmony_ci				aligned = false;
76962306a36Sopenharmony_ci				break;
77062306a36Sopenharmony_ci			}
77162306a36Sopenharmony_ci			nbytes -= bufcnt;
77262306a36Sopenharmony_ci			bufcnt = 0;
77362306a36Sopenharmony_ci			if (!nbytes)
77462306a36Sopenharmony_ci				list_ok = false;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci			continue;
77762306a36Sopenharmony_ci		}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci#ifdef CONFIG_ZONE_DMA
78062306a36Sopenharmony_ci		if (page_zonenum(sg_page(sg_tmp)) != ZONE_DMA) {
78162306a36Sopenharmony_ci			aligned = false;
78262306a36Sopenharmony_ci			break;
78362306a36Sopenharmony_ci		}
78462306a36Sopenharmony_ci#endif
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		if (offset < sg_tmp->length) {
78762306a36Sopenharmony_ci			if (!IS_ALIGNED(offset + sg_tmp->offset, 4)) {
78862306a36Sopenharmony_ci				aligned = false;
78962306a36Sopenharmony_ci				break;
79062306a36Sopenharmony_ci			}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci			if (!IS_ALIGNED(sg_tmp->length - offset, bs)) {
79362306a36Sopenharmony_ci				aligned = false;
79462306a36Sopenharmony_ci				break;
79562306a36Sopenharmony_ci			}
79662306a36Sopenharmony_ci		}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci		if (offset) {
79962306a36Sopenharmony_ci			offset -= sg_tmp->length;
80062306a36Sopenharmony_ci			if (offset < 0) {
80162306a36Sopenharmony_ci				nbytes += offset;
80262306a36Sopenharmony_ci				offset = 0;
80362306a36Sopenharmony_ci			}
80462306a36Sopenharmony_ci		} else {
80562306a36Sopenharmony_ci			nbytes -= sg_tmp->length;
80662306a36Sopenharmony_ci		}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci		sg_tmp = sg_next(sg_tmp);
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci		if (nbytes < 0) {
81162306a36Sopenharmony_ci			list_ok = false;
81262306a36Sopenharmony_ci			break;
81362306a36Sopenharmony_ci		}
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	if (new_len > OMAP_SHA_MAX_DMA_LEN) {
81762306a36Sopenharmony_ci		new_len = OMAP_SHA_MAX_DMA_LEN;
81862306a36Sopenharmony_ci		aligned = false;
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	if (!aligned)
82262306a36Sopenharmony_ci		return omap_sham_copy_sgs(rctx, sg, bs, new_len);
82362306a36Sopenharmony_ci	else if (!list_ok)
82462306a36Sopenharmony_ci		return omap_sham_copy_sg_lists(rctx, sg, bs, new_len);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	rctx->total = new_len;
82762306a36Sopenharmony_ci	rctx->offset += new_len;
82862306a36Sopenharmony_ci	rctx->sg_len = n;
82962306a36Sopenharmony_ci	if (rctx->bufcnt) {
83062306a36Sopenharmony_ci		sg_init_table(rctx->sgl, 2);
83162306a36Sopenharmony_ci		sg_set_buf(rctx->sgl, rctx->dd->xmit_buf, rctx->bufcnt);
83262306a36Sopenharmony_ci		sg_chain(rctx->sgl, 2, sg);
83362306a36Sopenharmony_ci		rctx->sg = rctx->sgl;
83462306a36Sopenharmony_ci	} else {
83562306a36Sopenharmony_ci		rctx->sg = sg;
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	return 0;
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic int omap_sham_prepare_request(struct crypto_engine *engine, void *areq)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	struct ahash_request *req = container_of(areq, struct ahash_request,
84462306a36Sopenharmony_ci						 base);
84562306a36Sopenharmony_ci	struct omap_sham_reqctx *rctx = ahash_request_ctx(req);
84662306a36Sopenharmony_ci	int bs;
84762306a36Sopenharmony_ci	int ret;
84862306a36Sopenharmony_ci	unsigned int nbytes;
84962306a36Sopenharmony_ci	bool final = rctx->flags & BIT(FLAGS_FINUP);
85062306a36Sopenharmony_ci	bool update = rctx->op == OP_UPDATE;
85162306a36Sopenharmony_ci	int hash_later;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	bs = get_block_size(rctx);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	nbytes = rctx->bufcnt;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	if (update)
85862306a36Sopenharmony_ci		nbytes += req->nbytes - rctx->offset;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	dev_dbg(rctx->dd->dev,
86162306a36Sopenharmony_ci		"%s: nbytes=%d, bs=%d, total=%d, offset=%d, bufcnt=%zd\n",
86262306a36Sopenharmony_ci		__func__, nbytes, bs, rctx->total, rctx->offset,
86362306a36Sopenharmony_ci		rctx->bufcnt);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	if (!nbytes)
86662306a36Sopenharmony_ci		return 0;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	rctx->total = nbytes;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	if (update && req->nbytes && (!IS_ALIGNED(rctx->bufcnt, bs))) {
87162306a36Sopenharmony_ci		int len = bs - rctx->bufcnt % bs;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci		if (len > req->nbytes)
87462306a36Sopenharmony_ci			len = req->nbytes;
87562306a36Sopenharmony_ci		scatterwalk_map_and_copy(rctx->buffer + rctx->bufcnt, req->src,
87662306a36Sopenharmony_ci					 0, len, 0);
87762306a36Sopenharmony_ci		rctx->bufcnt += len;
87862306a36Sopenharmony_ci		rctx->offset = len;
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	if (rctx->bufcnt)
88262306a36Sopenharmony_ci		memcpy(rctx->dd->xmit_buf, rctx->buffer, rctx->bufcnt);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	ret = omap_sham_align_sgs(req->src, nbytes, bs, final, rctx);
88562306a36Sopenharmony_ci	if (ret)
88662306a36Sopenharmony_ci		return ret;
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	hash_later = nbytes - rctx->total;
88962306a36Sopenharmony_ci	if (hash_later < 0)
89062306a36Sopenharmony_ci		hash_later = 0;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	if (hash_later && hash_later <= rctx->buflen) {
89362306a36Sopenharmony_ci		scatterwalk_map_and_copy(rctx->buffer,
89462306a36Sopenharmony_ci					 req->src,
89562306a36Sopenharmony_ci					 req->nbytes - hash_later,
89662306a36Sopenharmony_ci					 hash_later, 0);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci		rctx->bufcnt = hash_later;
89962306a36Sopenharmony_ci	} else {
90062306a36Sopenharmony_ci		rctx->bufcnt = 0;
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	if (hash_later > rctx->buflen)
90462306a36Sopenharmony_ci		set_bit(FLAGS_HUGE, &rctx->dd->flags);
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	rctx->total = min(nbytes, rctx->total);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	return 0;
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic int omap_sham_update_dma_stop(struct omap_sham_dev *dd)
91262306a36Sopenharmony_ci{
91362306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(dd->req);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	dma_unmap_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE);
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	clear_bit(FLAGS_DMA_ACTIVE, &dd->flags);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	return 0;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic struct omap_sham_dev *omap_sham_find_dev(struct omap_sham_reqctx *ctx)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	struct omap_sham_dev *dd;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	if (ctx->dd)
92762306a36Sopenharmony_ci		return ctx->dd;
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	spin_lock_bh(&sham.lock);
93062306a36Sopenharmony_ci	dd = list_first_entry(&sham.dev_list, struct omap_sham_dev, list);
93162306a36Sopenharmony_ci	list_move_tail(&dd->list, &sham.dev_list);
93262306a36Sopenharmony_ci	ctx->dd = dd;
93362306a36Sopenharmony_ci	spin_unlock_bh(&sham.lock);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	return dd;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic int omap_sham_init(struct ahash_request *req)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
94162306a36Sopenharmony_ci	struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
94262306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
94362306a36Sopenharmony_ci	struct omap_sham_dev *dd;
94462306a36Sopenharmony_ci	int bs = 0;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	ctx->dd = NULL;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	dd = omap_sham_find_dev(ctx);
94962306a36Sopenharmony_ci	if (!dd)
95062306a36Sopenharmony_ci		return -ENODEV;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	ctx->flags = 0;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	dev_dbg(dd->dev, "init: digest size: %d\n",
95562306a36Sopenharmony_ci		crypto_ahash_digestsize(tfm));
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	switch (crypto_ahash_digestsize(tfm)) {
95862306a36Sopenharmony_ci	case MD5_DIGEST_SIZE:
95962306a36Sopenharmony_ci		ctx->flags |= FLAGS_MODE_MD5;
96062306a36Sopenharmony_ci		bs = SHA1_BLOCK_SIZE;
96162306a36Sopenharmony_ci		break;
96262306a36Sopenharmony_ci	case SHA1_DIGEST_SIZE:
96362306a36Sopenharmony_ci		ctx->flags |= FLAGS_MODE_SHA1;
96462306a36Sopenharmony_ci		bs = SHA1_BLOCK_SIZE;
96562306a36Sopenharmony_ci		break;
96662306a36Sopenharmony_ci	case SHA224_DIGEST_SIZE:
96762306a36Sopenharmony_ci		ctx->flags |= FLAGS_MODE_SHA224;
96862306a36Sopenharmony_ci		bs = SHA224_BLOCK_SIZE;
96962306a36Sopenharmony_ci		break;
97062306a36Sopenharmony_ci	case SHA256_DIGEST_SIZE:
97162306a36Sopenharmony_ci		ctx->flags |= FLAGS_MODE_SHA256;
97262306a36Sopenharmony_ci		bs = SHA256_BLOCK_SIZE;
97362306a36Sopenharmony_ci		break;
97462306a36Sopenharmony_ci	case SHA384_DIGEST_SIZE:
97562306a36Sopenharmony_ci		ctx->flags |= FLAGS_MODE_SHA384;
97662306a36Sopenharmony_ci		bs = SHA384_BLOCK_SIZE;
97762306a36Sopenharmony_ci		break;
97862306a36Sopenharmony_ci	case SHA512_DIGEST_SIZE:
97962306a36Sopenharmony_ci		ctx->flags |= FLAGS_MODE_SHA512;
98062306a36Sopenharmony_ci		bs = SHA512_BLOCK_SIZE;
98162306a36Sopenharmony_ci		break;
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	ctx->bufcnt = 0;
98562306a36Sopenharmony_ci	ctx->digcnt = 0;
98662306a36Sopenharmony_ci	ctx->total = 0;
98762306a36Sopenharmony_ci	ctx->offset = 0;
98862306a36Sopenharmony_ci	ctx->buflen = BUFLEN;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (tctx->flags & BIT(FLAGS_HMAC)) {
99162306a36Sopenharmony_ci		if (!test_bit(FLAGS_AUTO_XOR, &dd->flags)) {
99262306a36Sopenharmony_ci			struct omap_sham_hmac_ctx *bctx = tctx->base;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci			memcpy(ctx->buffer, bctx->ipad, bs);
99562306a36Sopenharmony_ci			ctx->bufcnt = bs;
99662306a36Sopenharmony_ci		}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci		ctx->flags |= BIT(FLAGS_HMAC);
99962306a36Sopenharmony_ci	}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	return 0;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_cistatic int omap_sham_update_req(struct omap_sham_dev *dd)
100662306a36Sopenharmony_ci{
100762306a36Sopenharmony_ci	struct ahash_request *req = dd->req;
100862306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
100962306a36Sopenharmony_ci	int err;
101062306a36Sopenharmony_ci	bool final = (ctx->flags & BIT(FLAGS_FINUP)) &&
101162306a36Sopenharmony_ci		!(dd->flags & BIT(FLAGS_HUGE));
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	dev_dbg(dd->dev, "update_req: total: %u, digcnt: %zd, final: %d",
101462306a36Sopenharmony_ci		ctx->total, ctx->digcnt, final);
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	if (ctx->total < get_block_size(ctx) ||
101762306a36Sopenharmony_ci	    ctx->total < dd->fallback_sz)
101862306a36Sopenharmony_ci		ctx->flags |= BIT(FLAGS_CPU);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	if (ctx->flags & BIT(FLAGS_CPU))
102162306a36Sopenharmony_ci		err = omap_sham_xmit_cpu(dd, ctx->total, final);
102262306a36Sopenharmony_ci	else
102362306a36Sopenharmony_ci		err = omap_sham_xmit_dma(dd, ctx->total, final);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	/* wait for dma completion before can take more data */
102662306a36Sopenharmony_ci	dev_dbg(dd->dev, "update: err: %d, digcnt: %zd\n", err, ctx->digcnt);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	return err;
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic int omap_sham_final_req(struct omap_sham_dev *dd)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	struct ahash_request *req = dd->req;
103462306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
103562306a36Sopenharmony_ci	int err = 0, use_dma = 1;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	if (dd->flags & BIT(FLAGS_HUGE))
103862306a36Sopenharmony_ci		return 0;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if ((ctx->total <= get_block_size(ctx)) || dd->polling_mode)
104162306a36Sopenharmony_ci		/*
104262306a36Sopenharmony_ci		 * faster to handle last block with cpu or
104362306a36Sopenharmony_ci		 * use cpu when dma is not present.
104462306a36Sopenharmony_ci		 */
104562306a36Sopenharmony_ci		use_dma = 0;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	if (use_dma)
104862306a36Sopenharmony_ci		err = omap_sham_xmit_dma(dd, ctx->total, 1);
104962306a36Sopenharmony_ci	else
105062306a36Sopenharmony_ci		err = omap_sham_xmit_cpu(dd, ctx->total, 1);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	ctx->bufcnt = 0;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	dev_dbg(dd->dev, "final_req: err: %d\n", err);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	return err;
105762306a36Sopenharmony_ci}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_cistatic int omap_sham_hash_one_req(struct crypto_engine *engine, void *areq)
106062306a36Sopenharmony_ci{
106162306a36Sopenharmony_ci	struct ahash_request *req = container_of(areq, struct ahash_request,
106262306a36Sopenharmony_ci						 base);
106362306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
106462306a36Sopenharmony_ci	struct omap_sham_dev *dd = ctx->dd;
106562306a36Sopenharmony_ci	int err;
106662306a36Sopenharmony_ci	bool final = (ctx->flags & BIT(FLAGS_FINUP)) &&
106762306a36Sopenharmony_ci			!(dd->flags & BIT(FLAGS_HUGE));
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	dev_dbg(dd->dev, "hash-one: op: %u, total: %u, digcnt: %zd, final: %d",
107062306a36Sopenharmony_ci		ctx->op, ctx->total, ctx->digcnt, final);
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	err = omap_sham_prepare_request(engine, areq);
107362306a36Sopenharmony_ci	if (err)
107462306a36Sopenharmony_ci		return err;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	err = pm_runtime_resume_and_get(dd->dev);
107762306a36Sopenharmony_ci	if (err < 0) {
107862306a36Sopenharmony_ci		dev_err(dd->dev, "failed to get sync: %d\n", err);
107962306a36Sopenharmony_ci		return err;
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	dd->err = 0;
108362306a36Sopenharmony_ci	dd->req = req;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	if (ctx->digcnt)
108662306a36Sopenharmony_ci		dd->pdata->copy_hash(req, 0);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	if (ctx->op == OP_UPDATE)
108962306a36Sopenharmony_ci		err = omap_sham_update_req(dd);
109062306a36Sopenharmony_ci	else if (ctx->op == OP_FINAL)
109162306a36Sopenharmony_ci		err = omap_sham_final_req(dd);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	if (err != -EINPROGRESS)
109462306a36Sopenharmony_ci		omap_sham_finish_req(req, err);
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	return 0;
109762306a36Sopenharmony_ci}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistatic int omap_sham_finish_hmac(struct ahash_request *req)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
110262306a36Sopenharmony_ci	struct omap_sham_hmac_ctx *bctx = tctx->base;
110362306a36Sopenharmony_ci	int bs = crypto_shash_blocksize(bctx->shash);
110462306a36Sopenharmony_ci	int ds = crypto_shash_digestsize(bctx->shash);
110562306a36Sopenharmony_ci	SHASH_DESC_ON_STACK(shash, bctx->shash);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	shash->tfm = bctx->shash;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	return crypto_shash_init(shash) ?:
111062306a36Sopenharmony_ci	       crypto_shash_update(shash, bctx->opad, bs) ?:
111162306a36Sopenharmony_ci	       crypto_shash_finup(shash, req->result, ds, req->result);
111262306a36Sopenharmony_ci}
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_cistatic int omap_sham_finish(struct ahash_request *req)
111562306a36Sopenharmony_ci{
111662306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
111762306a36Sopenharmony_ci	struct omap_sham_dev *dd = ctx->dd;
111862306a36Sopenharmony_ci	int err = 0;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	if (ctx->digcnt) {
112162306a36Sopenharmony_ci		omap_sham_copy_ready_hash(req);
112262306a36Sopenharmony_ci		if ((ctx->flags & BIT(FLAGS_HMAC)) &&
112362306a36Sopenharmony_ci				!test_bit(FLAGS_AUTO_XOR, &dd->flags))
112462306a36Sopenharmony_ci			err = omap_sham_finish_hmac(req);
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	dev_dbg(dd->dev, "digcnt: %zd, bufcnt: %zd\n", ctx->digcnt, ctx->bufcnt);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	return err;
113062306a36Sopenharmony_ci}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_cistatic void omap_sham_finish_req(struct ahash_request *req, int err)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
113562306a36Sopenharmony_ci	struct omap_sham_dev *dd = ctx->dd;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (test_bit(FLAGS_SGS_COPIED, &dd->flags))
113862306a36Sopenharmony_ci		free_pages((unsigned long)sg_virt(ctx->sg),
113962306a36Sopenharmony_ci			   get_order(ctx->sg->length));
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	if (test_bit(FLAGS_SGS_ALLOCED, &dd->flags))
114262306a36Sopenharmony_ci		kfree(ctx->sg);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	ctx->sg = NULL;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	dd->flags &= ~(BIT(FLAGS_SGS_ALLOCED) | BIT(FLAGS_SGS_COPIED) |
114762306a36Sopenharmony_ci		       BIT(FLAGS_CPU) | BIT(FLAGS_DMA_READY) |
114862306a36Sopenharmony_ci		       BIT(FLAGS_OUTPUT_READY));
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	if (!err)
115162306a36Sopenharmony_ci		dd->pdata->copy_hash(req, 1);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (dd->flags & BIT(FLAGS_HUGE)) {
115462306a36Sopenharmony_ci		/* Re-enqueue the request */
115562306a36Sopenharmony_ci		omap_sham_enqueue(req, ctx->op);
115662306a36Sopenharmony_ci		return;
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	if (!err) {
116062306a36Sopenharmony_ci		if (test_bit(FLAGS_FINAL, &dd->flags))
116162306a36Sopenharmony_ci			err = omap_sham_finish(req);
116262306a36Sopenharmony_ci	} else {
116362306a36Sopenharmony_ci		ctx->flags |= BIT(FLAGS_ERROR);
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	/* atomic operation is not needed here */
116762306a36Sopenharmony_ci	dd->flags &= ~(BIT(FLAGS_FINAL) | BIT(FLAGS_CPU) |
116862306a36Sopenharmony_ci			BIT(FLAGS_DMA_READY) | BIT(FLAGS_OUTPUT_READY));
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	pm_runtime_mark_last_busy(dd->dev);
117162306a36Sopenharmony_ci	pm_runtime_put_autosuspend(dd->dev);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	ctx->offset = 0;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	crypto_finalize_hash_request(dd->engine, req, err);
117662306a36Sopenharmony_ci}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_cistatic int omap_sham_handle_queue(struct omap_sham_dev *dd,
117962306a36Sopenharmony_ci				  struct ahash_request *req)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	return crypto_transfer_hash_request_to_engine(dd->engine, req);
118262306a36Sopenharmony_ci}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_cistatic int omap_sham_enqueue(struct ahash_request *req, unsigned int op)
118562306a36Sopenharmony_ci{
118662306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
118762306a36Sopenharmony_ci	struct omap_sham_dev *dd = ctx->dd;
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	ctx->op = op;
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	return omap_sham_handle_queue(dd, req);
119262306a36Sopenharmony_ci}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_cistatic int omap_sham_update(struct ahash_request *req)
119562306a36Sopenharmony_ci{
119662306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
119762306a36Sopenharmony_ci	struct omap_sham_dev *dd = omap_sham_find_dev(ctx);
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	if (!req->nbytes)
120062306a36Sopenharmony_ci		return 0;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	if (ctx->bufcnt + req->nbytes <= ctx->buflen) {
120362306a36Sopenharmony_ci		scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src,
120462306a36Sopenharmony_ci					 0, req->nbytes, 0);
120562306a36Sopenharmony_ci		ctx->bufcnt += req->nbytes;
120662306a36Sopenharmony_ci		return 0;
120762306a36Sopenharmony_ci	}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	if (dd->polling_mode)
121062306a36Sopenharmony_ci		ctx->flags |= BIT(FLAGS_CPU);
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	return omap_sham_enqueue(req, OP_UPDATE);
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cistatic int omap_sham_final_shash(struct ahash_request *req)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
121862306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
121962306a36Sopenharmony_ci	int offset = 0;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	/*
122262306a36Sopenharmony_ci	 * If we are running HMAC on limited hardware support, skip
122362306a36Sopenharmony_ci	 * the ipad in the beginning of the buffer if we are going for
122462306a36Sopenharmony_ci	 * software fallback algorithm.
122562306a36Sopenharmony_ci	 */
122662306a36Sopenharmony_ci	if (test_bit(FLAGS_HMAC, &ctx->flags) &&
122762306a36Sopenharmony_ci	    !test_bit(FLAGS_AUTO_XOR, &ctx->dd->flags))
122862306a36Sopenharmony_ci		offset = get_block_size(ctx);
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	return crypto_shash_tfm_digest(tctx->fallback, ctx->buffer + offset,
123162306a36Sopenharmony_ci				       ctx->bufcnt - offset, req->result);
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_cistatic int omap_sham_final(struct ahash_request *req)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	ctx->flags |= BIT(FLAGS_FINUP);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	if (ctx->flags & BIT(FLAGS_ERROR))
124162306a36Sopenharmony_ci		return 0; /* uncompleted hash is not needed */
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	/*
124462306a36Sopenharmony_ci	 * OMAP HW accel works only with buffers >= 9.
124562306a36Sopenharmony_ci	 * HMAC is always >= 9 because ipad == block size.
124662306a36Sopenharmony_ci	 * If buffersize is less than fallback_sz, we use fallback
124762306a36Sopenharmony_ci	 * SW encoding, as using DMA + HW in this case doesn't provide
124862306a36Sopenharmony_ci	 * any benefit.
124962306a36Sopenharmony_ci	 */
125062306a36Sopenharmony_ci	if (!ctx->digcnt && ctx->bufcnt < ctx->dd->fallback_sz)
125162306a36Sopenharmony_ci		return omap_sham_final_shash(req);
125262306a36Sopenharmony_ci	else if (ctx->bufcnt)
125362306a36Sopenharmony_ci		return omap_sham_enqueue(req, OP_FINAL);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	/* copy ready hash (+ finalize hmac) */
125662306a36Sopenharmony_ci	return omap_sham_finish(req);
125762306a36Sopenharmony_ci}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_cistatic int omap_sham_finup(struct ahash_request *req)
126062306a36Sopenharmony_ci{
126162306a36Sopenharmony_ci	struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
126262306a36Sopenharmony_ci	int err1, err2;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	ctx->flags |= BIT(FLAGS_FINUP);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	err1 = omap_sham_update(req);
126762306a36Sopenharmony_ci	if (err1 == -EINPROGRESS || err1 == -EBUSY)
126862306a36Sopenharmony_ci		return err1;
126962306a36Sopenharmony_ci	/*
127062306a36Sopenharmony_ci	 * final() has to be always called to cleanup resources
127162306a36Sopenharmony_ci	 * even if udpate() failed, except EINPROGRESS
127262306a36Sopenharmony_ci	 */
127362306a36Sopenharmony_ci	err2 = omap_sham_final(req);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	return err1 ?: err2;
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_cistatic int omap_sham_digest(struct ahash_request *req)
127962306a36Sopenharmony_ci{
128062306a36Sopenharmony_ci	return omap_sham_init(req) ?: omap_sham_finup(req);
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic int omap_sham_setkey(struct crypto_ahash *tfm, const u8 *key,
128462306a36Sopenharmony_ci		      unsigned int keylen)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	struct omap_sham_ctx *tctx = crypto_ahash_ctx(tfm);
128762306a36Sopenharmony_ci	struct omap_sham_hmac_ctx *bctx = tctx->base;
128862306a36Sopenharmony_ci	int bs = crypto_shash_blocksize(bctx->shash);
128962306a36Sopenharmony_ci	int ds = crypto_shash_digestsize(bctx->shash);
129062306a36Sopenharmony_ci	int err, i;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	err = crypto_shash_setkey(tctx->fallback, key, keylen);
129362306a36Sopenharmony_ci	if (err)
129462306a36Sopenharmony_ci		return err;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	if (keylen > bs) {
129762306a36Sopenharmony_ci		err = crypto_shash_tfm_digest(bctx->shash, key, keylen,
129862306a36Sopenharmony_ci					      bctx->ipad);
129962306a36Sopenharmony_ci		if (err)
130062306a36Sopenharmony_ci			return err;
130162306a36Sopenharmony_ci		keylen = ds;
130262306a36Sopenharmony_ci	} else {
130362306a36Sopenharmony_ci		memcpy(bctx->ipad, key, keylen);
130462306a36Sopenharmony_ci	}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	memset(bctx->ipad + keylen, 0, bs - keylen);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (!test_bit(FLAGS_AUTO_XOR, &sham.flags)) {
130962306a36Sopenharmony_ci		memcpy(bctx->opad, bctx->ipad, bs);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci		for (i = 0; i < bs; i++) {
131262306a36Sopenharmony_ci			bctx->ipad[i] ^= HMAC_IPAD_VALUE;
131362306a36Sopenharmony_ci			bctx->opad[i] ^= HMAC_OPAD_VALUE;
131462306a36Sopenharmony_ci		}
131562306a36Sopenharmony_ci	}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	return err;
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_cistatic int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
132162306a36Sopenharmony_ci{
132262306a36Sopenharmony_ci	struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm);
132362306a36Sopenharmony_ci	const char *alg_name = crypto_tfm_alg_name(tfm);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	/* Allocate a fallback and abort if it failed. */
132662306a36Sopenharmony_ci	tctx->fallback = crypto_alloc_shash(alg_name, 0,
132762306a36Sopenharmony_ci					    CRYPTO_ALG_NEED_FALLBACK);
132862306a36Sopenharmony_ci	if (IS_ERR(tctx->fallback)) {
132962306a36Sopenharmony_ci		pr_err("omap-sham: fallback driver '%s' "
133062306a36Sopenharmony_ci				"could not be loaded.\n", alg_name);
133162306a36Sopenharmony_ci		return PTR_ERR(tctx->fallback);
133262306a36Sopenharmony_ci	}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
133562306a36Sopenharmony_ci				 sizeof(struct omap_sham_reqctx) + BUFLEN);
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	if (alg_base) {
133862306a36Sopenharmony_ci		struct omap_sham_hmac_ctx *bctx = tctx->base;
133962306a36Sopenharmony_ci		tctx->flags |= BIT(FLAGS_HMAC);
134062306a36Sopenharmony_ci		bctx->shash = crypto_alloc_shash(alg_base, 0,
134162306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK);
134262306a36Sopenharmony_ci		if (IS_ERR(bctx->shash)) {
134362306a36Sopenharmony_ci			pr_err("omap-sham: base driver '%s' "
134462306a36Sopenharmony_ci					"could not be loaded.\n", alg_base);
134562306a36Sopenharmony_ci			crypto_free_shash(tctx->fallback);
134662306a36Sopenharmony_ci			return PTR_ERR(bctx->shash);
134762306a36Sopenharmony_ci		}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	return 0;
135262306a36Sopenharmony_ci}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_cistatic int omap_sham_cra_init(struct crypto_tfm *tfm)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	return omap_sham_cra_init_alg(tfm, NULL);
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_cistatic int omap_sham_cra_sha1_init(struct crypto_tfm *tfm)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	return omap_sham_cra_init_alg(tfm, "sha1");
136262306a36Sopenharmony_ci}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_cistatic int omap_sham_cra_sha224_init(struct crypto_tfm *tfm)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	return omap_sham_cra_init_alg(tfm, "sha224");
136762306a36Sopenharmony_ci}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_cistatic int omap_sham_cra_sha256_init(struct crypto_tfm *tfm)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	return omap_sham_cra_init_alg(tfm, "sha256");
137262306a36Sopenharmony_ci}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_cistatic int omap_sham_cra_md5_init(struct crypto_tfm *tfm)
137562306a36Sopenharmony_ci{
137662306a36Sopenharmony_ci	return omap_sham_cra_init_alg(tfm, "md5");
137762306a36Sopenharmony_ci}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_cistatic int omap_sham_cra_sha384_init(struct crypto_tfm *tfm)
138062306a36Sopenharmony_ci{
138162306a36Sopenharmony_ci	return omap_sham_cra_init_alg(tfm, "sha384");
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic int omap_sham_cra_sha512_init(struct crypto_tfm *tfm)
138562306a36Sopenharmony_ci{
138662306a36Sopenharmony_ci	return omap_sham_cra_init_alg(tfm, "sha512");
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_cistatic void omap_sham_cra_exit(struct crypto_tfm *tfm)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	crypto_free_shash(tctx->fallback);
139462306a36Sopenharmony_ci	tctx->fallback = NULL;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if (tctx->flags & BIT(FLAGS_HMAC)) {
139762306a36Sopenharmony_ci		struct omap_sham_hmac_ctx *bctx = tctx->base;
139862306a36Sopenharmony_ci		crypto_free_shash(bctx->shash);
139962306a36Sopenharmony_ci	}
140062306a36Sopenharmony_ci}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_cistatic int omap_sham_export(struct ahash_request *req, void *out)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci	struct omap_sham_reqctx *rctx = ahash_request_ctx(req);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	memcpy(out, rctx, sizeof(*rctx) + rctx->bufcnt);
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	return 0;
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_cistatic int omap_sham_import(struct ahash_request *req, const void *in)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	struct omap_sham_reqctx *rctx = ahash_request_ctx(req);
141462306a36Sopenharmony_ci	const struct omap_sham_reqctx *ctx_in = in;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	memcpy(rctx, in, sizeof(*rctx) + ctx_in->bufcnt);
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	return 0;
141962306a36Sopenharmony_ci}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_cistatic struct ahash_engine_alg algs_sha1_md5[] = {
142262306a36Sopenharmony_ci{
142362306a36Sopenharmony_ci	.base.init		= omap_sham_init,
142462306a36Sopenharmony_ci	.base.update		= omap_sham_update,
142562306a36Sopenharmony_ci	.base.final		= omap_sham_final,
142662306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
142762306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
142862306a36Sopenharmony_ci	.base.halg.digestsize	= SHA1_DIGEST_SIZE,
142962306a36Sopenharmony_ci	.base.halg.base	= {
143062306a36Sopenharmony_ci		.cra_name		= "sha1",
143162306a36Sopenharmony_ci		.cra_driver_name	= "omap-sha1",
143262306a36Sopenharmony_ci		.cra_priority		= 400,
143362306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
143462306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
143562306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
143662306a36Sopenharmony_ci		.cra_blocksize		= SHA1_BLOCK_SIZE,
143762306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx),
143862306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
143962306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
144062306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_init,
144162306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
144262306a36Sopenharmony_ci	},
144362306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
144462306a36Sopenharmony_ci},
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	.base.init		= omap_sham_init,
144762306a36Sopenharmony_ci	.base.update		= omap_sham_update,
144862306a36Sopenharmony_ci	.base.final		= omap_sham_final,
144962306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
145062306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
145162306a36Sopenharmony_ci	.base.halg.digestsize	= MD5_DIGEST_SIZE,
145262306a36Sopenharmony_ci	.base.halg.base	= {
145362306a36Sopenharmony_ci		.cra_name		= "md5",
145462306a36Sopenharmony_ci		.cra_driver_name	= "omap-md5",
145562306a36Sopenharmony_ci		.cra_priority		= 400,
145662306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
145762306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
145862306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
145962306a36Sopenharmony_ci		.cra_blocksize		= SHA1_BLOCK_SIZE,
146062306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx),
146162306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
146262306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
146362306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_init,
146462306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
146562306a36Sopenharmony_ci	},
146662306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
146762306a36Sopenharmony_ci},
146862306a36Sopenharmony_ci{
146962306a36Sopenharmony_ci	.base.init		= omap_sham_init,
147062306a36Sopenharmony_ci	.base.update		= omap_sham_update,
147162306a36Sopenharmony_ci	.base.final		= omap_sham_final,
147262306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
147362306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
147462306a36Sopenharmony_ci	.base.setkey		= omap_sham_setkey,
147562306a36Sopenharmony_ci	.base.halg.digestsize	= SHA1_DIGEST_SIZE,
147662306a36Sopenharmony_ci	.base.halg.base	= {
147762306a36Sopenharmony_ci		.cra_name		= "hmac(sha1)",
147862306a36Sopenharmony_ci		.cra_driver_name	= "omap-hmac-sha1",
147962306a36Sopenharmony_ci		.cra_priority		= 400,
148062306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
148162306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
148262306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
148362306a36Sopenharmony_ci		.cra_blocksize		= SHA1_BLOCK_SIZE,
148462306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx) +
148562306a36Sopenharmony_ci					sizeof(struct omap_sham_hmac_ctx),
148662306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
148762306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
148862306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_sha1_init,
148962306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
149062306a36Sopenharmony_ci	},
149162306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
149262306a36Sopenharmony_ci},
149362306a36Sopenharmony_ci{
149462306a36Sopenharmony_ci	.base.init		= omap_sham_init,
149562306a36Sopenharmony_ci	.base.update		= omap_sham_update,
149662306a36Sopenharmony_ci	.base.final		= omap_sham_final,
149762306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
149862306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
149962306a36Sopenharmony_ci	.base.setkey		= omap_sham_setkey,
150062306a36Sopenharmony_ci	.base.halg.digestsize	= MD5_DIGEST_SIZE,
150162306a36Sopenharmony_ci	.base.halg.base	= {
150262306a36Sopenharmony_ci		.cra_name		= "hmac(md5)",
150362306a36Sopenharmony_ci		.cra_driver_name	= "omap-hmac-md5",
150462306a36Sopenharmony_ci		.cra_priority		= 400,
150562306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
150662306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
150762306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
150862306a36Sopenharmony_ci		.cra_blocksize		= SHA1_BLOCK_SIZE,
150962306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx) +
151062306a36Sopenharmony_ci					sizeof(struct omap_sham_hmac_ctx),
151162306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
151262306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
151362306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_md5_init,
151462306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
151562306a36Sopenharmony_ci	},
151662306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
151762306a36Sopenharmony_ci}
151862306a36Sopenharmony_ci};
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci/* OMAP4 has some algs in addition to what OMAP2 has */
152162306a36Sopenharmony_cistatic struct ahash_engine_alg algs_sha224_sha256[] = {
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	.base.init		= omap_sham_init,
152462306a36Sopenharmony_ci	.base.update		= omap_sham_update,
152562306a36Sopenharmony_ci	.base.final		= omap_sham_final,
152662306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
152762306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
152862306a36Sopenharmony_ci	.base.halg.digestsize	= SHA224_DIGEST_SIZE,
152962306a36Sopenharmony_ci	.base.halg.base	= {
153062306a36Sopenharmony_ci		.cra_name		= "sha224",
153162306a36Sopenharmony_ci		.cra_driver_name	= "omap-sha224",
153262306a36Sopenharmony_ci		.cra_priority		= 400,
153362306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
153462306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
153562306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
153662306a36Sopenharmony_ci		.cra_blocksize		= SHA224_BLOCK_SIZE,
153762306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx),
153862306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
153962306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
154062306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_init,
154162306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
154262306a36Sopenharmony_ci	},
154362306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
154462306a36Sopenharmony_ci},
154562306a36Sopenharmony_ci{
154662306a36Sopenharmony_ci	.base.init		= omap_sham_init,
154762306a36Sopenharmony_ci	.base.update		= omap_sham_update,
154862306a36Sopenharmony_ci	.base.final		= omap_sham_final,
154962306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
155062306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
155162306a36Sopenharmony_ci	.base.halg.digestsize	= SHA256_DIGEST_SIZE,
155262306a36Sopenharmony_ci	.base.halg.base	= {
155362306a36Sopenharmony_ci		.cra_name		= "sha256",
155462306a36Sopenharmony_ci		.cra_driver_name	= "omap-sha256",
155562306a36Sopenharmony_ci		.cra_priority		= 400,
155662306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
155762306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
155862306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
155962306a36Sopenharmony_ci		.cra_blocksize		= SHA256_BLOCK_SIZE,
156062306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx),
156162306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
156262306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
156362306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_init,
156462306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
156562306a36Sopenharmony_ci	},
156662306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
156762306a36Sopenharmony_ci},
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	.base.init		= omap_sham_init,
157062306a36Sopenharmony_ci	.base.update		= omap_sham_update,
157162306a36Sopenharmony_ci	.base.final		= omap_sham_final,
157262306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
157362306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
157462306a36Sopenharmony_ci	.base.setkey		= omap_sham_setkey,
157562306a36Sopenharmony_ci	.base.halg.digestsize	= SHA224_DIGEST_SIZE,
157662306a36Sopenharmony_ci	.base.halg.base	= {
157762306a36Sopenharmony_ci		.cra_name		= "hmac(sha224)",
157862306a36Sopenharmony_ci		.cra_driver_name	= "omap-hmac-sha224",
157962306a36Sopenharmony_ci		.cra_priority		= 400,
158062306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
158162306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
158262306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
158362306a36Sopenharmony_ci		.cra_blocksize		= SHA224_BLOCK_SIZE,
158462306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx) +
158562306a36Sopenharmony_ci					sizeof(struct omap_sham_hmac_ctx),
158662306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
158762306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
158862306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_sha224_init,
158962306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
159062306a36Sopenharmony_ci	},
159162306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
159262306a36Sopenharmony_ci},
159362306a36Sopenharmony_ci{
159462306a36Sopenharmony_ci	.base.init		= omap_sham_init,
159562306a36Sopenharmony_ci	.base.update		= omap_sham_update,
159662306a36Sopenharmony_ci	.base.final		= omap_sham_final,
159762306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
159862306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
159962306a36Sopenharmony_ci	.base.setkey		= omap_sham_setkey,
160062306a36Sopenharmony_ci	.base.halg.digestsize	= SHA256_DIGEST_SIZE,
160162306a36Sopenharmony_ci	.base.halg.base	= {
160262306a36Sopenharmony_ci		.cra_name		= "hmac(sha256)",
160362306a36Sopenharmony_ci		.cra_driver_name	= "omap-hmac-sha256",
160462306a36Sopenharmony_ci		.cra_priority		= 400,
160562306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
160662306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
160762306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
160862306a36Sopenharmony_ci		.cra_blocksize		= SHA256_BLOCK_SIZE,
160962306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx) +
161062306a36Sopenharmony_ci					sizeof(struct omap_sham_hmac_ctx),
161162306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
161262306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
161362306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_sha256_init,
161462306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
161562306a36Sopenharmony_ci	},
161662306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
161762306a36Sopenharmony_ci},
161862306a36Sopenharmony_ci};
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_cistatic struct ahash_engine_alg algs_sha384_sha512[] = {
162162306a36Sopenharmony_ci{
162262306a36Sopenharmony_ci	.base.init		= omap_sham_init,
162362306a36Sopenharmony_ci	.base.update		= omap_sham_update,
162462306a36Sopenharmony_ci	.base.final		= omap_sham_final,
162562306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
162662306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
162762306a36Sopenharmony_ci	.base.halg.digestsize	= SHA384_DIGEST_SIZE,
162862306a36Sopenharmony_ci	.base.halg.base	= {
162962306a36Sopenharmony_ci		.cra_name		= "sha384",
163062306a36Sopenharmony_ci		.cra_driver_name	= "omap-sha384",
163162306a36Sopenharmony_ci		.cra_priority		= 400,
163262306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
163362306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
163462306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
163562306a36Sopenharmony_ci		.cra_blocksize		= SHA384_BLOCK_SIZE,
163662306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx),
163762306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
163862306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
163962306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_init,
164062306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
164162306a36Sopenharmony_ci	},
164262306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
164362306a36Sopenharmony_ci},
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	.base.init		= omap_sham_init,
164662306a36Sopenharmony_ci	.base.update		= omap_sham_update,
164762306a36Sopenharmony_ci	.base.final		= omap_sham_final,
164862306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
164962306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
165062306a36Sopenharmony_ci	.base.halg.digestsize	= SHA512_DIGEST_SIZE,
165162306a36Sopenharmony_ci	.base.halg.base	= {
165262306a36Sopenharmony_ci		.cra_name		= "sha512",
165362306a36Sopenharmony_ci		.cra_driver_name	= "omap-sha512",
165462306a36Sopenharmony_ci		.cra_priority		= 400,
165562306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
165662306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
165762306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
165862306a36Sopenharmony_ci		.cra_blocksize		= SHA512_BLOCK_SIZE,
165962306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx),
166062306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
166162306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
166262306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_init,
166362306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
166462306a36Sopenharmony_ci	},
166562306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
166662306a36Sopenharmony_ci},
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	.base.init		= omap_sham_init,
166962306a36Sopenharmony_ci	.base.update		= omap_sham_update,
167062306a36Sopenharmony_ci	.base.final		= omap_sham_final,
167162306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
167262306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
167362306a36Sopenharmony_ci	.base.setkey		= omap_sham_setkey,
167462306a36Sopenharmony_ci	.base.halg.digestsize	= SHA384_DIGEST_SIZE,
167562306a36Sopenharmony_ci	.base.halg.base	= {
167662306a36Sopenharmony_ci		.cra_name		= "hmac(sha384)",
167762306a36Sopenharmony_ci		.cra_driver_name	= "omap-hmac-sha384",
167862306a36Sopenharmony_ci		.cra_priority		= 400,
167962306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
168062306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
168162306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
168262306a36Sopenharmony_ci		.cra_blocksize		= SHA384_BLOCK_SIZE,
168362306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx) +
168462306a36Sopenharmony_ci					sizeof(struct omap_sham_hmac_ctx),
168562306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
168662306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
168762306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_sha384_init,
168862306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
168962306a36Sopenharmony_ci	},
169062306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
169162306a36Sopenharmony_ci},
169262306a36Sopenharmony_ci{
169362306a36Sopenharmony_ci	.base.init		= omap_sham_init,
169462306a36Sopenharmony_ci	.base.update		= omap_sham_update,
169562306a36Sopenharmony_ci	.base.final		= omap_sham_final,
169662306a36Sopenharmony_ci	.base.finup		= omap_sham_finup,
169762306a36Sopenharmony_ci	.base.digest		= omap_sham_digest,
169862306a36Sopenharmony_ci	.base.setkey		= omap_sham_setkey,
169962306a36Sopenharmony_ci	.base.halg.digestsize	= SHA512_DIGEST_SIZE,
170062306a36Sopenharmony_ci	.base.halg.base	= {
170162306a36Sopenharmony_ci		.cra_name		= "hmac(sha512)",
170262306a36Sopenharmony_ci		.cra_driver_name	= "omap-hmac-sha512",
170362306a36Sopenharmony_ci		.cra_priority		= 400,
170462306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_KERN_DRIVER_ONLY |
170562306a36Sopenharmony_ci						CRYPTO_ALG_ASYNC |
170662306a36Sopenharmony_ci						CRYPTO_ALG_NEED_FALLBACK,
170762306a36Sopenharmony_ci		.cra_blocksize		= SHA512_BLOCK_SIZE,
170862306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct omap_sham_ctx) +
170962306a36Sopenharmony_ci					sizeof(struct omap_sham_hmac_ctx),
171062306a36Sopenharmony_ci		.cra_alignmask		= OMAP_ALIGN_MASK,
171162306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
171262306a36Sopenharmony_ci		.cra_init		= omap_sham_cra_sha512_init,
171362306a36Sopenharmony_ci		.cra_exit		= omap_sham_cra_exit,
171462306a36Sopenharmony_ci	},
171562306a36Sopenharmony_ci	.op.do_one_request = omap_sham_hash_one_req,
171662306a36Sopenharmony_ci},
171762306a36Sopenharmony_ci};
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_cistatic void omap_sham_done_task(unsigned long data)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	struct omap_sham_dev *dd = (struct omap_sham_dev *)data;
172262306a36Sopenharmony_ci	int err = 0;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	dev_dbg(dd->dev, "%s: flags=%lx\n", __func__, dd->flags);
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	if (test_bit(FLAGS_CPU, &dd->flags)) {
172762306a36Sopenharmony_ci		if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags))
172862306a36Sopenharmony_ci			goto finish;
172962306a36Sopenharmony_ci	} else if (test_bit(FLAGS_DMA_READY, &dd->flags)) {
173062306a36Sopenharmony_ci		if (test_bit(FLAGS_DMA_ACTIVE, &dd->flags)) {
173162306a36Sopenharmony_ci			omap_sham_update_dma_stop(dd);
173262306a36Sopenharmony_ci			if (dd->err) {
173362306a36Sopenharmony_ci				err = dd->err;
173462306a36Sopenharmony_ci				goto finish;
173562306a36Sopenharmony_ci			}
173662306a36Sopenharmony_ci		}
173762306a36Sopenharmony_ci		if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) {
173862306a36Sopenharmony_ci			/* hash or semi-hash ready */
173962306a36Sopenharmony_ci			clear_bit(FLAGS_DMA_READY, &dd->flags);
174062306a36Sopenharmony_ci			goto finish;
174162306a36Sopenharmony_ci		}
174262306a36Sopenharmony_ci	}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	return;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_cifinish:
174762306a36Sopenharmony_ci	dev_dbg(dd->dev, "update done: err: %d\n", err);
174862306a36Sopenharmony_ci	/* finish curent request */
174962306a36Sopenharmony_ci	omap_sham_finish_req(dd->req, err);
175062306a36Sopenharmony_ci}
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_cistatic irqreturn_t omap_sham_irq_common(struct omap_sham_dev *dd)
175362306a36Sopenharmony_ci{
175462306a36Sopenharmony_ci	set_bit(FLAGS_OUTPUT_READY, &dd->flags);
175562306a36Sopenharmony_ci	tasklet_schedule(&dd->done_task);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	return IRQ_HANDLED;
175862306a36Sopenharmony_ci}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_cistatic irqreturn_t omap_sham_irq_omap2(int irq, void *dev_id)
176162306a36Sopenharmony_ci{
176262306a36Sopenharmony_ci	struct omap_sham_dev *dd = dev_id;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	if (unlikely(test_bit(FLAGS_FINAL, &dd->flags)))
176562306a36Sopenharmony_ci		/* final -> allow device to go to power-saving mode */
176662306a36Sopenharmony_ci		omap_sham_write_mask(dd, SHA_REG_CTRL, 0, SHA_REG_CTRL_LENGTH);
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	omap_sham_write_mask(dd, SHA_REG_CTRL, SHA_REG_CTRL_OUTPUT_READY,
176962306a36Sopenharmony_ci				 SHA_REG_CTRL_OUTPUT_READY);
177062306a36Sopenharmony_ci	omap_sham_read(dd, SHA_REG_CTRL);
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	return omap_sham_irq_common(dd);
177362306a36Sopenharmony_ci}
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_cistatic irqreturn_t omap_sham_irq_omap4(int irq, void *dev_id)
177662306a36Sopenharmony_ci{
177762306a36Sopenharmony_ci	struct omap_sham_dev *dd = dev_id;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	omap_sham_write_mask(dd, SHA_REG_MASK(dd), 0, SHA_REG_MASK_IT_EN);
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	return omap_sham_irq_common(dd);
178262306a36Sopenharmony_ci}
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_cistatic struct omap_sham_algs_info omap_sham_algs_info_omap2[] = {
178562306a36Sopenharmony_ci	{
178662306a36Sopenharmony_ci		.algs_list	= algs_sha1_md5,
178762306a36Sopenharmony_ci		.size		= ARRAY_SIZE(algs_sha1_md5),
178862306a36Sopenharmony_ci	},
178962306a36Sopenharmony_ci};
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_cistatic const struct omap_sham_pdata omap_sham_pdata_omap2 = {
179262306a36Sopenharmony_ci	.algs_info	= omap_sham_algs_info_omap2,
179362306a36Sopenharmony_ci	.algs_info_size	= ARRAY_SIZE(omap_sham_algs_info_omap2),
179462306a36Sopenharmony_ci	.flags		= BIT(FLAGS_BE32_SHA1),
179562306a36Sopenharmony_ci	.digest_size	= SHA1_DIGEST_SIZE,
179662306a36Sopenharmony_ci	.copy_hash	= omap_sham_copy_hash_omap2,
179762306a36Sopenharmony_ci	.write_ctrl	= omap_sham_write_ctrl_omap2,
179862306a36Sopenharmony_ci	.trigger	= omap_sham_trigger_omap2,
179962306a36Sopenharmony_ci	.poll_irq	= omap_sham_poll_irq_omap2,
180062306a36Sopenharmony_ci	.intr_hdlr	= omap_sham_irq_omap2,
180162306a36Sopenharmony_ci	.idigest_ofs	= 0x00,
180262306a36Sopenharmony_ci	.din_ofs	= 0x1c,
180362306a36Sopenharmony_ci	.digcnt_ofs	= 0x14,
180462306a36Sopenharmony_ci	.rev_ofs	= 0x5c,
180562306a36Sopenharmony_ci	.mask_ofs	= 0x60,
180662306a36Sopenharmony_ci	.sysstatus_ofs	= 0x64,
180762306a36Sopenharmony_ci	.major_mask	= 0xf0,
180862306a36Sopenharmony_ci	.major_shift	= 4,
180962306a36Sopenharmony_ci	.minor_mask	= 0x0f,
181062306a36Sopenharmony_ci	.minor_shift	= 0,
181162306a36Sopenharmony_ci};
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci#ifdef CONFIG_OF
181462306a36Sopenharmony_cistatic struct omap_sham_algs_info omap_sham_algs_info_omap4[] = {
181562306a36Sopenharmony_ci	{
181662306a36Sopenharmony_ci		.algs_list	= algs_sha1_md5,
181762306a36Sopenharmony_ci		.size		= ARRAY_SIZE(algs_sha1_md5),
181862306a36Sopenharmony_ci	},
181962306a36Sopenharmony_ci	{
182062306a36Sopenharmony_ci		.algs_list	= algs_sha224_sha256,
182162306a36Sopenharmony_ci		.size		= ARRAY_SIZE(algs_sha224_sha256),
182262306a36Sopenharmony_ci	},
182362306a36Sopenharmony_ci};
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_cistatic const struct omap_sham_pdata omap_sham_pdata_omap4 = {
182662306a36Sopenharmony_ci	.algs_info	= omap_sham_algs_info_omap4,
182762306a36Sopenharmony_ci	.algs_info_size	= ARRAY_SIZE(omap_sham_algs_info_omap4),
182862306a36Sopenharmony_ci	.flags		= BIT(FLAGS_AUTO_XOR),
182962306a36Sopenharmony_ci	.digest_size	= SHA256_DIGEST_SIZE,
183062306a36Sopenharmony_ci	.copy_hash	= omap_sham_copy_hash_omap4,
183162306a36Sopenharmony_ci	.write_ctrl	= omap_sham_write_ctrl_omap4,
183262306a36Sopenharmony_ci	.trigger	= omap_sham_trigger_omap4,
183362306a36Sopenharmony_ci	.poll_irq	= omap_sham_poll_irq_omap4,
183462306a36Sopenharmony_ci	.intr_hdlr	= omap_sham_irq_omap4,
183562306a36Sopenharmony_ci	.idigest_ofs	= 0x020,
183662306a36Sopenharmony_ci	.odigest_ofs	= 0x0,
183762306a36Sopenharmony_ci	.din_ofs	= 0x080,
183862306a36Sopenharmony_ci	.digcnt_ofs	= 0x040,
183962306a36Sopenharmony_ci	.rev_ofs	= 0x100,
184062306a36Sopenharmony_ci	.mask_ofs	= 0x110,
184162306a36Sopenharmony_ci	.sysstatus_ofs	= 0x114,
184262306a36Sopenharmony_ci	.mode_ofs	= 0x44,
184362306a36Sopenharmony_ci	.length_ofs	= 0x48,
184462306a36Sopenharmony_ci	.major_mask	= 0x0700,
184562306a36Sopenharmony_ci	.major_shift	= 8,
184662306a36Sopenharmony_ci	.minor_mask	= 0x003f,
184762306a36Sopenharmony_ci	.minor_shift	= 0,
184862306a36Sopenharmony_ci};
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_cistatic struct omap_sham_algs_info omap_sham_algs_info_omap5[] = {
185162306a36Sopenharmony_ci	{
185262306a36Sopenharmony_ci		.algs_list	= algs_sha1_md5,
185362306a36Sopenharmony_ci		.size		= ARRAY_SIZE(algs_sha1_md5),
185462306a36Sopenharmony_ci	},
185562306a36Sopenharmony_ci	{
185662306a36Sopenharmony_ci		.algs_list	= algs_sha224_sha256,
185762306a36Sopenharmony_ci		.size		= ARRAY_SIZE(algs_sha224_sha256),
185862306a36Sopenharmony_ci	},
185962306a36Sopenharmony_ci	{
186062306a36Sopenharmony_ci		.algs_list	= algs_sha384_sha512,
186162306a36Sopenharmony_ci		.size		= ARRAY_SIZE(algs_sha384_sha512),
186262306a36Sopenharmony_ci	},
186362306a36Sopenharmony_ci};
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_cistatic const struct omap_sham_pdata omap_sham_pdata_omap5 = {
186662306a36Sopenharmony_ci	.algs_info	= omap_sham_algs_info_omap5,
186762306a36Sopenharmony_ci	.algs_info_size	= ARRAY_SIZE(omap_sham_algs_info_omap5),
186862306a36Sopenharmony_ci	.flags		= BIT(FLAGS_AUTO_XOR),
186962306a36Sopenharmony_ci	.digest_size	= SHA512_DIGEST_SIZE,
187062306a36Sopenharmony_ci	.copy_hash	= omap_sham_copy_hash_omap4,
187162306a36Sopenharmony_ci	.write_ctrl	= omap_sham_write_ctrl_omap4,
187262306a36Sopenharmony_ci	.trigger	= omap_sham_trigger_omap4,
187362306a36Sopenharmony_ci	.poll_irq	= omap_sham_poll_irq_omap4,
187462306a36Sopenharmony_ci	.intr_hdlr	= omap_sham_irq_omap4,
187562306a36Sopenharmony_ci	.idigest_ofs	= 0x240,
187662306a36Sopenharmony_ci	.odigest_ofs	= 0x200,
187762306a36Sopenharmony_ci	.din_ofs	= 0x080,
187862306a36Sopenharmony_ci	.digcnt_ofs	= 0x280,
187962306a36Sopenharmony_ci	.rev_ofs	= 0x100,
188062306a36Sopenharmony_ci	.mask_ofs	= 0x110,
188162306a36Sopenharmony_ci	.sysstatus_ofs	= 0x114,
188262306a36Sopenharmony_ci	.mode_ofs	= 0x284,
188362306a36Sopenharmony_ci	.length_ofs	= 0x288,
188462306a36Sopenharmony_ci	.major_mask	= 0x0700,
188562306a36Sopenharmony_ci	.major_shift	= 8,
188662306a36Sopenharmony_ci	.minor_mask	= 0x003f,
188762306a36Sopenharmony_ci	.minor_shift	= 0,
188862306a36Sopenharmony_ci};
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_cistatic const struct of_device_id omap_sham_of_match[] = {
189162306a36Sopenharmony_ci	{
189262306a36Sopenharmony_ci		.compatible	= "ti,omap2-sham",
189362306a36Sopenharmony_ci		.data		= &omap_sham_pdata_omap2,
189462306a36Sopenharmony_ci	},
189562306a36Sopenharmony_ci	{
189662306a36Sopenharmony_ci		.compatible	= "ti,omap3-sham",
189762306a36Sopenharmony_ci		.data		= &omap_sham_pdata_omap2,
189862306a36Sopenharmony_ci	},
189962306a36Sopenharmony_ci	{
190062306a36Sopenharmony_ci		.compatible	= "ti,omap4-sham",
190162306a36Sopenharmony_ci		.data		= &omap_sham_pdata_omap4,
190262306a36Sopenharmony_ci	},
190362306a36Sopenharmony_ci	{
190462306a36Sopenharmony_ci		.compatible	= "ti,omap5-sham",
190562306a36Sopenharmony_ci		.data		= &omap_sham_pdata_omap5,
190662306a36Sopenharmony_ci	},
190762306a36Sopenharmony_ci	{},
190862306a36Sopenharmony_ci};
190962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_sham_of_match);
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_cistatic int omap_sham_get_res_of(struct omap_sham_dev *dd,
191262306a36Sopenharmony_ci		struct device *dev, struct resource *res)
191362306a36Sopenharmony_ci{
191462306a36Sopenharmony_ci	struct device_node *node = dev->of_node;
191562306a36Sopenharmony_ci	int err = 0;
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	dd->pdata = of_device_get_match_data(dev);
191862306a36Sopenharmony_ci	if (!dd->pdata) {
191962306a36Sopenharmony_ci		dev_err(dev, "no compatible OF match\n");
192062306a36Sopenharmony_ci		err = -EINVAL;
192162306a36Sopenharmony_ci		goto err;
192262306a36Sopenharmony_ci	}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	err = of_address_to_resource(node, 0, res);
192562306a36Sopenharmony_ci	if (err < 0) {
192662306a36Sopenharmony_ci		dev_err(dev, "can't translate OF node address\n");
192762306a36Sopenharmony_ci		err = -EINVAL;
192862306a36Sopenharmony_ci		goto err;
192962306a36Sopenharmony_ci	}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	dd->irq = irq_of_parse_and_map(node, 0);
193262306a36Sopenharmony_ci	if (!dd->irq) {
193362306a36Sopenharmony_ci		dev_err(dev, "can't translate OF irq value\n");
193462306a36Sopenharmony_ci		err = -EINVAL;
193562306a36Sopenharmony_ci		goto err;
193662306a36Sopenharmony_ci	}
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_cierr:
193962306a36Sopenharmony_ci	return err;
194062306a36Sopenharmony_ci}
194162306a36Sopenharmony_ci#else
194262306a36Sopenharmony_cistatic const struct of_device_id omap_sham_of_match[] = {
194362306a36Sopenharmony_ci	{},
194462306a36Sopenharmony_ci};
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_cistatic int omap_sham_get_res_of(struct omap_sham_dev *dd,
194762306a36Sopenharmony_ci		struct device *dev, struct resource *res)
194862306a36Sopenharmony_ci{
194962306a36Sopenharmony_ci	return -EINVAL;
195062306a36Sopenharmony_ci}
195162306a36Sopenharmony_ci#endif
195262306a36Sopenharmony_ci
195362306a36Sopenharmony_cistatic int omap_sham_get_res_pdev(struct omap_sham_dev *dd,
195462306a36Sopenharmony_ci		struct platform_device *pdev, struct resource *res)
195562306a36Sopenharmony_ci{
195662306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
195762306a36Sopenharmony_ci	struct resource *r;
195862306a36Sopenharmony_ci	int err = 0;
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	/* Get the base address */
196162306a36Sopenharmony_ci	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
196262306a36Sopenharmony_ci	if (!r) {
196362306a36Sopenharmony_ci		dev_err(dev, "no MEM resource info\n");
196462306a36Sopenharmony_ci		err = -ENODEV;
196562306a36Sopenharmony_ci		goto err;
196662306a36Sopenharmony_ci	}
196762306a36Sopenharmony_ci	memcpy(res, r, sizeof(*res));
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	/* Get the IRQ */
197062306a36Sopenharmony_ci	dd->irq = platform_get_irq(pdev, 0);
197162306a36Sopenharmony_ci	if (dd->irq < 0) {
197262306a36Sopenharmony_ci		err = dd->irq;
197362306a36Sopenharmony_ci		goto err;
197462306a36Sopenharmony_ci	}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	/* Only OMAP2/3 can be non-DT */
197762306a36Sopenharmony_ci	dd->pdata = &omap_sham_pdata_omap2;
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_cierr:
198062306a36Sopenharmony_ci	return err;
198162306a36Sopenharmony_ci}
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_cistatic ssize_t fallback_show(struct device *dev, struct device_attribute *attr,
198462306a36Sopenharmony_ci			     char *buf)
198562306a36Sopenharmony_ci{
198662306a36Sopenharmony_ci	struct omap_sham_dev *dd = dev_get_drvdata(dev);
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	return sprintf(buf, "%d\n", dd->fallback_sz);
198962306a36Sopenharmony_ci}
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_cistatic ssize_t fallback_store(struct device *dev, struct device_attribute *attr,
199262306a36Sopenharmony_ci			      const char *buf, size_t size)
199362306a36Sopenharmony_ci{
199462306a36Sopenharmony_ci	struct omap_sham_dev *dd = dev_get_drvdata(dev);
199562306a36Sopenharmony_ci	ssize_t status;
199662306a36Sopenharmony_ci	long value;
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	status = kstrtol(buf, 0, &value);
199962306a36Sopenharmony_ci	if (status)
200062306a36Sopenharmony_ci		return status;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	/* HW accelerator only works with buffers > 9 */
200362306a36Sopenharmony_ci	if (value < 9) {
200462306a36Sopenharmony_ci		dev_err(dev, "minimum fallback size 9\n");
200562306a36Sopenharmony_ci		return -EINVAL;
200662306a36Sopenharmony_ci	}
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	dd->fallback_sz = value;
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	return size;
201162306a36Sopenharmony_ci}
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_cistatic ssize_t queue_len_show(struct device *dev, struct device_attribute *attr,
201462306a36Sopenharmony_ci			      char *buf)
201562306a36Sopenharmony_ci{
201662306a36Sopenharmony_ci	struct omap_sham_dev *dd = dev_get_drvdata(dev);
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	return sprintf(buf, "%d\n", dd->queue.max_qlen);
201962306a36Sopenharmony_ci}
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_cistatic ssize_t queue_len_store(struct device *dev,
202262306a36Sopenharmony_ci			       struct device_attribute *attr, const char *buf,
202362306a36Sopenharmony_ci			       size_t size)
202462306a36Sopenharmony_ci{
202562306a36Sopenharmony_ci	struct omap_sham_dev *dd = dev_get_drvdata(dev);
202662306a36Sopenharmony_ci	ssize_t status;
202762306a36Sopenharmony_ci	long value;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	status = kstrtol(buf, 0, &value);
203062306a36Sopenharmony_ci	if (status)
203162306a36Sopenharmony_ci		return status;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	if (value < 1)
203462306a36Sopenharmony_ci		return -EINVAL;
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	/*
203762306a36Sopenharmony_ci	 * Changing the queue size in fly is safe, if size becomes smaller
203862306a36Sopenharmony_ci	 * than current size, it will just not accept new entries until
203962306a36Sopenharmony_ci	 * it has shrank enough.
204062306a36Sopenharmony_ci	 */
204162306a36Sopenharmony_ci	dd->queue.max_qlen = value;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	return size;
204462306a36Sopenharmony_ci}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_cistatic DEVICE_ATTR_RW(queue_len);
204762306a36Sopenharmony_cistatic DEVICE_ATTR_RW(fallback);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_cistatic struct attribute *omap_sham_attrs[] = {
205062306a36Sopenharmony_ci	&dev_attr_queue_len.attr,
205162306a36Sopenharmony_ci	&dev_attr_fallback.attr,
205262306a36Sopenharmony_ci	NULL,
205362306a36Sopenharmony_ci};
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_cistatic const struct attribute_group omap_sham_attr_group = {
205662306a36Sopenharmony_ci	.attrs = omap_sham_attrs,
205762306a36Sopenharmony_ci};
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_cistatic int omap_sham_probe(struct platform_device *pdev)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	struct omap_sham_dev *dd;
206262306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
206362306a36Sopenharmony_ci	struct resource res;
206462306a36Sopenharmony_ci	dma_cap_mask_t mask;
206562306a36Sopenharmony_ci	int err, i, j;
206662306a36Sopenharmony_ci	u32 rev;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	dd = devm_kzalloc(dev, sizeof(struct omap_sham_dev), GFP_KERNEL);
206962306a36Sopenharmony_ci	if (dd == NULL) {
207062306a36Sopenharmony_ci		dev_err(dev, "unable to alloc data struct.\n");
207162306a36Sopenharmony_ci		err = -ENOMEM;
207262306a36Sopenharmony_ci		goto data_err;
207362306a36Sopenharmony_ci	}
207462306a36Sopenharmony_ci	dd->dev = dev;
207562306a36Sopenharmony_ci	platform_set_drvdata(pdev, dd);
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	INIT_LIST_HEAD(&dd->list);
207862306a36Sopenharmony_ci	tasklet_init(&dd->done_task, omap_sham_done_task, (unsigned long)dd);
207962306a36Sopenharmony_ci	crypto_init_queue(&dd->queue, OMAP_SHAM_QUEUE_LENGTH);
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	err = (dev->of_node) ? omap_sham_get_res_of(dd, dev, &res) :
208262306a36Sopenharmony_ci			       omap_sham_get_res_pdev(dd, pdev, &res);
208362306a36Sopenharmony_ci	if (err)
208462306a36Sopenharmony_ci		goto data_err;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	dd->io_base = devm_ioremap_resource(dev, &res);
208762306a36Sopenharmony_ci	if (IS_ERR(dd->io_base)) {
208862306a36Sopenharmony_ci		err = PTR_ERR(dd->io_base);
208962306a36Sopenharmony_ci		goto data_err;
209062306a36Sopenharmony_ci	}
209162306a36Sopenharmony_ci	dd->phys_base = res.start;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	err = devm_request_irq(dev, dd->irq, dd->pdata->intr_hdlr,
209462306a36Sopenharmony_ci			       IRQF_TRIGGER_NONE, dev_name(dev), dd);
209562306a36Sopenharmony_ci	if (err) {
209662306a36Sopenharmony_ci		dev_err(dev, "unable to request irq %d, err = %d\n",
209762306a36Sopenharmony_ci			dd->irq, err);
209862306a36Sopenharmony_ci		goto data_err;
209962306a36Sopenharmony_ci	}
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	dma_cap_zero(mask);
210262306a36Sopenharmony_ci	dma_cap_set(DMA_SLAVE, mask);
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	dd->dma_lch = dma_request_chan(dev, "rx");
210562306a36Sopenharmony_ci	if (IS_ERR(dd->dma_lch)) {
210662306a36Sopenharmony_ci		err = PTR_ERR(dd->dma_lch);
210762306a36Sopenharmony_ci		if (err == -EPROBE_DEFER)
210862306a36Sopenharmony_ci			goto data_err;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci		dd->polling_mode = 1;
211162306a36Sopenharmony_ci		dev_dbg(dev, "using polling mode instead of dma\n");
211262306a36Sopenharmony_ci	}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	dd->flags |= dd->pdata->flags;
211562306a36Sopenharmony_ci	sham.flags |= dd->pdata->flags;
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	pm_runtime_use_autosuspend(dev);
211862306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, DEFAULT_AUTOSUSPEND_DELAY);
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	dd->fallback_sz = OMAP_SHA_DMA_THRESHOLD;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	pm_runtime_enable(dev);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	err = pm_runtime_resume_and_get(dev);
212562306a36Sopenharmony_ci	if (err < 0) {
212662306a36Sopenharmony_ci		dev_err(dev, "failed to get sync: %d\n", err);
212762306a36Sopenharmony_ci		goto err_pm;
212862306a36Sopenharmony_ci	}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	rev = omap_sham_read(dd, SHA_REG_REV(dd));
213162306a36Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	dev_info(dev, "hw accel on OMAP rev %u.%u\n",
213462306a36Sopenharmony_ci		(rev & dd->pdata->major_mask) >> dd->pdata->major_shift,
213562306a36Sopenharmony_ci		(rev & dd->pdata->minor_mask) >> dd->pdata->minor_shift);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	spin_lock_bh(&sham.lock);
213862306a36Sopenharmony_ci	list_add_tail(&dd->list, &sham.dev_list);
213962306a36Sopenharmony_ci	spin_unlock_bh(&sham.lock);
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	dd->engine = crypto_engine_alloc_init(dev, 1);
214262306a36Sopenharmony_ci	if (!dd->engine) {
214362306a36Sopenharmony_ci		err = -ENOMEM;
214462306a36Sopenharmony_ci		goto err_engine;
214562306a36Sopenharmony_ci	}
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	err = crypto_engine_start(dd->engine);
214862306a36Sopenharmony_ci	if (err)
214962306a36Sopenharmony_ci		goto err_engine_start;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	for (i = 0; i < dd->pdata->algs_info_size; i++) {
215262306a36Sopenharmony_ci		if (dd->pdata->algs_info[i].registered)
215362306a36Sopenharmony_ci			break;
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci		for (j = 0; j < dd->pdata->algs_info[i].size; j++) {
215662306a36Sopenharmony_ci			struct ahash_engine_alg *ealg;
215762306a36Sopenharmony_ci			struct ahash_alg *alg;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci			ealg = &dd->pdata->algs_info[i].algs_list[j];
216062306a36Sopenharmony_ci			alg = &ealg->base;
216162306a36Sopenharmony_ci			alg->export = omap_sham_export;
216262306a36Sopenharmony_ci			alg->import = omap_sham_import;
216362306a36Sopenharmony_ci			alg->halg.statesize = sizeof(struct omap_sham_reqctx) +
216462306a36Sopenharmony_ci					      BUFLEN;
216562306a36Sopenharmony_ci			err = crypto_engine_register_ahash(ealg);
216662306a36Sopenharmony_ci			if (err)
216762306a36Sopenharmony_ci				goto err_algs;
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci			dd->pdata->algs_info[i].registered++;
217062306a36Sopenharmony_ci		}
217162306a36Sopenharmony_ci	}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	err = sysfs_create_group(&dev->kobj, &omap_sham_attr_group);
217462306a36Sopenharmony_ci	if (err) {
217562306a36Sopenharmony_ci		dev_err(dev, "could not create sysfs device attrs\n");
217662306a36Sopenharmony_ci		goto err_algs;
217762306a36Sopenharmony_ci	}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	return 0;
218062306a36Sopenharmony_ci
218162306a36Sopenharmony_cierr_algs:
218262306a36Sopenharmony_ci	for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
218362306a36Sopenharmony_ci		for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--)
218462306a36Sopenharmony_ci			crypto_engine_unregister_ahash(
218562306a36Sopenharmony_ci					&dd->pdata->algs_info[i].algs_list[j]);
218662306a36Sopenharmony_cierr_engine_start:
218762306a36Sopenharmony_ci	crypto_engine_exit(dd->engine);
218862306a36Sopenharmony_cierr_engine:
218962306a36Sopenharmony_ci	spin_lock_bh(&sham.lock);
219062306a36Sopenharmony_ci	list_del(&dd->list);
219162306a36Sopenharmony_ci	spin_unlock_bh(&sham.lock);
219262306a36Sopenharmony_cierr_pm:
219362306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(dev);
219462306a36Sopenharmony_ci	pm_runtime_disable(dev);
219562306a36Sopenharmony_ci	if (!dd->polling_mode)
219662306a36Sopenharmony_ci		dma_release_channel(dd->dma_lch);
219762306a36Sopenharmony_cidata_err:
219862306a36Sopenharmony_ci	dev_err(dev, "initialization failed.\n");
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	return err;
220162306a36Sopenharmony_ci}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_cistatic int omap_sham_remove(struct platform_device *pdev)
220462306a36Sopenharmony_ci{
220562306a36Sopenharmony_ci	struct omap_sham_dev *dd;
220662306a36Sopenharmony_ci	int i, j;
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	dd = platform_get_drvdata(pdev);
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	spin_lock_bh(&sham.lock);
221162306a36Sopenharmony_ci	list_del(&dd->list);
221262306a36Sopenharmony_ci	spin_unlock_bh(&sham.lock);
221362306a36Sopenharmony_ci	for (i = dd->pdata->algs_info_size - 1; i >= 0; i--)
221462306a36Sopenharmony_ci		for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) {
221562306a36Sopenharmony_ci			crypto_engine_unregister_ahash(
221662306a36Sopenharmony_ci					&dd->pdata->algs_info[i].algs_list[j]);
221762306a36Sopenharmony_ci			dd->pdata->algs_info[i].registered--;
221862306a36Sopenharmony_ci		}
221962306a36Sopenharmony_ci	tasklet_kill(&dd->done_task);
222062306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
222162306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	if (!dd->polling_mode)
222462306a36Sopenharmony_ci		dma_release_channel(dd->dma_lch);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	sysfs_remove_group(&dd->dev->kobj, &omap_sham_attr_group);
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	return 0;
222962306a36Sopenharmony_ci}
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_cistatic struct platform_driver omap_sham_driver = {
223262306a36Sopenharmony_ci	.probe	= omap_sham_probe,
223362306a36Sopenharmony_ci	.remove	= omap_sham_remove,
223462306a36Sopenharmony_ci	.driver	= {
223562306a36Sopenharmony_ci		.name	= "omap-sham",
223662306a36Sopenharmony_ci		.of_match_table	= omap_sham_of_match,
223762306a36Sopenharmony_ci	},
223862306a36Sopenharmony_ci};
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_cimodule_platform_driver(omap_sham_driver);
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ciMODULE_DESCRIPTION("OMAP SHA1/MD5 hw acceleration support.");
224362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
224462306a36Sopenharmony_ciMODULE_AUTHOR("Dmitry Kasatkin");
224562306a36Sopenharmony_ciMODULE_ALIAS("platform:omap-sham");
2246