Skip to content

Commit 79152e8

Browse files
krzkherbertx
authored andcommitted
crypto: s5p-sss - Fix missed interrupts when working with 8 kB blocks
The tcrypt testing module on Exynos5422-based Odroid XU3/4 board failed on testing 8 kB size blocks: $ sudo modprobe tcrypt sec=1 mode=500 testing speed of async ecb(aes) (ecb-aes-s5p) encryption test 0 (128 bit key, 16 byte blocks): 21971 operations in 1 seconds (351536 bytes) test 1 (128 bit key, 64 byte blocks): 21731 operations in 1 seconds (1390784 bytes) test 2 (128 bit key, 256 byte blocks): 21932 operations in 1 seconds (5614592 bytes) test 3 (128 bit key, 1024 byte blocks): 21685 operations in 1 seconds (22205440 bytes) test 4 (128 bit key, 8192 byte blocks): This was caused by a race issue of missed BRDMA_DONE ("Block cipher Receiving DMA") interrupt. Device starts processing the data in DMA mode immediately after setting length of DMA block: receiving (FCBRDMAL) or transmitting (FCBTDMAL). The driver sets these lengths from interrupt handler through s5p_set_dma_indata() function (or xxx_setdata()). However the interrupt handler was first dealing with receive buffer (dma-unmap old, dma-map new, set receive block length which starts the operation), then with transmit buffer and finally was clearing pending interrupts (FCINTPEND). Because of the time window between setting receive buffer length and clearing pending interrupts, the operation on receive buffer could end already and driver would miss new interrupt. User manual for Exynos5422 confirms in example code that setting DMA block lengths should be the last operation. The tcrypt hang could be also observed in following blocked-task dmesg: INFO: task modprobe:258 blocked for more than 120 seconds. Not tainted 4.6.0-rc4-next-20160419-00005-g9eac8b7b7753-dirty #42 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. modprobe D c06b09d8 0 258 256 0x00000000 [<c06b09d8>] (__schedule) from [<c06b0f24>] (schedule+0x40/0xac) [<c06b0f24>] (schedule) from [<c06b49f8>] (schedule_timeout+0x124/0x178) [<c06b49f8>] (schedule_timeout) from [<c06b17fc>] (wait_for_common+0xb8/0x144) [<c06b17fc>] (wait_for_common) from [<bf0013b8>] (test_acipher_speed+0x49c/0x740 [tcrypt]) [<bf0013b8>] (test_acipher_speed [tcrypt]) from [<bf003e8c>] (do_test+0x2240/0x30ec [tcrypt]) [<bf003e8c>] (do_test [tcrypt]) from [<bf008048>] (tcrypt_mod_init+0x48/0xa4 [tcrypt]) [<bf008048>] (tcrypt_mod_init [tcrypt]) from [<c010177c>] (do_one_initcall+0x3c/0x16c) [<c010177c>] (do_one_initcall) from [<c0191ff0>] (do_init_module+0x5c/0x1ac) [<c0191ff0>] (do_init_module) from [<c0185610>] (load_module+0x1a30/0x1d08) [<c0185610>] (load_module) from [<c0185ab0>] (SyS_finit_module+0x8c/0x98) [<c0185ab0>] (SyS_finit_module) from [<c01078c0>] (ret_fast_syscall+0x0/0x3c) Fixes: a49e490 ("crypto: s5p-sss - add S5PV210 advanced crypto engine support") Cc: <[email protected]> Signed-off-by: Krzysztof Kozlowski <[email protected]> Tested-by: Marek Szyprowski <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent 5e00c60 commit 79152e8

File tree

1 file changed

+39
-14
lines changed

1 file changed

+39
-14
lines changed

drivers/crypto/s5p-sss.c

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -367,43 +367,55 @@ static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
367367
return err;
368368
}
369369

370-
static void s5p_aes_tx(struct s5p_aes_dev *dev)
370+
/*
371+
* Returns true if new transmitting (output) data is ready and its
372+
* address+length have to be written to device (by calling
373+
* s5p_set_dma_outdata()). False otherwise.
374+
*/
375+
static bool s5p_aes_tx(struct s5p_aes_dev *dev)
371376
{
372377
int err = 0;
378+
bool ret = false;
373379

374380
s5p_unset_outdata(dev);
375381

376382
if (!sg_is_last(dev->sg_dst)) {
377383
err = s5p_set_outdata(dev, sg_next(dev->sg_dst));
378-
if (err) {
384+
if (err)
379385
s5p_aes_complete(dev, err);
380-
return;
381-
}
382-
383-
s5p_set_dma_outdata(dev, dev->sg_dst);
386+
else
387+
ret = true;
384388
} else {
385389
s5p_aes_complete(dev, err);
386390

387391
dev->busy = true;
388392
tasklet_schedule(&dev->tasklet);
389393
}
394+
395+
return ret;
390396
}
391397

392-
static void s5p_aes_rx(struct s5p_aes_dev *dev)
398+
/*
399+
* Returns true if new receiving (input) data is ready and its
400+
* address+length have to be written to device (by calling
401+
* s5p_set_dma_indata()). False otherwise.
402+
*/
403+
static bool s5p_aes_rx(struct s5p_aes_dev *dev)
393404
{
394405
int err;
406+
bool ret = false;
395407

396408
s5p_unset_indata(dev);
397409

398410
if (!sg_is_last(dev->sg_src)) {
399411
err = s5p_set_indata(dev, sg_next(dev->sg_src));
400-
if (err) {
412+
if (err)
401413
s5p_aes_complete(dev, err);
402-
return;
403-
}
404-
405-
s5p_set_dma_indata(dev, dev->sg_src);
414+
else
415+
ret = true;
406416
}
417+
418+
return ret;
407419
}
408420

409421
static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
@@ -412,17 +424,30 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
412424
struct s5p_aes_dev *dev = platform_get_drvdata(pdev);
413425
uint32_t status;
414426
unsigned long flags;
427+
bool set_dma_tx = false;
428+
bool set_dma_rx = false;
415429

416430
spin_lock_irqsave(&dev->lock, flags);
417431

418432
status = SSS_READ(dev, FCINTSTAT);
419433
if (status & SSS_FCINTSTAT_BRDMAINT)
420-
s5p_aes_rx(dev);
434+
set_dma_rx = s5p_aes_rx(dev);
421435
if (status & SSS_FCINTSTAT_BTDMAINT)
422-
s5p_aes_tx(dev);
436+
set_dma_tx = s5p_aes_tx(dev);
423437

424438
SSS_WRITE(dev, FCINTPEND, status);
425439

440+
/*
441+
* Writing length of DMA block (either receiving or transmitting)
442+
* will start the operation immediately, so this should be done
443+
* at the end (even after clearing pending interrupts to not miss the
444+
* interrupt).
445+
*/
446+
if (set_dma_tx)
447+
s5p_set_dma_outdata(dev, dev->sg_dst);
448+
if (set_dma_rx)
449+
s5p_set_dma_indata(dev, dev->sg_src);
450+
426451
spin_unlock_irqrestore(&dev->lock, flags);
427452

428453
return IRQ_HANDLED;

0 commit comments

Comments
 (0)