diff mbox

[v2,1/4] Crypto: Crypto driver support aes/des/des3 for rk3288

Message ID 29530953.Mr1LQyjF1I@phil (mailing list archive)
State Not Applicable
Delegated to: Herbert Xu
Headers show

Commit Message

Heiko Stübner Nov. 7, 2015, 11:19 p.m. UTC
Hi Zain,

looks like my comment on v1 came later than your v2 submission,
so here it is again :-)

Am Freitag, 6. November 2015, 09:17:21 schrieb Zain Wang:
> The names registered are:
>     ecb(aes) cbc(aes) ecb(des) cbc(des) ecb(des3_ede) cbc(des3_ede)
> You can alloc tags above in your case.
> 
> And other algorithms and platforms will be added later on.
> 
> Signed-off-by: Zain Wang <zain.wang@rock-chips.com>
> ---
> 

[...]

> diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c
> new file mode 100644
> index 0000000..c2a419b
> --- /dev/null
> +++ b/drivers/crypto/rockchip/rk3288_crypto.c

[...]

> +static int rk_crypto_probe(struct platform_device *pdev)
> +{
> +	int err = 0;
> +	struct resource *res;
> +	struct device *dev = &pdev->dev;
> +	struct crypto_info_t *crypto_info;
> +

rk3288 chromebooks use the crypto-engine to validate the boot images and
seem to leave it in a half-on state. This results in an irq pending
during probe and thus a null-pointer dereference in the irq-handler, as
it runs before the crypto-device is fully initialized.

resetting the crypto block, successfull fixed that issue, so I did the
following change:

-------------------
-------------------


> +	crypto_info = devm_kzalloc(&pdev->dev,
> +				   sizeof(*crypto_info), GFP_KERNEL);
> +	if (!crypto_info)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&crypto_info->lock);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	crypto_info->reg = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(crypto_info->reg)) {
> +		err = PTR_ERR(crypto_info->reg);
> +		goto err_ioremap;
> +	}
> +
> +	crypto_info->aclk = devm_clk_get(&pdev->dev, "aclk");
> +	if (IS_ERR(crypto_info->aclk)) {
> +		err = PTR_ERR(crypto_info->aclk);
> +		goto err_ioremap;
> +	}
> +
> +	crypto_info->hclk = devm_clk_get(&pdev->dev, "hclk");
> +	if (IS_ERR(crypto_info->hclk)) {
> +		err = PTR_ERR(crypto_info->hclk);
> +		goto err_ioremap;
> +	}
> +
> +	crypto_info->sclk = devm_clk_get(&pdev->dev, "sclk");
> +	if (IS_ERR(crypto_info->sclk)) {
> +		err = PTR_ERR(crypto_info->sclk);
> +		goto err_ioremap;
> +	}
> +
> +	crypto_info->dmaclk = devm_clk_get(&pdev->dev, "apb_pclk");
> +	if (IS_ERR(crypto_info->dmaclk)) {
> +		err = PTR_ERR(crypto_info->dmaclk);
> +		goto err_ioremap;
> +	}
> +
> +	crypto_info->irq = platform_get_irq(pdev, 0);
> +	if (crypto_info->irq < 0) {
> +		dev_warn(crypto_info->dev,
> +			 "control Interrupt is not available.\n");
> +		err = crypto_info->irq;
> +		goto err_ioremap;
> +	}
> +
> +	err = devm_request_irq(&pdev->dev, crypto_info->irq, crypto_irq_handle,
> +			       IRQF_SHARED, "rk-crypto", pdev);
> +
> +	if (err) {
> +		dev_err(crypto_info->dev, "irq request failed.\n");
> +		goto err_ioremap;
> +	}
> +
> +	crypto_info->dev = &pdev->dev;
> +	platform_set_drvdata(pdev, crypto_info);
> +	crypto_p = crypto_info;
> +
> +	tasklet_init(&crypto_info->crypto_tasklet,
> +		     rk_crypto_tasklet_cb, (unsigned long)crypto_info);
> +	crypto_init_queue(&crypto_info->queue, 50);
> +
> +	crypto_info->enable_clk = rk_crypto_enable_clk;
> +	crypto_info->disable_clk = rk_crypto_disable_clk;
> +	crypto_info->load_data = rk_load_data;
> +	crypto_info->unload_data = rk_unload_data;
> +
> +	err = rk_crypto_register();
> +	if (err) {
> +		dev_err(dev, "err in register alg");
> +		goto err_reg_alg;
> +	}
> +
> +	return 0;
> +
> +err_reg_alg:
> +	free_irq(crypto_info->irq, crypto_info);
> +err_ioremap:
> +	crypto_p = NULL;
> +
> +	return err;
> +}
> +

[...]

> diff --git a/drivers/crypto/rockchip/rk3288_crypto.h b/drivers/crypto/rockchip/rk3288_crypto.h
> new file mode 100644
> index 0000000..cf4cd18
> --- /dev/null
> +++ b/drivers/crypto/rockchip/rk3288_crypto.h
> @@ -0,0 +1,222 @@

[...]

> +struct crypto_info_t {

this is highly rockchip specific, so should probably be named
        rk_crypto_info
or similar instead of a generic sounding crypto_info_t

[...]

> +	struct device			*dev;
> +	struct clk			*aclk;
> +	struct clk			*hclk;
> +	struct clk			*sclk;
> +	struct clk			*dmaclk;
> +	void __iomem			*reg;
> +	int				irq;
> +	struct crypto_queue		queue;
> +	struct tasklet_struct		crypto_tasklet;
> +	struct ablkcipher_request	*ablk_req;
> +	/* device lock */
> +	spinlock_t			lock;
> +
> +	/* the public variable */
> +	struct scatterlist		*sg_src;
> +	struct scatterlist		*sg_dst;
> +	struct scatterlist		sg_tmp;
> +	struct scatterlist		*first;
> +	unsigned int			left_bytes;
> +	void				*addr_vir;
> +	int				aligned;
> +	int				align_size;
> +	size_t				nents;
> +	unsigned int			total;
> +	unsigned int			count;
> +	u32				mode;
> +	dma_addr_t			addr_in;
> +	dma_addr_t			addr_out;
> +	int (*start)(struct crypto_info_t *dev);
> +	int (*update)(struct crypto_info_t *dev);
> +	void (*complete)(struct crypto_info_t *dev, int err);
> +	int (*enable_clk)(struct crypto_info_t *dev);
> +	void (*disable_clk)(struct crypto_info_t *dev);
> +	int (*load_data)(struct crypto_info_t *dev,
> +			 struct scatterlist *sg_src,
> +			 struct scatterlist *sg_dst);
> +	void (*unload_data)(struct crypto_info_t *dev);
> +};
> +
> +/* the private variable of cipher */
> +struct rk_cipher_ctx {
> +	struct crypto_info_t		*dev;
> +	unsigned int			keylen;
> +};
> +
> +extern struct crypto_info_t *crypto_p;
> +
> +extern struct crypto_alg rk_ecb_aes_alg;
> +extern struct crypto_alg rk_cbc_aes_alg;
> +extern struct crypto_alg rk_ecb_des_alg;
> +extern struct crypto_alg rk_cbc_des_alg;
> +extern struct crypto_alg rk_ecb_des3_ede_alg;
> +extern struct crypto_alg rk_cbc_des3_ede_alg;
> +
> +#endif
> diff --git a/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c
> new file mode 100644
> index 0000000..28b49c9
> --- /dev/null
> +++ b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c
> @@ -0,0 +1,511 @@

[...]

> +static int rk_ablk_cra_init(struct crypto_tfm *tfm)
> +{
> +	struct rk_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
> +
> +	ctx->dev = crypto_p;

please no static pointers for devices.

For example, sunxi_ss does the following to transport the core device-data
into the init function:

        struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);
        struct crypto_alg *alg = tfm->__crt_alg;
        struct sun4i_ss_alg_template *algt;

        algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto);
        op->ss = algt->ss;

so you could probably do something similar

Same of course for the other crypto_p users.


Thanks
Heiko
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Zain Wang Nov. 9, 2015, 3:46 a.m. UTC | #1
Hi Heiko,
Thanks for your serious comments always.

On 2015?11?08? 07:19, Heiko Stuebner wrote:
> Hi Zain,
>
> looks like my comment on v1 came later than your v2 submission,
> so here it is again :-)
>
> Am Freitag, 6. November 2015, 09:17:21 schrieb Zain Wang:
>> The names registered are:
>>     ecb(aes) cbc(aes) ecb(des) cbc(des) ecb(des3_ede) cbc(des3_ede)
>> You can alloc tags above in your case.
>>
>> And other algorithms and platforms will be added later on.
>>
>> Signed-off-by: Zain Wang <zain.wang@rock-chips.com>
>> ---
>>
> [...]
>
>> diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c
>> new file mode 100644
>> index 0000000..c2a419b
>> --- /dev/null
>> +++ b/drivers/crypto/rockchip/rk3288_crypto.c
> [...]
>
>> +static int rk_crypto_probe(struct platform_device *pdev)
>> +{
>> +	int err = 0;
>> +	struct resource *res;
>> +	struct device *dev = &pdev->dev;
>> +	struct crypto_info_t *crypto_info;
>> +
> rk3288 chromebooks use the crypto-engine to validate the boot images and
> seem to leave it in a half-on state. This results in an irq pending
> during probe and thus a null-pointer dereference in the irq-handler, as
> it runs before the crypto-device is fully initialized.
>
> resetting the crypto block, successfull fixed that issue, so I did the
> following change:
>
> -------------------
> diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
> index 121b6d5..e978fb2 100644
> --- a/arch/arm/boot/dts/rk3288.dtsi
> +++ b/arch/arm/boot/dts/rk3288.dtsi
> @@ -182,6 +182,8 @@
>                               "hclk",
>                               "sclk",
>                               "apb_pclk";
> +               resets = <&cru SRST_CRYPTO>;
> +               reset-names = "crypto";
>                 status = "okay";
>         };
>  
> diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c
> index 02830f2..2245d3d 100644
> --- a/drivers/crypto/rockchip/rk3288_crypto.c
> +++ b/drivers/crypto/rockchip/rk3288_crypto.c
> @@ -18,6 +18,7 @@
>  #include <linux/of.h>
>  #include <linux/clk.h>
>  #include <linux/crypto.h>
> +#include <linux/reset.h>
>  
>  struct crypto_info_t *crypto_p;
>  
> @@ -266,6 +267,15 @@ static int rk_crypto_probe(struct platform_device *pdev)
>         struct resource *res;
>         struct device *dev = &pdev->dev;
>         struct crypto_info_t *crypto_info;
> +       struct reset_control *rst;
> +
> +       /* reset the block to remove any pending actions */
> +       rst = devm_reset_control_get(dev, "crypto");
> +       if (!IS_ERR(rst)) {
> +               reset_control_assert(rst);
> +               usleep_range(10, 20);
> +               reset_control_deassert(rst);
> +       }
>  
>         crypto_info = devm_kzalloc(&pdev->dev,
>                         sizeof(*crypto_info), GFP_KERNEL);
> -------------------
>
Ok! done!
>> +	crypto_info = devm_kzalloc(&pdev->dev,
>> +				   sizeof(*crypto_info), GFP_KERNEL);
>> +	if (!crypto_info)
>> +		return -ENOMEM;
>> +
>> +	spin_lock_init(&crypto_info->lock);
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	crypto_info->reg = devm_ioremap_resource(&pdev->dev, res);
>> +	if (IS_ERR(crypto_info->reg)) {
>> +		err = PTR_ERR(crypto_info->reg);
>> +		goto err_ioremap;
>> +	}
>> +
>> +	crypto_info->aclk = devm_clk_get(&pdev->dev, "aclk");
>> +	if (IS_ERR(crypto_info->aclk)) {
>> +		err = PTR_ERR(crypto_info->aclk);
>> +		goto err_ioremap;
>> +	}
>> +
>> +	crypto_info->hclk = devm_clk_get(&pdev->dev, "hclk");
>> +	if (IS_ERR(crypto_info->hclk)) {
>> +		err = PTR_ERR(crypto_info->hclk);
>> +		goto err_ioremap;
>> +	}
>> +
>> +	crypto_info->sclk = devm_clk_get(&pdev->dev, "sclk");
>> +	if (IS_ERR(crypto_info->sclk)) {
>> +		err = PTR_ERR(crypto_info->sclk);
>> +		goto err_ioremap;
>> +	}
>> +
>> +	crypto_info->dmaclk = devm_clk_get(&pdev->dev, "apb_pclk");
>> +	if (IS_ERR(crypto_info->dmaclk)) {
>> +		err = PTR_ERR(crypto_info->dmaclk);
>> +		goto err_ioremap;
>> +	}
>> +
>> +	crypto_info->irq = platform_get_irq(pdev, 0);
>> +	if (crypto_info->irq < 0) {
>> +		dev_warn(crypto_info->dev,
>> +			 "control Interrupt is not available.\n");
>> +		err = crypto_info->irq;
>> +		goto err_ioremap;
>> +	}
>> +
>> +	err = devm_request_irq(&pdev->dev, crypto_info->irq, crypto_irq_handle,
>> +			       IRQF_SHARED, "rk-crypto", pdev);
>> +
>> +	if (err) {
>> +		dev_err(crypto_info->dev, "irq request failed.\n");
>> +		goto err_ioremap;
>> +	}
>> +
>> +	crypto_info->dev = &pdev->dev;
>> +	platform_set_drvdata(pdev, crypto_info);
>> +	crypto_p = crypto_info;
>> +
>> +	tasklet_init(&crypto_info->crypto_tasklet,
>> +		     rk_crypto_tasklet_cb, (unsigned long)crypto_info);
>> +	crypto_init_queue(&crypto_info->queue, 50);
>> +
>> +	crypto_info->enable_clk = rk_crypto_enable_clk;
>> +	crypto_info->disable_clk = rk_crypto_disable_clk;
>> +	crypto_info->load_data = rk_load_data;
>> +	crypto_info->unload_data = rk_unload_data;
>> +
>> +	err = rk_crypto_register();
>> +	if (err) {
>> +		dev_err(dev, "err in register alg");
>> +		goto err_reg_alg;
>> +	}
>> +
>> +	return 0;
>> +
>> +err_reg_alg:
>> +	free_irq(crypto_info->irq, crypto_info);
>> +err_ioremap:
>> +	crypto_p = NULL;
>> +
>> +	return err;
>> +}
>> +
> [...]
>
>> diff --git a/drivers/crypto/rockchip/rk3288_crypto.h b/drivers/crypto/rockchip/rk3288_crypto.h
>> new file mode 100644
>> index 0000000..cf4cd18
>> --- /dev/null
>> +++ b/drivers/crypto/rockchip/rk3288_crypto.h
>> @@ -0,0 +1,222 @@
> [...]
>
>> +struct crypto_info_t {
> this is highly rockchip specific, so should probably be named
>         rk_crypto_info
> or similar instead of a generic sounding crypto_info_t
Ok! Done!
>
> [...]
>
>> +	struct device			*dev;
>> +	struct clk			*aclk;
>> +	struct clk			*hclk;
>> +	struct clk			*sclk;
>> +	struct clk			*dmaclk;
>> +	void __iomem			*reg;
>> +	int				irq;
>> +	struct crypto_queue		queue;
>> +	struct tasklet_struct		crypto_tasklet;
>> +	struct ablkcipher_request	*ablk_req;
>> +	/* device lock */
>> +	spinlock_t			lock;
>> +
>> +	/* the public variable */
>> +	struct scatterlist		*sg_src;
>> +	struct scatterlist		*sg_dst;
>> +	struct scatterlist		sg_tmp;
>> +	struct scatterlist		*first;
>> +	unsigned int			left_bytes;
>> +	void				*addr_vir;
>> +	int				aligned;
>> +	int				align_size;
>> +	size_t				nents;
>> +	unsigned int			total;
>> +	unsigned int			count;
>> +	u32				mode;
>> +	dma_addr_t			addr_in;
>> +	dma_addr_t			addr_out;
>> +	int (*start)(struct crypto_info_t *dev);
>> +	int (*update)(struct crypto_info_t *dev);
>> +	void (*complete)(struct crypto_info_t *dev, int err);
>> +	int (*enable_clk)(struct crypto_info_t *dev);
>> +	void (*disable_clk)(struct crypto_info_t *dev);
>> +	int (*load_data)(struct crypto_info_t *dev,
>> +			 struct scatterlist *sg_src,
>> +			 struct scatterlist *sg_dst);
>> +	void (*unload_data)(struct crypto_info_t *dev);
>> +};
>> +
>> +/* the private variable of cipher */
>> +struct rk_cipher_ctx {
>> +	struct crypto_info_t		*dev;
>> +	unsigned int			keylen;
>> +};
>> +
>> +extern struct crypto_info_t *crypto_p;
>> +
>> +extern struct crypto_alg rk_ecb_aes_alg;
>> +extern struct crypto_alg rk_cbc_aes_alg;
>> +extern struct crypto_alg rk_ecb_des_alg;
>> +extern struct crypto_alg rk_cbc_des_alg;
>> +extern struct crypto_alg rk_ecb_des3_ede_alg;
>> +extern struct crypto_alg rk_cbc_des3_ede_alg;
>> +
>> +#endif
>> diff --git a/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c
>> new file mode 100644
>> index 0000000..28b49c9
>> --- /dev/null
>> +++ b/drivers/crypto/rockchip/rk3288_crypto_ablkcipher.c
>> @@ -0,0 +1,511 @@
> [...]
>
>> +static int rk_ablk_cra_init(struct crypto_tfm *tfm)
>> +{
>> +	struct rk_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
>> +
>> +	ctx->dev = crypto_p;
> please no static pointers for devices.
>
> For example, sunxi_ss does the following to transport the core device-data
> into the init function:
>
>         struct sun4i_tfm_ctx *op = crypto_tfm_ctx(tfm);
>         struct crypto_alg *alg = tfm->__crt_alg;
>         struct sun4i_ss_alg_template *algt;
>
>         algt = container_of(alg, struct sun4i_ss_alg_template, alg.crypto);
>         op->ss = algt->ss;
>
> so you could probably do something similar
>
> Same of course for the other crypto_p users.
Ok! Done!
>
>
> Thanks
> Heiko
>
>
>
Thanks
Zain

--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 121b6d5..e978fb2 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -182,6 +182,8 @@ 
                              "hclk",
                              "sclk",
                              "apb_pclk";
+               resets = <&cru SRST_CRYPTO>;
+               reset-names = "crypto";
                status = "okay";
        };
 
diff --git a/drivers/crypto/rockchip/rk3288_crypto.c b/drivers/crypto/rockchip/rk3288_crypto.c
index 02830f2..2245d3d 100644
--- a/drivers/crypto/rockchip/rk3288_crypto.c
+++ b/drivers/crypto/rockchip/rk3288_crypto.c
@@ -18,6 +18,7 @@ 
 #include <linux/of.h>
 #include <linux/clk.h>
 #include <linux/crypto.h>
+#include <linux/reset.h>
 
 struct crypto_info_t *crypto_p;
 
@@ -266,6 +267,15 @@  static int rk_crypto_probe(struct platform_device *pdev)
        struct resource *res;
        struct device *dev = &pdev->dev;
        struct crypto_info_t *crypto_info;
+       struct reset_control *rst;
+
+       /* reset the block to remove any pending actions */
+       rst = devm_reset_control_get(dev, "crypto");
+       if (!IS_ERR(rst)) {
+               reset_control_assert(rst);
+               usleep_range(10, 20);
+               reset_control_deassert(rst);
+       }
 
        crypto_info = devm_kzalloc(&pdev->dev,
                        sizeof(*crypto_info), GFP_KERNEL);