diff options
author | Cyrille Pitchen <cyrille.pitchen@atmel.com> | 2017-01-26 11:07:52 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2017-02-03 05:16:13 -0500 |
commit | eec12f66b02c3812252103d5efcb80754b04012c (patch) | |
tree | ec84949d020e869cfff9300a335bd27a333cefef /drivers/crypto/atmel-sha.c | |
parent | 563c47df79747412bf5d0fdb8fd24089d7316c2b (diff) |
crypto: atmel-sha - add atmel_sha_cpu_start()
This patch adds a simple function to perform data transfer with PIO, hence
handled by the CPU.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto/atmel-sha.c')
-rw-r--r-- | drivers/crypto/atmel-sha.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index be0d72cf4352..58d9ca8ac0f2 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c | |||
@@ -64,6 +64,8 @@ | |||
64 | #define SHA_FLAGS_ERROR BIT(23) | 64 | #define SHA_FLAGS_ERROR BIT(23) |
65 | #define SHA_FLAGS_PAD BIT(24) | 65 | #define SHA_FLAGS_PAD BIT(24) |
66 | #define SHA_FLAGS_RESTORE BIT(25) | 66 | #define SHA_FLAGS_RESTORE BIT(25) |
67 | #define SHA_FLAGS_IDATAR0 BIT(26) | ||
68 | #define SHA_FLAGS_WAIT_DATARDY BIT(27) | ||
67 | 69 | ||
68 | #define SHA_OP_UPDATE 1 | 70 | #define SHA_OP_UPDATE 1 |
69 | #define SHA_OP_FINAL 2 | 71 | #define SHA_OP_FINAL 2 |
@@ -141,6 +143,7 @@ struct atmel_sha_dev { | |||
141 | struct ahash_request *req; | 143 | struct ahash_request *req; |
142 | bool is_async; | 144 | bool is_async; |
143 | atmel_sha_fn_t resume; | 145 | atmel_sha_fn_t resume; |
146 | atmel_sha_fn_t cpu_transfer_complete; | ||
144 | 147 | ||
145 | struct atmel_sha_dma dma_lch_in; | 148 | struct atmel_sha_dma dma_lch_in; |
146 | 149 | ||
@@ -1317,6 +1320,93 @@ static irqreturn_t atmel_sha_irq(int irq, void *dev_id) | |||
1317 | return IRQ_NONE; | 1320 | return IRQ_NONE; |
1318 | } | 1321 | } |
1319 | 1322 | ||
1323 | |||
1324 | /* CPU transfer functions */ | ||
1325 | |||
1326 | static int atmel_sha_cpu_transfer(struct atmel_sha_dev *dd) | ||
1327 | { | ||
1328 | struct ahash_request *req = dd->req; | ||
1329 | struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); | ||
1330 | const u32 *words = (const u32 *)ctx->buffer; | ||
1331 | size_t i, num_words; | ||
1332 | u32 isr, din, din_inc; | ||
1333 | |||
1334 | din_inc = (ctx->flags & SHA_FLAGS_IDATAR0) ? 0 : 1; | ||
1335 | for (;;) { | ||
1336 | /* Write data into the Input Data Registers. */ | ||
1337 | num_words = DIV_ROUND_UP(ctx->bufcnt, sizeof(u32)); | ||
1338 | for (i = 0, din = 0; i < num_words; ++i, din += din_inc) | ||
1339 | atmel_sha_write(dd, SHA_REG_DIN(din), words[i]); | ||
1340 | |||
1341 | ctx->offset += ctx->bufcnt; | ||
1342 | ctx->total -= ctx->bufcnt; | ||
1343 | |||
1344 | if (!ctx->total) | ||
1345 | break; | ||
1346 | |||
1347 | /* | ||
1348 | * Prepare next block: | ||
1349 | * Fill ctx->buffer now with the next data to be written into | ||
1350 | * IDATARx: it gives time for the SHA hardware to process | ||
1351 | * the current data so the SHA_INT_DATARDY flag might be set | ||
1352 | * in SHA_ISR when polling this register at the beginning of | ||
1353 | * the next loop. | ||
1354 | */ | ||
1355 | ctx->bufcnt = min_t(size_t, ctx->block_size, ctx->total); | ||
1356 | scatterwalk_map_and_copy(ctx->buffer, ctx->sg, | ||
1357 | ctx->offset, ctx->bufcnt, 0); | ||
1358 | |||
1359 | /* Wait for hardware to be ready again. */ | ||
1360 | isr = atmel_sha_read(dd, SHA_ISR); | ||
1361 | if (!(isr & SHA_INT_DATARDY)) { | ||
1362 | /* Not ready yet. */ | ||
1363 | dd->resume = atmel_sha_cpu_transfer; | ||
1364 | atmel_sha_write(dd, SHA_IER, SHA_INT_DATARDY); | ||
1365 | return -EINPROGRESS; | ||
1366 | } | ||
1367 | } | ||
1368 | |||
1369 | if (unlikely(!(ctx->flags & SHA_FLAGS_WAIT_DATARDY))) | ||
1370 | return dd->cpu_transfer_complete(dd); | ||
1371 | |||
1372 | return atmel_sha_wait_for_data_ready(dd, dd->cpu_transfer_complete); | ||
1373 | } | ||
1374 | |||
1375 | static int atmel_sha_cpu_start(struct atmel_sha_dev *dd, | ||
1376 | struct scatterlist *sg, | ||
1377 | unsigned int len, | ||
1378 | bool idatar0_only, | ||
1379 | bool wait_data_ready, | ||
1380 | atmel_sha_fn_t resume) | ||
1381 | { | ||
1382 | struct ahash_request *req = dd->req; | ||
1383 | struct atmel_sha_reqctx *ctx = ahash_request_ctx(req); | ||
1384 | |||
1385 | if (!len) | ||
1386 | return resume(dd); | ||
1387 | |||
1388 | ctx->flags &= ~(SHA_FLAGS_IDATAR0 | SHA_FLAGS_WAIT_DATARDY); | ||
1389 | |||
1390 | if (idatar0_only) | ||
1391 | ctx->flags |= SHA_FLAGS_IDATAR0; | ||
1392 | |||
1393 | if (wait_data_ready) | ||
1394 | ctx->flags |= SHA_FLAGS_WAIT_DATARDY; | ||
1395 | |||
1396 | ctx->sg = sg; | ||
1397 | ctx->total = len; | ||
1398 | ctx->offset = 0; | ||
1399 | |||
1400 | /* Prepare the first block to be written. */ | ||
1401 | ctx->bufcnt = min_t(size_t, ctx->block_size, ctx->total); | ||
1402 | scatterwalk_map_and_copy(ctx->buffer, ctx->sg, | ||
1403 | ctx->offset, ctx->bufcnt, 0); | ||
1404 | |||
1405 | dd->cpu_transfer_complete = resume; | ||
1406 | return atmel_sha_cpu_transfer(dd); | ||
1407 | } | ||
1408 | |||
1409 | |||
1320 | static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd) | 1410 | static void atmel_sha_unregister_algs(struct atmel_sha_dev *dd) |
1321 | { | 1411 | { |
1322 | int i; | 1412 | int i; |