Skip to content

Commit 7cee350

Browse files
Cyrille Pitchenherbertx
authored andcommitted
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 <cyrille.pitchen@atmel.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
1 parent 507c5cc commit 7cee350

File tree

2 files changed

+84
-25
lines changed

2 files changed

+84
-25
lines changed

drivers/crypto/atmel-sha-regs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@
88
#define SHA_CR_START (1 << 0)
99
#define SHA_CR_FIRST (1 << 4)
1010
#define SHA_CR_SWRST (1 << 8)
11+
#define SHA_CR_WUIHV (1 << 12)
12+
#define SHA_CR_WUIEHV (1 << 13)
1113

1214
#define SHA_MR 0x04
1315
#define SHA_MR_MODE_MASK (0x3 << 0)
1416
#define SHA_MR_MODE_MANUAL 0x0
1517
#define SHA_MR_MODE_AUTO 0x1
1618
#define SHA_MR_MODE_PDC 0x2
1719
#define SHA_MR_PROCDLY (1 << 4)
20+
#define SHA_MR_UIHV (1 << 5)
21+
#define SHA_MR_UIEHV (1 << 6)
1822
#define SHA_MR_ALGO_SHA1 (0 << 8)
1923
#define SHA_MR_ALGO_SHA256 (1 << 8)
2024
#define SHA_MR_ALGO_SHA384 (2 << 8)

drivers/crypto/atmel-sha.c

Lines changed: 80 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@
5353

5454
#define SHA_FLAGS_FINUP BIT(16)
5555
#define SHA_FLAGS_SG BIT(17)
56+
#define SHA_FLAGS_ALGO_MASK GENMASK(22, 18)
5657
#define SHA_FLAGS_SHA1 BIT(18)
5758
#define SHA_FLAGS_SHA224 BIT(19)
5859
#define SHA_FLAGS_SHA256 BIT(20)
5960
#define SHA_FLAGS_SHA384 BIT(21)
6061
#define SHA_FLAGS_SHA512 BIT(22)
6162
#define SHA_FLAGS_ERROR BIT(23)
6263
#define SHA_FLAGS_PAD BIT(24)
64+
#define SHA_FLAGS_RESTORE BIT(25)
6365

6466
#define SHA_OP_UPDATE 1
6567
#define SHA_OP_FINAL 2
@@ -73,6 +75,7 @@ struct atmel_sha_caps {
7375
bool has_dualbuff;
7476
bool has_sha224;
7577
bool has_sha_384_512;
78+
bool has_uihv;
7679
};
7780

7881
struct atmel_sha_dev;
@@ -318,7 +321,8 @@ static int atmel_sha_init(struct ahash_request *req)
318321
static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
319322
{
320323
struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req);
321-
u32 valcr = 0, valmr = SHA_MR_MODE_AUTO;
324+
u32 valmr = SHA_MR_MODE_AUTO;
325+
unsigned int i, hashsize = 0;
322326

323327
if (likely(dma)) {
324328
if (!dd->caps.has_dma)
@@ -330,22 +334,62 @@ static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma)
330334
atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY);
331335
}
332336

333-
if (ctx->flags & SHA_FLAGS_SHA1)
337+
switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
338+
case SHA_FLAGS_SHA1:
334339
valmr |= SHA_MR_ALGO_SHA1;
335-
else if (ctx->flags & SHA_FLAGS_SHA224)
340+
hashsize = SHA1_DIGEST_SIZE;
341+
break;
342+
343+
case SHA_FLAGS_SHA224:
336344
valmr |= SHA_MR_ALGO_SHA224;
337-
else if (ctx->flags & SHA_FLAGS_SHA256)
345+
hashsize = SHA256_DIGEST_SIZE;
346+
break;
347+
348+
case SHA_FLAGS_SHA256:
338349
valmr |= SHA_MR_ALGO_SHA256;
339-
else if (ctx->flags & SHA_FLAGS_SHA384)
350+
hashsize = SHA256_DIGEST_SIZE;
351+
break;
352+
353+
case SHA_FLAGS_SHA384:
340354
valmr |= SHA_MR_ALGO_SHA384;
341-
else if (ctx->flags & SHA_FLAGS_SHA512)
355+
hashsize = SHA512_DIGEST_SIZE;
356+
break;
357+
358+
case SHA_FLAGS_SHA512:
342359
valmr |= SHA_MR_ALGO_SHA512;
360+
hashsize = SHA512_DIGEST_SIZE;
361+
break;
362+
363+
default:
364+
break;
365+
}
343366

344367
/* Setting CR_FIRST only for the first iteration */
345-
if (!(ctx->digcnt[0] || ctx->digcnt[1]))
346-
valcr = SHA_CR_FIRST;
368+
if (!(ctx->digcnt[0] || ctx->digcnt[1])) {
369+
atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST);
370+
} else if (dd->caps.has_uihv && (ctx->flags & SHA_FLAGS_RESTORE)) {
371+
const u32 *hash = (const u32 *)ctx->digest;
372+
373+
/*
374+
* Restore the hardware context: update the User Initialize
375+
* Hash Value (UIHV) with the value saved when the latest
376+
* 'update' operation completed on this very same crypto
377+
* request.
378+
*/
379+
ctx->flags &= ~SHA_FLAGS_RESTORE;
380+
atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV);
381+
for (i = 0; i < hashsize / sizeof(u32); ++i)
382+
atmel_sha_write(dd, SHA_REG_DIN(i), hash[i]);
383+
atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST);
384+
valmr |= SHA_MR_UIHV;
385+
}
386+
/*
387+
* WARNING: If the UIHV feature is not available, the hardware CANNOT
388+
* process concurrent requests: the internal registers used to store
389+
* the hash/digest are still set to the partial digest output values
390+
* computed during the latest round.
391+
*/
347392

348-
atmel_sha_write(dd, SHA_CR, valcr);
349393
atmel_sha_write(dd, SHA_MR, valmr);
350394
}
351395

@@ -714,23 +758,31 @@ static void atmel_sha_copy_hash(struct ahash_request *req)
714758
{
715759
struct atmel_sha_reqctx *ctx = ahash_request_ctx(req);
716760
u32 *hash = (u32 *)ctx->digest;
717-
int i;
761+
unsigned int i, hashsize;
718762

719-
if (ctx->flags & SHA_FLAGS_SHA1)
720-
for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++)
721-
hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
722-
else if (ctx->flags & SHA_FLAGS_SHA224)
723-
for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(u32); i++)
724-
hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
725-
else if (ctx->flags & SHA_FLAGS_SHA256)
726-
for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++)
727-
hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
728-
else if (ctx->flags & SHA_FLAGS_SHA384)
729-
for (i = 0; i < SHA384_DIGEST_SIZE / sizeof(u32); i++)
730-
hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
731-
else
732-
for (i = 0; i < SHA512_DIGEST_SIZE / sizeof(u32); i++)
733-
hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
763+
switch (ctx->flags & SHA_FLAGS_ALGO_MASK) {
764+
case SHA_FLAGS_SHA1:
765+
hashsize = SHA1_DIGEST_SIZE;
766+
break;
767+
768+
case SHA_FLAGS_SHA224:
769+
case SHA_FLAGS_SHA256:
770+
hashsize = SHA256_DIGEST_SIZE;
771+
break;
772+
773+
case SHA_FLAGS_SHA384:
774+
case SHA_FLAGS_SHA512:
775+
hashsize = SHA512_DIGEST_SIZE;
776+
break;
777+
778+
default:
779+
/* Should not happen... */
780+
return;
781+
}
782+
783+
for (i = 0; i < hashsize / sizeof(u32); ++i)
784+
hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i));
785+
ctx->flags |= SHA_FLAGS_RESTORE;
734786
}
735787

736788
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)
12761328
dd->caps.has_dualbuff = 0;
12771329
dd->caps.has_sha224 = 0;
12781330
dd->caps.has_sha_384_512 = 0;
1331+
dd->caps.has_uihv = 0;
12791332

12801333
/* keep only major version number */
12811334
switch (dd->hw_version & 0xff0) {
@@ -1284,12 +1337,14 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd)
12841337
dd->caps.has_dualbuff = 1;
12851338
dd->caps.has_sha224 = 1;
12861339
dd->caps.has_sha_384_512 = 1;
1340+
dd->caps.has_uihv = 1;
12871341
break;
12881342
case 0x420:
12891343
dd->caps.has_dma = 1;
12901344
dd->caps.has_dualbuff = 1;
12911345
dd->caps.has_sha224 = 1;
12921346
dd->caps.has_sha_384_512 = 1;
1347+
dd->caps.has_uihv = 1;
12931348
break;
12941349
case 0x410:
12951350
dd->caps.has_dma = 1;

0 commit comments

Comments
 (0)