Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Cyrille Pitchen and committed by
Herbert Xu
7cee3508 507c5cc2

+84 -25
+4
drivers/crypto/atmel-sha-regs.h
··· 8 8 #define SHA_CR_START (1 << 0) 9 9 #define SHA_CR_FIRST (1 << 4) 10 10 #define SHA_CR_SWRST (1 << 8) 11 + #define SHA_CR_WUIHV (1 << 12) 12 + #define SHA_CR_WUIEHV (1 << 13) 11 13 12 14 #define SHA_MR 0x04 13 15 #define SHA_MR_MODE_MASK (0x3 << 0) ··· 17 15 #define SHA_MR_MODE_AUTO 0x1 18 16 #define SHA_MR_MODE_PDC 0x2 19 17 #define SHA_MR_PROCDLY (1 << 4) 18 + #define SHA_MR_UIHV (1 << 5) 19 + #define SHA_MR_UIEHV (1 << 6) 20 20 #define SHA_MR_ALGO_SHA1 (0 << 8) 21 21 #define SHA_MR_ALGO_SHA256 (1 << 8) 22 22 #define SHA_MR_ALGO_SHA384 (2 << 8)
+80 -25
drivers/crypto/atmel-sha.c
··· 53 53 54 54 #define SHA_FLAGS_FINUP BIT(16) 55 55 #define SHA_FLAGS_SG BIT(17) 56 + #define SHA_FLAGS_ALGO_MASK GENMASK(22, 18) 56 57 #define SHA_FLAGS_SHA1 BIT(18) 57 58 #define SHA_FLAGS_SHA224 BIT(19) 58 59 #define SHA_FLAGS_SHA256 BIT(20) ··· 61 60 #define SHA_FLAGS_SHA512 BIT(22) 62 61 #define SHA_FLAGS_ERROR BIT(23) 63 62 #define SHA_FLAGS_PAD BIT(24) 63 + #define SHA_FLAGS_RESTORE BIT(25) 64 64 65 65 #define SHA_OP_UPDATE 1 66 66 #define SHA_OP_FINAL 2 ··· 75 73 bool has_dualbuff; 76 74 bool has_sha224; 77 75 bool has_sha_384_512; 76 + bool has_uihv; 78 77 }; 79 78 80 79 struct atmel_sha_dev; ··· 321 318 static void atmel_sha_write_ctrl(struct atmel_sha_dev *dd, int dma) 322 319 { 323 320 struct atmel_sha_reqctx *ctx = ahash_request_ctx(dd->req); 324 - u32 valcr = 0, valmr = SHA_MR_MODE_AUTO; 321 + u32 valmr = SHA_MR_MODE_AUTO; 322 + unsigned int i, hashsize = 0; 325 323 326 324 if (likely(dma)) { 327 325 if (!dd->caps.has_dma) ··· 334 330 atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY); 335 331 } 336 332 337 - if (ctx->flags & SHA_FLAGS_SHA1) 333 + switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { 334 + case SHA_FLAGS_SHA1: 338 335 valmr |= SHA_MR_ALGO_SHA1; 339 - else if (ctx->flags & SHA_FLAGS_SHA224) 336 + hashsize = SHA1_DIGEST_SIZE; 337 + break; 338 + 339 + case SHA_FLAGS_SHA224: 340 340 valmr |= SHA_MR_ALGO_SHA224; 341 - else if (ctx->flags & SHA_FLAGS_SHA256) 341 + hashsize = SHA256_DIGEST_SIZE; 342 + break; 343 + 344 + case SHA_FLAGS_SHA256: 342 345 valmr |= SHA_MR_ALGO_SHA256; 343 - else if (ctx->flags & SHA_FLAGS_SHA384) 346 + hashsize = SHA256_DIGEST_SIZE; 347 + break; 348 + 349 + case SHA_FLAGS_SHA384: 344 350 valmr |= SHA_MR_ALGO_SHA384; 345 - else if (ctx->flags & SHA_FLAGS_SHA512) 351 + hashsize = SHA512_DIGEST_SIZE; 352 + break; 353 + 354 + case SHA_FLAGS_SHA512: 346 355 valmr |= SHA_MR_ALGO_SHA512; 356 + hashsize = SHA512_DIGEST_SIZE; 357 + break; 358 + 359 + default: 360 + break; 361 + } 347 362 348 363 /* Setting CR_FIRST only for the first iteration */ 349 - if (!(ctx->digcnt[0] || ctx->digcnt[1])) 350 - valcr = SHA_CR_FIRST; 364 + if (!(ctx->digcnt[0] || ctx->digcnt[1])) { 365 + atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); 366 + } else if (dd->caps.has_uihv && (ctx->flags & SHA_FLAGS_RESTORE)) { 367 + const u32 *hash = (const u32 *)ctx->digest; 351 368 352 - atmel_sha_write(dd, SHA_CR, valcr); 369 + /* 370 + * Restore the hardware context: update the User Initialize 371 + * Hash Value (UIHV) with the value saved when the latest 372 + * 'update' operation completed on this very same crypto 373 + * request. 374 + */ 375 + ctx->flags &= ~SHA_FLAGS_RESTORE; 376 + atmel_sha_write(dd, SHA_CR, SHA_CR_WUIHV); 377 + for (i = 0; i < hashsize / sizeof(u32); ++i) 378 + atmel_sha_write(dd, SHA_REG_DIN(i), hash[i]); 379 + atmel_sha_write(dd, SHA_CR, SHA_CR_FIRST); 380 + valmr |= SHA_MR_UIHV; 381 + } 382 + /* 383 + * WARNING: If the UIHV feature is not available, the hardware CANNOT 384 + * process concurrent requests: the internal registers used to store 385 + * the hash/digest are still set to the partial digest output values 386 + * computed during the latest round. 387 + */ 388 + 353 389 atmel_sha_write(dd, SHA_MR, valmr); 354 390 } 355 391 ··· 758 714 { 759 715 struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); 760 716 u32 *hash = (u32 *)ctx->digest; 761 - int i; 717 + unsigned int i, hashsize; 762 718 763 - if (ctx->flags & SHA_FLAGS_SHA1) 764 - for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(u32); i++) 765 - hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); 766 - else if (ctx->flags & SHA_FLAGS_SHA224) 767 - for (i = 0; i < SHA224_DIGEST_SIZE / sizeof(u32); i++) 768 - hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); 769 - else if (ctx->flags & SHA_FLAGS_SHA256) 770 - for (i = 0; i < SHA256_DIGEST_SIZE / sizeof(u32); i++) 771 - hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); 772 - else if (ctx->flags & SHA_FLAGS_SHA384) 773 - for (i = 0; i < SHA384_DIGEST_SIZE / sizeof(u32); i++) 774 - hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); 775 - else 776 - for (i = 0; i < SHA512_DIGEST_SIZE / sizeof(u32); i++) 777 - hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); 719 + switch (ctx->flags & SHA_FLAGS_ALGO_MASK) { 720 + case SHA_FLAGS_SHA1: 721 + hashsize = SHA1_DIGEST_SIZE; 722 + break; 723 + 724 + case SHA_FLAGS_SHA224: 725 + case SHA_FLAGS_SHA256: 726 + hashsize = SHA256_DIGEST_SIZE; 727 + break; 728 + 729 + case SHA_FLAGS_SHA384: 730 + case SHA_FLAGS_SHA512: 731 + hashsize = SHA512_DIGEST_SIZE; 732 + break; 733 + 734 + default: 735 + /* Should not happen... */ 736 + return; 737 + } 738 + 739 + for (i = 0; i < hashsize / sizeof(u32); ++i) 740 + hash[i] = atmel_sha_read(ctx->dd, SHA_REG_DIGEST(i)); 741 + ctx->flags |= SHA_FLAGS_RESTORE; 778 742 } 779 743 780 744 static void atmel_sha_copy_ready_hash(struct ahash_request *req) ··· 1328 1276 dd->caps.has_dualbuff = 0; 1329 1277 dd->caps.has_sha224 = 0; 1330 1278 dd->caps.has_sha_384_512 = 0; 1279 + dd->caps.has_uihv = 0; 1331 1280 1332 1281 /* keep only major version number */ 1333 1282 switch (dd->hw_version & 0xff0) { ··· 1337 1284 dd->caps.has_dualbuff = 1; 1338 1285 dd->caps.has_sha224 = 1; 1339 1286 dd->caps.has_sha_384_512 = 1; 1287 + dd->caps.has_uihv = 1; 1340 1288 break; 1341 1289 case 0x420: 1342 1290 dd->caps.has_dma = 1; 1343 1291 dd->caps.has_dualbuff = 1; 1344 1292 dd->caps.has_sha224 = 1; 1345 1293 dd->caps.has_sha_384_512 = 1; 1294 + dd->caps.has_uihv = 1; 1346 1295 break; 1347 1296 case 0x410: 1348 1297 dd->caps.has_dma = 1;