From 1900c583c8e24df9d07282598166279187dce832 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Fri, 15 Jan 2016 15:49:31 +0100 Subject: crypto: atmel-sha - fix crash when computing digest on empty message This patch fixes a crash which occured during the computation of the digest of an empty message. Indeed, when processing an empty message, the atmel_sha_handle_queue() function was never called, hence the dd->req pointer remained uninitialized. Later, when the atmel_sha_final_req() function was called, it used to crash while using this uninitialized dd->req pointer. Hence this patch adds missing initializations of dd->req before calls of the atmel_sha_final_req() function. This bug prevented us from passing the tcrypt test suite on SHA algo. Signed-off-by: Cyrille Pitchen Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/crypto/atmel-sha.c') diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 20de861aa0ea..006b2aefba30 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -939,6 +939,7 @@ static int atmel_sha_final(struct ahash_request *req) if (err) goto err1; + dd->req = req; dd->flags |= SHA_FLAGS_BUSY; err = atmel_sha_final_req(dd); } else { -- cgit v1.2.3 From f56809c3c6059327aad3e0718bca9c6c756386f6 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Fri, 15 Jan 2016 15:49:32 +0100 Subject: crypto: atmel-sha - fix a race between the 'done' tasklet and the crypto client The 'done' tasklet handler used to check the 'BUSY' flag to either finalize the processing of a crypto request which had just completed or manage the crypto queue to start the next crypto request. On request R1 completion, the driver calls atmel_sha_finish_req(), which: 1 - clears the 'BUSY' flag since the hardware is no longer used and is ready again to process new crypto requests. 2 - notifies the above layer (the client) about the completion of the asynchronous crypto request R1 by calling its base.complete() callback. 3 - schedules the 'done' task to check the crypto queue and start to process the next crypto request (the 'BUSY' flag is supposed to be cleared at that moment) if such a pending request exists. However step 2 might wake the client up so it can now ask our driver to process a new crypto request R2. This request is enqueued by calling the atmel_sha_handle_queue() function, which sets the 'BUSY' flags then starts to process R2. If the 'done' tasklet, scheduled by step 3, runs just after, it would see that the 'BUSY' flag is set then understand that R2 has just completed, which is wrong! So the state of 'BUSY' flag is not a proper way to detect and handle crypto request completion. This patch fixes this race condition by using two different tasklets, one to handle the crypto request completion events, the other to manage the crypto queue if needed. Signed-off-by: Cyrille Pitchen Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/crypto/atmel-sha.c') diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 006b2aefba30..75a8cbcf3121 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -122,6 +122,7 @@ struct atmel_sha_dev { spinlock_t lock; int err; struct tasklet_struct done_task; + struct tasklet_struct queue_task; unsigned long flags; struct crypto_queue queue; @@ -788,7 +789,7 @@ static void atmel_sha_finish_req(struct ahash_request *req, int err) req->base.complete(&req->base, err); /* handle new request */ - tasklet_schedule(&dd->done_task); + tasklet_schedule(&dd->queue_task); } static int atmel_sha_hw_init(struct atmel_sha_dev *dd) @@ -1101,16 +1102,18 @@ static struct ahash_alg sha_384_512_algs[] = { }, }; +static void atmel_sha_queue_task(unsigned long data) +{ + struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data; + + atmel_sha_handle_queue(dd, NULL); +} + static void atmel_sha_done_task(unsigned long data) { struct atmel_sha_dev *dd = (struct atmel_sha_dev *)data; int err = 0; - if (!(SHA_FLAGS_BUSY & dd->flags)) { - atmel_sha_handle_queue(dd, NULL); - return; - } - if (SHA_FLAGS_CPU & dd->flags) { if (SHA_FLAGS_OUTPUT_READY & dd->flags) { dd->flags &= ~SHA_FLAGS_OUTPUT_READY; @@ -1367,6 +1370,8 @@ static int atmel_sha_probe(struct platform_device *pdev) tasklet_init(&sha_dd->done_task, atmel_sha_done_task, (unsigned long)sha_dd); + tasklet_init(&sha_dd->queue_task, atmel_sha_queue_task, + (unsigned long)sha_dd); crypto_init_queue(&sha_dd->queue, ATMEL_SHA_QUEUE_LENGTH); @@ -1459,6 +1464,7 @@ err_algs: atmel_sha_dma_cleanup(sha_dd); err_sha_dma: res_err: + tasklet_kill(&sha_dd->queue_task); tasklet_kill(&sha_dd->done_task); sha_dd_err: dev_err(dev, "initialization failed.\n"); @@ -1479,6 +1485,7 @@ static int atmel_sha_remove(struct platform_device *pdev) atmel_sha_unregister_algs(sha_dd); + tasklet_kill(&sha_dd->queue_task); tasklet_kill(&sha_dd->done_task); if (sha_dd->caps.has_dma) -- cgit v1.2.3 From 507c5cc236a2d751ea423a86486a2d1972369549 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Fri, 15 Jan 2016 15:49:33 +0100 Subject: crypto: atmel-sha - add support of sama5d2x SoCs This patch adds support of hardware version 5.1.x embedded inside sama5d2x SoCs. Signed-off-by: Cyrille Pitchen Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/crypto/atmel-sha.c') diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 75a8cbcf3121..7327e11e0ccb 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -1279,6 +1279,12 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd) /* keep only major version number */ switch (dd->hw_version & 0xff0) { + case 0x510: + dd->caps.has_dma = 1; + dd->caps.has_dualbuff = 1; + dd->caps.has_sha224 = 1; + dd->caps.has_sha_384_512 = 1; + break; case 0x420: dd->caps.has_dma = 1; dd->caps.has_dualbuff = 1; -- cgit v1.2.3 From 7cee3508162a1760bc104c48d14202b01af28e53 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Fri, 15 Jan 2016 15:49:34 +0100 Subject: crypto: atmel-sha - fix context switches This patch saves the value of the internal hash register at the end of an 'update' operation then restores this value before starting the next 'update'. This way the driver can now properly handle context switches. WARNING: only hardware versions from sama5d4x and later provide the needed interface to update the internal hash value. Especially, sama5d3x cannot implement this feature so context switches are still broken. Signed-off-by: Cyrille Pitchen Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha-regs.h | 4 ++ drivers/crypto/atmel-sha.c | 105 ++++++++++++++++++++++++++++++---------- 2 files changed, 84 insertions(+), 25 deletions(-) (limited to 'drivers/crypto/atmel-sha.c') diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h index 83b2d7425666..e08897109cab 100644 --- a/drivers/crypto/atmel-sha-regs.h +++ b/drivers/crypto/atmel-sha-regs.h @@ -8,6 +8,8 @@ #define SHA_CR_START (1 << 0) #define SHA_CR_FIRST (1 << 4) #define SHA_CR_SWRST (1 << 8) +#define SHA_CR_WUIHV (1 << 12) +#define SHA_CR_WUIEHV (1 << 13) #define SHA_MR 0x04 #define SHA_MR_MODE_MASK (0x3 << 0) @@ -15,6 +17,8 @@ #define SHA_MR_MODE_AUTO 0x1 #define SHA_MR_MODE_PDC 0x2 #define SHA_MR_PROCDLY (1 << 4) +#define SHA_MR_UIHV (1 << 5) +#define SHA_MR_UIEHV (1 << 6) #define SHA_MR_ALGO_SHA1 (0 << 8) #define SHA_MR_ALGO_SHA256 (1 << 8) #define SHA_MR_ALGO_SHA384 (2 << 8) diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 7327e11e0ccb..da4c3055784f 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -53,6 +53,7 @@ #define SHA_FLAGS_FINUP BIT(16) #define SHA_FLAGS_SG BIT(17) +#define SHA_FLAGS_ALGO_MASK GENMASK(22, 18) #define SHA_FLAGS_SHA1 BIT(18) #define SHA_FLAGS_SHA224 BIT(19) #define SHA_FLAGS_SHA256 BIT(20) @@ -60,6 +61,7 @@ #define SHA_FLAGS_SHA512 BIT(22) #define SHA_FLAGS_ERROR BIT(23) #define SHA_FLAGS_PAD BIT(24) +#define SHA_FLAGS_RESTORE BIT(25) #define SHA_OP_UPDATE 1 #define SHA_OP_FINAL 2 @@ -73,6 +75,7 @@ struct atmel_sha_caps { bool has_dualbuff; bool has_sha224; bool has_sha_384_512; + bool has_uihv; }; struct atmel_sha_dev; @@ -318,7 +321,8 @@ static int atmel_sha_init(struct ahash_request *req) static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma) { struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); - u32 valcr = 0, valmr = SHA_MR_MODE_AUTO; + u32 valmr = SHA_MR_MODE_AUTO; + unsigned int i, hashsize = 0; if (likely(dma)) { if (!dd->caps.has_dma) @@ -330,22 +334,62 @@ static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma) atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY); } - if (ctx->flags & SHA_FLAGS_SHA1) + switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { + case SHA_FLAGS_SHA1: valmr |= SHA_MR_ALGO_SHA1; - else if (ctx->flags & SHA_FLAGS_SHA224) + hashsize = SHA1_DIGEST_SIZE; + break; + + case SHA_FLAGS_SHA224: valmr |= SHA_MR_ALGO_SHA224; - else if (ctx->flags & SHA_FLAGS_SHA256) + hashsize = SHA256_DIGEST_SIZE; + break; + + case SHA_FLAGS_SHA256: valmr |= SHA_MR_ALGO_SHA256; - else if (ctx->flags & SHA_FLAGS_SHA384) + hashsize = SHA256_DIGEST_SIZE; + break; + + case SHA_FLAGS_SHA384: valmr |= SHA_MR_ALGO_SHA384; - else if (ctx->flags & SHA_FLAGS_SHA512) + hashsize = SHA512_DIGEST_SIZE; + break; + + case SHA_FLAGS_SHA512: valmr |= SHA_MR_ALGO_SHA512; + hashsize = SHA512_DIGEST_SIZE; + break; + + default: + break; + } /* Setting CR_FIRST only for the first iteration */ - if (!(ctx->digcnt[0] || ctx->digcnt[1])) - valcr = SHA_CR_FIRST; + if (!(ctx->digcnt[0] || ctx->digcnt[1])) { + atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); + } else if (dd->caps.has_uihv && (ctx->flags & SHA_FLAGS_RESTORE)) { + const u32 *hash = (const u32 *)ctx->digest; + + /* + * Restore the hardware context: update the User Initialize + * Hash Value (UIHV) with the value saved when the latest + * 'update' operation completed on this very same crypto + * request. + */ + ctx->flags &= ~SHA_FLAGS_RESTORE; + atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); + for (i = 0; i < hashsize / sizeof(u32); ++i) + atmel_sha_write(dd, SHA_REG_DIN(i), hash[i]); + atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); + valmr |= SHA_MR_UIHV; + } + /* + * WARNING: If the UIHV feature is not available, the hardware CANNOT + * process concurrent requests: the internal registers used to store + * the hash/digest are still set to the partial digest output values + * computed during the latest round. + */ - atmel_sha_write(dd, SHA_CR, valcr); atmel_sha_write(dd, SHA_MR, valmr); } @@ -714,23 +758,31 @@ static void atmel_sha_copy_hash(struct ahash_request *req) { struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); u32 *hash = (u32 *)ctx->digest; - int i; + unsigned int i, hashsize; - if (ctx->flags & SHA_FLAGS_SHA1) - for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) - hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); - else if (ctx->flags & SHA_FLAGS_SHA224) - for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(u32); i++) - hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); - else if (ctx->flags & SHA_FLAGS_SHA256) - for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++) - hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); - else if (ctx->flags & SHA_FLAGS_SHA384) - for (i = 0; i < SHA384_DIGEST_SIZE / sizeof(u32); i++) - hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); - else - for (i = 0; i < SHA512_DIGEST_SIZE / sizeof(u32); i++) - hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); + switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { + case SHA_FLAGS_SHA1: + hashsize = SHA1_DIGEST_SIZE; + break; + + case SHA_FLAGS_SHA224: + case SHA_FLAGS_SHA256: + hashsize = SHA256_DIGEST_SIZE; + break; + + case SHA_FLAGS_SHA384: + case SHA_FLAGS_SHA512: + hashsize = SHA512_DIGEST_SIZE; + break; + + default: + /* Should not happen... */ + return; + } + + for (i = 0; i < hashsize / sizeof(u32); ++i) + hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); + ctx->flags |= SHA_FLAGS_RESTORE; } static void atmel_sha_copy_ready_hash(struct ahash_request *req) @@ -1276,6 +1328,7 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd) dd->caps.has_dualbuff = 0; dd->caps.has_sha224 = 0; dd->caps.has_sha_384_512 = 0; + dd->caps.has_uihv = 0; /* keep only major version number */ switch (dd->hw_version & 0xff0) { @@ -1284,12 +1337,14 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd) dd->caps.has_dualbuff = 1; dd->caps.has_sha224 = 1; dd->caps.has_sha_384_512 = 1; + dd->caps.has_uihv = 1; break; case 0x420: dd->caps.has_dma = 1; dd->caps.has_dualbuff = 1; dd->caps.has_sha224 = 1; dd->caps.has_sha_384_512 = 1; + dd->caps.has_uihv = 1; break; case 0x410: dd->caps.has_dma = 1; -- cgit v1.2.3 From cc831d32d7b1bd45c5d74c44d8e39d354049c369 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Fri, 29 Jan 2016 17:04:02 +0100 Subject: crypto: atmel-sha - fix algorihtm registration This patch implements the missing .import() and .export() mandatory hooks for asynchronous hash algorithms. It also sets the relevant, non zero, value for the .statesize field when declaring the supported SHA algorithms. Indeed a zero value of .statesize prevents the algorithm from being registered. Signed-off-by: Cyrille Pitchen Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha.c | 61 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) (limited to 'drivers/crypto/atmel-sha.c') diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index da4c3055784f..63b09e01075c 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -66,7 +66,7 @@ #define SHA_OP_UPDATE 1 #define SHA_OP_FINAL 2 -#define SHA_BUFFER_LEN PAGE_SIZE +#define SHA_BUFFER_LEN (PAGE_SIZE / 16) #define ATMEL_SHA_DMA_THRESHOLD 56 @@ -80,6 +80,17 @@ struct atmel_sha_caps { struct atmel_sha_dev; +/* + * .statesize = sizeof(struct atmel_sha_state) must be <= PAGE_SIZE / 8 as + * tested by the ahash_prepare_alg() function. + */ +struct atmel_sha_state { + u8 digest[SHA512_DIGEST_SIZE]; + u8 buffer[SHA_BUFFER_LEN]; + u64 digcnt[2]; + size_t bufcnt; +}; + struct atmel_sha_reqctx { struct atmel_sha_dev *dd; unsigned long flags; @@ -1033,6 +1044,39 @@ static int atmel_sha_digest(struct ahash_request *req) return atmel_sha_init(req) ?: atmel_sha_finup(req); } + +static int atmel_sha_export(struct ahash_request *req, void *out) +{ + const struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); + struct atmel_sha_state state; + + memcpy(state.digest, ctx->digest, SHA512_DIGEST_SIZE); + memcpy(state.buffer, ctx->buffer, ctx->bufcnt); + state.bufcnt = ctx->bufcnt; + state.digcnt[0] = ctx->digcnt[0]; + state.digcnt[1] = ctx->digcnt[1]; + + /* out might be unaligned. */ + memcpy(out, &state, sizeof(state)); + return 0; +} + +static int atmel_sha_import(struct ahash_request *req, const void *in) +{ + struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); + struct atmel_sha_state state; + + /* in might be unaligned. */ + memcpy(&state, in, sizeof(state)); + + memcpy(ctx->digest, state.digest, SHA512_DIGEST_SIZE); + memcpy(ctx->buffer, state.buffer, state.bufcnt); + ctx->bufcnt = state.bufcnt; + ctx->digcnt[0] = state.digcnt[0]; + ctx->digcnt[1] = state.digcnt[1]; + return 0; +} + static int atmel_sha_cra_init(struct crypto_tfm *tfm) { crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), @@ -1049,8 +1093,11 @@ static struct ahash_alg sha_1_256_algs[] = { .final = atmel_sha_final, .finup = atmel_sha_finup, .digest = atmel_sha_digest, + .export = atmel_sha_export, + .import = atmel_sha_import, .halg = { .digestsize = SHA1_DIGEST_SIZE, + .statesize = sizeof(struct atmel_sha_state), .base = { .cra_name = "sha1", .cra_driver_name = "atmel-sha1", @@ -1070,8 +1117,11 @@ static struct ahash_alg sha_1_256_algs[] = { .final = atmel_sha_final, .finup = atmel_sha_finup, .digest = atmel_sha_digest, + .export = atmel_sha_export, + .import = atmel_sha_import, .halg = { .digestsize = SHA256_DIGEST_SIZE, + .statesize = sizeof(struct atmel_sha_state), .base = { .cra_name = "sha256", .cra_driver_name = "atmel-sha256", @@ -1093,8 +1143,11 @@ static struct ahash_alg sha_224_alg = { .final = atmel_sha_final, .finup = atmel_sha_finup, .digest = atmel_sha_digest, + .export = atmel_sha_export, + .import = atmel_sha_import, .halg = { .digestsize = SHA224_DIGEST_SIZE, + .statesize = sizeof(struct atmel_sha_state), .base = { .cra_name = "sha224", .cra_driver_name = "atmel-sha224", @@ -1116,8 +1169,11 @@ static struct ahash_alg sha_384_512_algs[] = { .final = atmel_sha_final, .finup = atmel_sha_finup, .digest = atmel_sha_digest, + .export = atmel_sha_export, + .import = atmel_sha_import, .halg = { .digestsize = SHA384_DIGEST_SIZE, + .statesize = sizeof(struct atmel_sha_state), .base = { .cra_name = "sha384", .cra_driver_name = "atmel-sha384", @@ -1137,8 +1193,11 @@ static struct ahash_alg sha_384_512_algs[] = { .final = atmel_sha_final, .finup = atmel_sha_finup, .digest = atmel_sha_digest, + .export = atmel_sha_export, + .import = atmel_sha_import, .halg = { .digestsize = SHA512_DIGEST_SIZE, + .statesize = sizeof(struct atmel_sha_state), .base = { .cra_name = "sha512", .cra_driver_name = "atmel-sha512", -- cgit v1.2.3 From d961436c11482e974b702c8324426208f00cd7c4 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Fri, 5 Feb 2016 13:45:12 +0100 Subject: crypto: atmel-sha - fix atmel_sha_remove() Since atmel_sha_probe() uses devm_xxx functions to allocate resources, atmel_sha_remove() should no longer explicitly release them. Cc: stable@vger.kernel.org Signed-off-by: Cyrille Pitchen Fixes: b0e8b3417a62 ("crypto: atmel - use devm_xxx() managed function") Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/crypto/atmel-sha.c') diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 20de861aa0ea..b5ab7400008d 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -1483,13 +1483,6 @@ static int atmel_sha_remove(struct platform_device *pdev) if (sha_dd->caps.has_dma) atmel_sha_dma_cleanup(sha_dd); - iounmap(sha_dd->io_base); - - clk_put(sha_dd->iclk); - - if (sha_dd->irq >= 0) - free_irq(sha_dd->irq, sha_dd); - return 0; } -- cgit v1.2.3 From c033042aa8f69894df37dabcaa0231594834a4e4 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Fri, 5 Feb 2016 13:45:13 +0100 Subject: crypto: atmel-sha - remove calls of clk_prepare() from atomic contexts clk_prepare()/clk_unprepare() must not be called within atomic context. This patch calls clk_prepare() once for all from atmel_sha_probe() and clk_unprepare() from atmel_sha_remove(). Then calls of clk_prepare_enable()/clk_disable_unprepare() were replaced by calls of clk_enable()/clk_disable(). Cc: stable@vger.kernel.org Signed-off-by: Cyrille Pitchen Reported-by: Matthias Mayr Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/crypto/atmel-sha.c') diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index b5ab7400008d..8bf9914d4d15 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -782,7 +782,7 @@ static void atmel_sha_finish_req(struct ahash_request *req, int err) dd->flags &= ~(SHA_FLAGS_BUSY | SHA_FLAGS_FINAL | SHA_FLAGS_CPU | SHA_FLAGS_DMA_READY | SHA_FLAGS_OUTPUT_READY); - clk_disable_unprepare(dd->iclk); + clk_disable(dd->iclk); if (req->base.complete) req->base.complete(&req->base, err); @@ -795,7 +795,7 @@ static int atmel_sha_hw_init(struct atmel_sha_dev *dd) { int err; - err = clk_prepare_enable(dd->iclk); + err = clk_enable(dd->iclk); if (err) return err; @@ -822,7 +822,7 @@ static void atmel_sha_hw_version_init(struct atmel_sha_dev *dd) dev_info(dd->dev, "version: 0x%x\n", dd->hw_version); - clk_disable_unprepare(dd->iclk); + clk_disable(dd->iclk); } static int atmel_sha_handle_queue(struct atmel_sha_dev *dd, @@ -1410,6 +1410,10 @@ static int atmel_sha_probe(struct platform_device *pdev) goto res_err; } + err = clk_prepare(sha_dd->iclk); + if (err) + goto res_err; + atmel_sha_hw_version_init(sha_dd); atmel_sha_get_cap(sha_dd); @@ -1421,12 +1425,12 @@ static int atmel_sha_probe(struct platform_device *pdev) if (IS_ERR(pdata)) { dev_err(&pdev->dev, "platform data not available\n"); err = PTR_ERR(pdata); - goto res_err; + goto iclk_unprepare; } } if (!pdata->dma_slave) { err = -ENXIO; - goto res_err; + goto iclk_unprepare; } err = atmel_sha_dma_init(sha_dd, pdata); if (err) @@ -1457,6 +1461,8 @@ err_algs: if (sha_dd->caps.has_dma) atmel_sha_dma_cleanup(sha_dd); err_sha_dma: +iclk_unprepare: + clk_unprepare(sha_dd->iclk); res_err: tasklet_kill(&sha_dd->done_task); sha_dd_err: @@ -1483,6 +1489,8 @@ static int atmel_sha_remove(struct platform_device *pdev) if (sha_dd->caps.has_dma) atmel_sha_dma_cleanup(sha_dd); + clk_unprepare(sha_dd->iclk); + return 0; } -- cgit v1.2.3 From 9c4274d90d2923dda7435073de6494f0250ccb5a Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 8 Feb 2016 16:26:48 +0100 Subject: crypto: atmel-sha - fix .import()/.export() implementation Using only the digest, digcnt[], bufcnt and buffer[] fields of the struct atmel_sha_reqctx was not enough to import/export the request state, so now we use the whole structure. Signed-off-by: Cyrille Pitchen Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha.c | 44 ++++++++++---------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) (limited to 'drivers/crypto/atmel-sha.c') diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 63b09e01075c..e4757f8957ae 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -81,16 +81,9 @@ struct atmel_sha_caps { struct atmel_sha_dev; /* - * .statesize = sizeof(struct atmel_sha_state) must be <= PAGE_SIZE / 8 as + * .statesize = sizeof(struct atmel_sha_reqctx) must be <= PAGE_SIZE / 8 as * tested by the ahash_prepare_alg() function. */ -struct atmel_sha_state { - u8 digest[SHA512_DIGEST_SIZE]; - u8 buffer[SHA_BUFFER_LEN]; - u64 digcnt[2]; - size_t bufcnt; -}; - struct atmel_sha_reqctx { struct atmel_sha_dev *dd; unsigned long flags; @@ -109,7 +102,7 @@ struct atmel_sha_reqctx { size_t block_size; - u8 buffer[0] __aligned(sizeof(u32)); + u8 buffer[SHA_BUFFER_LEN + SHA512_BLOCK_SIZE] __aligned(sizeof(u32)); }; struct atmel_sha_ctx { @@ -1048,40 +1041,23 @@ static int atmel_sha_digest(struct ahash_request *req) static int atmel_sha_export(struct ahash_request *req, void *out) { const struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); - struct atmel_sha_state state; - - memcpy(state.digest, ctx->digest, SHA512_DIGEST_SIZE); - memcpy(state.buffer, ctx->buffer, ctx->bufcnt); - state.bufcnt = ctx->bufcnt; - state.digcnt[0] = ctx->digcnt[0]; - state.digcnt[1] = ctx->digcnt[1]; - /* out might be unaligned. */ - memcpy(out, &state, sizeof(state)); + memcpy(out, ctx, sizeof(*ctx)); return 0; } static int atmel_sha_import(struct ahash_request *req, const void *in) { struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); - struct atmel_sha_state state; - - /* in might be unaligned. */ - memcpy(&state, in, sizeof(state)); - memcpy(ctx->digest, state.digest, SHA512_DIGEST_SIZE); - memcpy(ctx->buffer, state.buffer, state.bufcnt); - ctx->bufcnt = state.bufcnt; - ctx->digcnt[0] = state.digcnt[0]; - ctx->digcnt[1] = state.digcnt[1]; + memcpy(ctx, in, sizeof(*ctx)); return 0; } static int atmel_sha_cra_init(struct crypto_tfm *tfm) { crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct atmel_sha_reqctx) + - SHA_BUFFER_LEN + SHA512_BLOCK_SIZE); + sizeof(struct atmel_sha_reqctx)); return 0; } @@ -1097,7 +1073,7 @@ static struct ahash_alg sha_1_256_algs[] = { .import = atmel_sha_import, .halg = { .digestsize = SHA1_DIGEST_SIZE, - .statesize = sizeof(struct atmel_sha_state), + .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "sha1", .cra_driver_name = "atmel-sha1", @@ -1121,7 +1097,7 @@ static struct ahash_alg sha_1_256_algs[] = { .import = atmel_sha_import, .halg = { .digestsize = SHA256_DIGEST_SIZE, - .statesize = sizeof(struct atmel_sha_state), + .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "sha256", .cra_driver_name = "atmel-sha256", @@ -1147,7 +1123,7 @@ static struct ahash_alg sha_224_alg = { .import = atmel_sha_import, .halg = { .digestsize = SHA224_DIGEST_SIZE, - .statesize = sizeof(struct atmel_sha_state), + .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "sha224", .cra_driver_name = "atmel-sha224", @@ -1173,7 +1149,7 @@ static struct ahash_alg sha_384_512_algs[] = { .import = atmel_sha_import, .halg = { .digestsize = SHA384_DIGEST_SIZE, - .statesize = sizeof(struct atmel_sha_state), + .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "sha384", .cra_driver_name = "atmel-sha384", @@ -1197,7 +1173,7 @@ static struct ahash_alg sha_384_512_algs[] = { .import = atmel_sha_import, .halg = { .digestsize = SHA512_DIGEST_SIZE, - .statesize = sizeof(struct atmel_sha_state), + .statesize = sizeof(struct atmel_sha_reqctx), .base = { .cra_name = "sha512", .cra_driver_name = "atmel-sha512", -- cgit v1.2.3 From ad84112a1135bda928806fcbb98680847ab81436 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 8 Feb 2016 16:26:49 +0100 Subject: crypto: atmel-sha - fix race in atmel_sha_final() When (!ctx->bufcnt && !(ctx->flags & SHA_FLAGS_PAD)), the former source code used to set the SHA_FLAGS_BUSY without checking whether this flag was already set. If so, the hardware is already processing another hash request so the processing of the req argument of atmel_sha_final() should be delayed by queueing this request, the same way as done for the (ctx->bufcnt != 0) case. Signed-off-by: Cyrille Pitchen Signed-off-by: Herbert Xu --- drivers/crypto/atmel-sha.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) (limited to 'drivers/crypto/atmel-sha.c') diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index e4757f8957ae..7b93586154a7 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -979,37 +979,17 @@ static int atmel_sha_update(struct ahash_request *req) static int atmel_sha_final(struct ahash_request *req) { struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); - struct atmel_sha_ctx *tctx = crypto_tfm_ctx(req->base.tfm); - struct atmel_sha_dev *dd = tctx->dd; - - int err = 0; ctx->flags |= SHA_FLAGS_FINUP; if (ctx->flags & SHA_FLAGS_ERROR) return 0; /* uncompleted hash is not needed */ - if (ctx->bufcnt) { - return atmel_sha_enqueue(req, SHA_OP_FINAL); - } else if (!(ctx->flags & SHA_FLAGS_PAD)) { /* add padding */ - err = atmel_sha_hw_init(dd); - if (err) - goto err1; - - dd->req = req; - dd->flags |= SHA_FLAGS_BUSY; - err = atmel_sha_final_req(dd); - } else { + if (ctx->flags & SHA_FLAGS_PAD) /* copy ready hash (+ finalize hmac) */ return atmel_sha_finish(req); - } - -err1: - if (err != -EINPROGRESS) - /* done_task will not finish it, so do it here */ - atmel_sha_finish_req(req, err); - return err; + return atmel_sha_enqueue(req, SHA_OP_FINAL); } static int atmel_sha_finup(struct ahash_request *req) -- cgit v1.2.3 From 9b52d55f4f0e2bb9a34abbcf99e05e17f1b3b281 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Sun, 6 Mar 2016 03:21:52 +0200 Subject: crypto: atmel - fix checks of error code returned by devm_ioremap_resource() The change fixes potential oops while accessing iomem on invalid address, if devm_ioremap_resource() fails due to some reason. The devm_ioremap_resource() function returns ERR_PTR() and never returns NULL, which makes useless a following check for NULL. Signed-off-by: Vladimir Zapolskiy Fixes: b0e8b3417a62 ("crypto: atmel - use devm_xxx() managed function") Signed-off-by: Herbert Xu --- drivers/crypto/atmel-aes.c | 4 ++-- drivers/crypto/atmel-sha.c | 4 ++-- drivers/crypto/atmel-tdes.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/crypto/atmel-sha.c') diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 949af89cdac3..93474f8babfc 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -2079,9 +2079,9 @@ static int atmel_aes_probe(struct platform_device *pdev) } aes_dd->io_base = devm_ioremap_resource(&pdev->dev, aes_res); - if (!aes_dd->io_base) { + if (IS_ERR(aes_dd->io_base)) { dev_err(dev, "can't ioremap\n"); - err = -ENOMEM; + err = PTR_ERR(aes_dd->io_base); goto res_err; } diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 7b93586154a7..4b2dd95782bf 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -1486,9 +1486,9 @@ static int atmel_sha_probe(struct platform_device *pdev) } sha_dd->io_base = devm_ioremap_resource(&pdev->dev, sha_res); - if (!sha_dd->io_base) { + if (IS_ERR(sha_dd->io_base)) { dev_err(dev, "can't ioremap\n"); - err = -ENOMEM; + err = PTR_ERR(sha_dd->io_base); goto res_err; } diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index 2c7a628d0375..bf467d7be35c 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -1417,9 +1417,9 @@ static int atmel_tdes_probe(struct platform_device *pdev) } tdes_dd->io_base = devm_ioremap_resource(&pdev->dev, tdes_res); - if (!tdes_dd->io_base) { + if (IS_ERR(tdes_dd->io_base)) { dev_err(dev, "can't ioremap\n"); - err = -ENOMEM; + err = PTR_ERR(tdes_dd->io_base); goto res_err; } -- cgit v1.2.3