[Linux-stm32] [PATCH 6/7] crypto: stm32/hash: Support Ux500 hash

Lionel DEBIEVE lionel.debieve at foss.st.com
Tue Jan 3 09:00:51 UTC 2023


On 12/28/22 00:03, Linus Walleij wrote:

> The Ux500 has a hash block which is an ancestor to the STM32
> hash block. With some minor code path additions we can
> support also this variant in the STM32 driver. Differences:
>
> - Ux500 only supports SHA1 and SHA256 (+/- MAC) so we split
>    up the algorithm registration per-algorithm and register
>    each algorithm along with its MAC variant separately.
>
> - Ux500 does not have an interrupt to indicate that hash
>    calculation is complete, so we add code paths to handle
>    polling for completion if the interrupt is missing in the
>    device tree.
>
> - Ux500 is lacking the SR status register, to check if an
>    operating is complete, we need to poll the HASH_STR_DCAL
>    bit in the HASH_STR register instead.
>
> - Ux500 had the resulting has at address offset 0x0c and
>    8 32bit registers ahead. We account for this with a special
>    code path when reading out the hash digest.
>
> - Ux500 need a special bit set in the control register before
>    performing the final hash calculation on an empty message.
>
> - Ux500 hashes on empty messages will be performed if the
>    above bit is set, but are incorrect. For this reason we
>    just make an inline synchronous hash using a fallback
>    hash.
>
> Tested on the Ux500 Golden device with the extended tests.
>
> Signed-off-by: Linus Walleij<linus.walleij at linaro.org>
> ---
>   drivers/crypto/stm32/stm32-hash.c | 231 ++++++++++++++++++++++++++++++++------
>   1 file changed, 197 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c
> index 92b2d55d6e93..5dd7308f8adb 100644
> --- a/drivers/crypto/stm32/stm32-hash.c
> +++ b/drivers/crypto/stm32/stm32-hash.c
> @@ -32,9 +32,11 @@
>   #define HASH_CR				0x00
>   #define HASH_DIN			0x04
>   #define HASH_STR			0x08
> +#define HASH_UX500_HREG(x)		(0x0c + ((x) * 0x04))
>   #define HASH_IMR			0x20
>   #define HASH_SR				0x24
>   #define HASH_CSR(x)			(0x0F8 + ((x) * 0x04))
> +

Remove empty line

>   #define HASH_HREG(x)			(0x310 + ((x) * 0x04))
>   #define HASH_HWCFGR			0x3F0
>   #define HASH_VER			0x3F4
> @@ -54,6 +56,10 @@
>   #define HASH_CR_ALGO_SHA224		0x40000
>   #define HASH_CR_ALGO_SHA256		0x40080
>   
> +#define HASH_CR_UX500_EMPTYMSG		BIT(20)
> +#define HASH_CR_UX500_ALGO_SHA1		BIT(7)
> +#define HASH_CR_UX500_ALGO_SHA256	0x0
> +
>   /* Interrupt */
>   #define HASH_DINIE			BIT(0)
>   #define HASH_DCIE			BIT(1)
> @@ -157,6 +163,10 @@ struct stm32_hash_algs_info {
>   struct stm32_hash_pdata {
>   	struct stm32_hash_algs_info	*algs_info;
>   	size_t				algs_info_size;
> +	bool				has_sr;
> +	bool				has_mdma;
> +	bool				broken_emptymsg;
> +	bool				ux500;
>   };
>   
>   struct stm32_hash_dev {
> @@ -168,6 +178,7 @@ struct stm32_hash_dev {
>   	phys_addr_t		phys_base;
>   	bool			dma_mode;
>   	u32			dma_maxburst;
> +	bool			polled;
>   
>   	struct ahash_request	*req;
>   	struct crypto_engine	*engine;
> @@ -208,6 +219,11 @@ static inline int stm32_hash_wait_busy(struct stm32_hash_dev *hdev)
>   {
>   	u32 status;
>   
> +	/* The Ux500 lacks the special status register, we poll the DCAL bit instead */
> +	if (!hdev->pdata->has_sr)
> +		return readl_relaxed_poll_timeout(hdev->io_base + HASH_STR, status,
> +						  !(status & HASH_STR_DCAL), 10, 10000);
> +
>   	return readl_relaxed_poll_timeout(hdev->io_base + HASH_SR, status,
>   				   !(status & HASH_SR_BUSY), 10, 10000);
>   }
> @@ -249,7 +265,7 @@ static int stm32_hash_write_key(struct stm32_hash_dev *hdev)
>   	return 0;
>   }
>   
> -static void stm32_hash_write_ctrl(struct stm32_hash_dev *hdev)
> +static void stm32_hash_write_ctrl(struct stm32_hash_dev *hdev, int bufcnt)
>   {
>   	struct stm32_hash_request_ctx *rctx = ahash_request_ctx(hdev->req);
>   	struct crypto_ahash *tfm = crypto_ahash_reqtfm(hdev->req);
> @@ -263,13 +279,19 @@ static void stm32_hash_write_ctrl(struct stm32_hash_dev *hdev)
>   			reg |= HASH_CR_ALGO_MD5;
>   			break;
>   		case HASH_FLAGS_SHA1:
> -			reg |= HASH_CR_ALGO_SHA1;
> +			if (hdev->pdata->ux500)
> +				reg |= HASH_CR_UX500_ALGO_SHA1;
> +			else
> +				reg |= HASH_CR_ALGO_SHA1;
>   			break;
>   		case HASH_FLAGS_SHA224:
>   			reg |= HASH_CR_ALGO_SHA224;
>   			break;
>   		case HASH_FLAGS_SHA256:
> -			reg |= HASH_CR_ALGO_SHA256;
> +			if (hdev->pdata->ux500)
> +				reg |= HASH_CR_UX500_ALGO_SHA256;
> +			else
> +				reg |= HASH_CR_ALGO_SHA256;
>   			break;
>   		default:
>   			reg |= HASH_CR_ALGO_MD5;
> @@ -284,7 +306,15 @@ static void stm32_hash_write_ctrl(struct stm32_hash_dev *hdev)
>   				reg |= HASH_CR_LKEY;
>   		}
>   
> -		stm32_hash_write(hdev, HASH_IMR, HASH_DCIE);
> +		/*
> +		 * On the Ux500 we need to set a special flag to indicate that
> +		 * the message is zero length.
> +		 */
> +		if (hdev->pdata->ux500 && bufcnt == 0)
> +			reg |= HASH_CR_UX500_EMPTYMSG;
> +
> +		if (!hdev->polled)
> +			stm32_hash_write(hdev, HASH_IMR, HASH_DCIE);
>   
>   		stm32_hash_write(hdev, HASH_CR, reg);
>   
> @@ -345,7 +375,7 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev,
>   
>   	hdev->flags |= HASH_FLAGS_CPU;
>   
> -	stm32_hash_write_ctrl(hdev);
> +	stm32_hash_write_ctrl(hdev, length);
>   
>   	if (stm32_hash_wait_busy(hdev))
>   		return -ETIMEDOUT;
> @@ -366,6 +396,7 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev,
>   			return -ETIMEDOUT;
>   
>   		stm32_hash_set_nblw(hdev, length);
> +

Remove empty line

>   		reg = stm32_hash_read(hdev, HASH_STR);
>   		reg |= HASH_STR_DCAL;
>   		stm32_hash_write(hdev, HASH_STR, reg);
> @@ -403,6 +434,14 @@ static int stm32_hash_update_cpu(struct stm32_hash_dev *hdev)
>   		bufcnt = rctx->bufcnt;
>   		rctx->bufcnt = 0;
>   		err = stm32_hash_xmit_cpu(hdev, rctx->buffer, bufcnt, 1);
> +
> +		/* If we have an IRQ, wait for that, else poll for completion */
> +		if (hdev->polled) {
> +			if (stm32_hash_wait_busy(hdev))
> +				return -ETIMEDOUT;
> +			hdev->flags |= HASH_FLAGS_OUTPUT_READY;
> +			err = 0;
> +		}
>   	}
>   
>   	return err;
> @@ -433,11 +472,12 @@ static int stm32_hash_xmit_dma(struct stm32_hash_dev *hdev,
>   
>   	reg = stm32_hash_read(hdev, HASH_CR);
>   
> -	if (mdma)
> -		reg |= HASH_CR_MDMAT;
> -	else
> -		reg &= ~HASH_CR_MDMAT;
> -
> +	if (!hdev->pdata->has_mdma) {
> +		if (mdma)
> +			reg |= HASH_CR_MDMAT;
> +		else
> +			reg &= ~HASH_CR_MDMAT;
> +	}
>   	reg |= HASH_CR_DMAE;
>   
>   	stm32_hash_write(hdev, HASH_CR, reg);
> @@ -558,7 +598,7 @@ static int stm32_hash_dma_send(struct stm32_hash_dev *hdev)
>   	if (rctx->nents < 0)
>   		return -EINVAL;
>   
> -	stm32_hash_write_ctrl(hdev);
> +	stm32_hash_write_ctrl(hdev, rctx->total);
>   
>   	if (hdev->flags & HASH_FLAGS_HMAC) {
>   		err = stm32_hash_hmac_dma_send(hdev);
> @@ -745,16 +785,75 @@ static int stm32_hash_final_req(struct stm32_hash_dev *hdev)
>   	else
>   		err = stm32_hash_xmit_cpu(hdev, rctx->buffer, buflen, 1);
>   
> +	/* If we have an IRQ, wait for that, else poll for completion */
> +	if (hdev->polled) {
> +		if (stm32_hash_wait_busy(hdev))
> +			return -ETIMEDOUT;
> +		hdev->flags |= HASH_FLAGS_OUTPUT_READY;
> +		/* Caller will call stm32_hash_finish_req() */
> +		err = 0;
> +	}
>   
>   	return err;
>   }
>   
> +static void stm32_hash_emptymsg_fallback(struct ahash_request *req)
> +{
> +	struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
> +	struct stm32_hash_ctx *ctx = crypto_ahash_ctx(ahash);
> +	struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req);
> +	struct stm32_hash_dev *hdev = rctx->hdev;
> +	struct crypto_shash *xtfm;
> +	struct shash_desc *sdesc;
> +	size_t len;
> +	int ret;
> +
> +	dev_dbg(hdev->dev, "use fallback message size 0 key size %d\n", ctx->keylen);
> +	xtfm = crypto_alloc_shash(crypto_ahash_alg_name(ahash),
> +				  0, CRYPTO_ALG_NEED_FALLBACK);
> +	if (IS_ERR(xtfm)) {
> +		dev_err(hdev->dev, "failed to allocate syncronous fallback\n");

s/syncronous/synchronous

> +		return;
> +	}
> +
> +	len = sizeof(*sdesc) + crypto_shash_descsize(xtfm);
> +	sdesc = kmalloc(len, GFP_KERNEL);
> +	if (!sdesc)
> +		goto err_hashkey_sdesc;
> +	sdesc->tfm = xtfm;
> +
> +	if (ctx->keylen) {
> +		ret = crypto_shash_setkey(xtfm, ctx->key, ctx->keylen);
> +		if (ret) {
> +			dev_err(hdev->dev, "failed to set key ret=%d\n", ret);
> +			goto err_hashkey_sdesc;

Must call err_hashkey here.

> +		}
> +	}
> +
> +	ret = crypto_shash_init(sdesc);
> +	if (ret) {
> +		dev_err(hdev->dev, "shash init error ret=%d\n", ret);
> +		goto err_hashkey;
> +	}

Add empty line here

> +	ret = crypto_shash_finup(sdesc, NULL, 0, rctx->digest);
> +	if (ret)
> +		dev_err(hdev->dev, "shash finup error\n");
> +err_hashkey:
> +	kfree(sdesc);
> +err_hashkey_sdesc:
> +	crypto_free_shash(xtfm);
> +}
> +
>   static void stm32_hash_copy_hash(struct ahash_request *req)
>   {
>   	struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req);
> +	struct stm32_hash_dev *hdev = rctx->hdev;
>   	__be32 *hash = (void *)rctx->digest;
>   	unsigned int i, hashsize;
>   
> +	if (hdev->pdata->broken_emptymsg && !req->nbytes)
> +		return stm32_hash_emptymsg_fallback(req);
> +
>   	switch (rctx->flags & HASH_FLAGS_ALGO_MASK) {
>   	case HASH_FLAGS_MD5:
>   		hashsize = MD5_DIGEST_SIZE;
> @@ -772,9 +871,14 @@ static void stm32_hash_copy_hash(struct ahash_request *req)
>   		return;
>   	}
>   
> -	for (i = 0; i < hashsize / sizeof(u32); i++)
> -		hash[i] = cpu_to_be32(stm32_hash_read(rctx->hdev,
> -						      HASH_HREG(i)));
> +	for (i = 0; i < hashsize / sizeof(u32); i++) {
> +		if (hdev->pdata->ux500)
> +			hash[i] = cpu_to_be32(stm32_hash_read(hdev,
> +					      HASH_UX500_HREG(i)));
> +		else
> +			hash[i] = cpu_to_be32(stm32_hash_read(hdev,
> +					      HASH_HREG(i)));
> +	}
>   }
>   
>   static int stm32_hash_finish(struct ahash_request *req)
> @@ -977,7 +1081,8 @@ static int stm32_hash_export(struct ahash_request *req, void *out)
>   
>   	preg = rctx->hw_context;
>   
> -	*preg++ = stm32_hash_read(hdev, HASH_IMR);
> +	if (!hdev->pdata->ux500)
> +		*preg++ = stm32_hash_read(hdev, HASH_IMR);
>   	*preg++ = stm32_hash_read(hdev, HASH_STR);
>   	*preg++ = stm32_hash_read(hdev, HASH_CR);
>   	for (i = 0; i < HASH_CSR_REGISTER_NUMBER; i++)
> @@ -1006,7 +1111,8 @@ static int stm32_hash_import(struct ahash_request *req, const void *in)
>   
>   	pm_runtime_get_sync(hdev->dev);
>   
> -	stm32_hash_write(hdev, HASH_IMR, *preg++);
> +	if (!hdev->pdata->ux500)
> +		stm32_hash_write(hdev, HASH_IMR, *preg++);
>   	stm32_hash_write(hdev, HASH_STR, *preg++);
>   	stm32_hash_write(hdev, HASH_CR, *preg);
>   	reg = *preg++ | HASH_CR_INIT;
> @@ -1125,7 +1231,7 @@ static irqreturn_t stm32_hash_irq_handler(int irq, void *dev_id)
>   	return IRQ_NONE;
>   }
>   
> -static struct ahash_alg algs_md5_sha1[] = {
> +static struct ahash_alg algs_md5[] = {
>   	{
>   		.init = stm32_hash_init,
>   		.update = stm32_hash_update,
> @@ -1177,6 +1283,9 @@ static struct ahash_alg algs_md5_sha1[] = {
>   			}
>   		}
>   	},
> +};
> +
> +static struct ahash_alg algs_sha1[] = {
>   	{
>   		.init = stm32_hash_init,
>   		.update = stm32_hash_update,
> @@ -1230,7 +1339,7 @@ static struct ahash_alg algs_md5_sha1[] = {
>   	},
>   };
>   
> -static struct ahash_alg algs_sha224_sha256[] = {
> +static struct ahash_alg algs_sha224[] = {
>   	{
>   		.init = stm32_hash_init,
>   		.update = stm32_hash_update,
> @@ -1282,6 +1391,9 @@ static struct ahash_alg algs_sha224_sha256[] = {
>   			}
>   		}
>   	},
> +};
> +
> +static struct ahash_alg algs_sha256[] = {
>   	{
>   		.init = stm32_hash_init,
>   		.update = stm32_hash_update,
> @@ -1374,35 +1486,73 @@ static int stm32_hash_unregister_algs(struct stm32_hash_dev *hdev)
>   	return 0;
>   }
>   
> +static struct stm32_hash_algs_info stm32_hash_algs_info_ux500[] = {
> +	{
> +		.algs_list	= algs_sha1,
> +		.size		= ARRAY_SIZE(algs_sha1),
> +	},
> +	{
> +		.algs_list	= algs_sha256,
> +		.size		= ARRAY_SIZE(algs_sha256),
> +	},
> +};
> +
> +static const struct stm32_hash_pdata stm32_hash_pdata_ux500 = {
> +	.algs_info	= stm32_hash_algs_info_ux500,
> +	.algs_info_size	= ARRAY_SIZE(stm32_hash_algs_info_ux500),
> +	.broken_emptymsg = true,
> +	.ux500		= true,
> +};
> +
>   static struct stm32_hash_algs_info stm32_hash_algs_info_stm32f4[] = {
>   	{
> -		.algs_list	= algs_md5_sha1,
> -		.size		= ARRAY_SIZE(algs_md5_sha1),
> +		.algs_list	= algs_md5,
> +		.size		= ARRAY_SIZE(algs_md5),
> +	},
> +	{
> +		.algs_list	= algs_sha1,
> +		.size		= ARRAY_SIZE(algs_sha1),
>   	},
>   };
>   
>   static const struct stm32_hash_pdata stm32_hash_pdata_stm32f4 = {
>   	.algs_info	= stm32_hash_algs_info_stm32f4,
>   	.algs_info_size	= ARRAY_SIZE(stm32_hash_algs_info_stm32f4),
> +	.has_sr		= true,
> +	.has_mdma	= true,
>   };
>   
>   static struct stm32_hash_algs_info stm32_hash_algs_info_stm32f7[] = {
>   	{
> -		.algs_list	= algs_md5_sha1,
> -		.size		= ARRAY_SIZE(algs_md5_sha1),
> +		.algs_list	= algs_md5,
> +		.size		= ARRAY_SIZE(algs_md5),
> +	},
> +	{
> +		.algs_list	= algs_sha1,
> +		.size		= ARRAY_SIZE(algs_sha1),
> +	},
> +	{
> +		.algs_list	= algs_sha224,
> +		.size		= ARRAY_SIZE(algs_sha224),
>   	},
>   	{
> -		.algs_list	= algs_sha224_sha256,
> -		.size		= ARRAY_SIZE(algs_sha224_sha256),
> +		.algs_list	= algs_sha256,
> +		.size		= ARRAY_SIZE(algs_sha256),
>   	},
>   };
>   
>   static const struct stm32_hash_pdata stm32_hash_pdata_stm32f7 = {
>   	.algs_info	= stm32_hash_algs_info_stm32f7,
>   	.algs_info_size	= ARRAY_SIZE(stm32_hash_algs_info_stm32f7),
> +	.has_sr		= true,
> +	.has_mdma	= true,

Initial my fault but prefer to call it mdmat rather than mdma which is the DMA name on STM32MP15

>   };
>   
>   static const struct of_device_id stm32_hash_of_match[] = {
> +	{
> +		.compatible = "stericsson,ux500-hash",
> +		.data = &stm32_hash_pdata_ux500,
> +	},
>   	{
>   		.compatible = "st,stm32f456-hash",
>   		.data = &stm32_hash_pdata_stm32f4,
> @@ -1456,16 +1606,23 @@ static int stm32_hash_probe(struct platform_device *pdev)
>   	if (ret)
>   		return ret;
>   
> -	irq = platform_get_irq(pdev, 0);
> -	if (irq < 0)
> +	irq = platform_get_irq_optional(pdev, 0);
> +	if (irq < 0 && irq != -ENXIO)
>   		return irq;
>   
> -	ret = devm_request_threaded_irq(dev, irq, stm32_hash_irq_handler,
> -					stm32_hash_irq_thread, IRQF_ONESHOT,
> -					dev_name(dev), hdev);
> -	if (ret) {
> -		dev_err(dev, "Cannot grab IRQ\n");
> -		return ret;
> +	if (irq > 0) {
> +		ret = devm_request_threaded_irq(dev, irq,
> +						stm32_hash_irq_handler,
> +						stm32_hash_irq_thread,
> +						IRQF_ONESHOT,
> +						dev_name(dev), hdev);
> +		if (ret) {
> +			dev_err(dev, "Cannot grab IRQ\n");
> +			return ret;
> +		}
> +	} else {
> +		dev_info(dev, "No IRQ, use polling mode\n");
> +		hdev->polled = true;
>   	}
>   
>   	hdev->clk = devm_clk_get(&pdev->dev, NULL);
> @@ -1507,9 +1664,11 @@ static int stm32_hash_probe(struct platform_device *pdev)
>   	case 0:
>   		break;
>   	case -ENOENT:
> -		dev_dbg(dev, "DMA mode not available\n");
> +	case -ENODEV:
> +		dev_info(dev, "DMA mode not available\n");
>   		break;
>   	default:
> +		dev_err(dev, "DMA init error %d\n", ret);
>   		goto err_dma;
>   	}
>   
> @@ -1528,7 +1687,11 @@ static int stm32_hash_probe(struct platform_device *pdev)
>   	if (ret)
>   		goto err_engine_start;
>   
> -	hdev->dma_mode = !!stm32_hash_read(hdev, HASH_HWCFGR);
> +	if (hdev->pdata->ux500)
> +		/* FIXME: implement DMA mode for Ux500 */
> +		hdev->dma_mode = false;
> +	else
> +		hdev->dma_mode = !!stm32_hash_read(hdev, HASH_HWCFGR);
>   
>   	/* Register algos */
>   	ret = stm32_hash_register_algs(hdev);
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://st-md-mailman.stormreply.com/pipermail/linux-stm32/attachments/20230103/945f7165/attachment.html>


More information about the Linux-stm32 mailing list