From patchwork Mon May 30 10:09:28 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Krzysztof Kozlowski X-Patchwork-Id: 9140857 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8363E60759 for ; Mon, 30 May 2016 10:10:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7B67128212 for ; Mon, 30 May 2016 10:10:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 702F728220; Mon, 30 May 2016 10:10:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EA80428212 for ; Mon, 30 May 2016 10:09:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754596AbcE3KJo (ORCPT ); Mon, 30 May 2016 06:09:44 -0400 Received: from mailout4.w1.samsung.com ([210.118.77.14]:22968 "EHLO mailout4.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754333AbcE3KJn (ORCPT ); Mon, 30 May 2016 06:09:43 -0400 Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245]) by mailout4.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0O7Z00JW8IW3VX90@mailout4.w1.samsung.com>; Mon, 30 May 2016 11:09:39 +0100 (BST) X-AuditID: cbfec7f5-f792a6d000001302-d2-574c1162cd35 Received: from eusync4.samsung.com ( [203.254.199.214]) by eucpsbgm2.samsung.com (EUCPMTA) with SMTP id 09.F4.04866.2611C475; Mon, 30 May 2016 11:09:38 +0100 (BST) Received: from AMDC2174.DIGITAL.local ([106.120.53.17]) by eusync4.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0O7Z00HK7IW0CQ10@eusync4.samsung.com>; Mon, 30 May 2016 11:09:38 +0100 (BST) From: Krzysztof Kozlowski To: stable@vger.kernel.org Cc: linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, Krzysztof Kozlowski , Bartlomiej Zolnierkiewicz , Herbert Xu Subject: [PATCH stable 3.16+] crypto: s5p-sss - Fix missed interrupts when working with 8 kB blocks Date: Mon, 30 May 2016 12:09:28 +0200 Message-id: <1464602968-7526-1-git-send-email-k.kozlowski@samsung.com> X-Mailer: git-send-email 1.9.1 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrJJMWRmVeSWpSXmKPExsVy+t/xa7pJgj7hBi+/2VhsnLGe1aL7lYzF 6xeGFvfv/WSyuLxrDpvFgo2PGB3YPLYdUPXo27KK0ePzJrkA5igum5TUnMyy1CJ9uwSujEtT djEVbDKo2LLyAksD40X1LkZODgkBE4lVJy+yQ9hiEhfurWfrYuTiEBJYyiix6ekGFginkUli 7pQusCo2AWOJzcuXAFVxcIgISEncv2oNUsMscJlR4t2Nd8wgcWGBVIlre7JBylkEVCUmr9/E CmLzCrhJbLy6hQ1imZzEyWOTWScwci9gZFjFKJpamlxQnJSea6RXnJhbXJqXrpecn7uJERIA X3cwLj1mdYhRgINRiYe3QNM7XIg1say4MvcQowQHs5II72ROn3Ah3pTEyqrUovz4otKc1OJD jNIcLErivDN3vQ8REkhPLEnNTk0tSC2CyTJxcEo1MJ431n35OSNJQvjik+W1C62qTbpiTRbF K+nZm3r+jD2Xzl24t/zOjZ/fryR+OP2By27bqmD7+c9aXEQOc5puWPNCs++BZqsMR6LoV7bw iCCPV1ZfL9ewGcudmzj/20c94S3XW7w6bp9NMxf6zz1pwuRSAc89S2fpGWxb+EPteZDh50av Y8F2/UosxRmJhlrMRcWJAPB/m1z8AQAA Sender: linux-crypto-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP commit 79152e8d085fd64484afd473ef6830b45518acba upstream. 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 [] (__schedule) from [] (schedule+0x40/0xac) [] (schedule) from [] (schedule_timeout+0x124/0x178) [] (schedule_timeout) from [] (wait_for_common+0xb8/0x144) [] (wait_for_common) from [] (test_acipher_speed+0x49c/0x740 [tcrypt]) [] (test_acipher_speed [tcrypt]) from [] (do_test+0x2240/0x30ec [tcrypt]) [] (do_test [tcrypt]) from [] (tcrypt_mod_init+0x48/0xa4 [tcrypt]) [] (tcrypt_mod_init [tcrypt]) from [] (do_one_initcall+0x3c/0x16c) [] (do_one_initcall) from [] (do_init_module+0x5c/0x1ac) [] (do_init_module) from [] (load_module+0x1a30/0x1d08) [] (load_module) from [] (SyS_finit_module+0x8c/0x98) [] (SyS_finit_module) from [] (ret_fast_syscall+0x0/0x3c) Fixes: a49e490c7a8a ("crypto: s5p-sss - add S5PV210 advanced crypto engine support") Cc: # 3.16+ Signed-off-by: Krzysztof Kozlowski Tested-by: Marek Szyprowski Signed-off-by: Herbert Xu [k.kozlowski: Backport to v3.16] Acked-by: Herbert Xu --- Backporting to earlier kernels does not make much sense as the driver differs and the testing won't be possible probably. --- drivers/crypto/s5p-sss.c | 53 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 4197ad9a711b..8a46de76b834 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -313,43 +313,55 @@ static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) return err; } -static void s5p_aes_tx(struct s5p_aes_dev *dev) +/* + * Returns true if new transmitting (output) data is ready and its + * address+length have to be written to device (by calling + * s5p_set_dma_outdata()). False otherwise. + */ +static bool s5p_aes_tx(struct s5p_aes_dev *dev) { int err = 0; + bool ret = false; s5p_unset_outdata(dev); if (!sg_is_last(dev->sg_dst)) { err = s5p_set_outdata(dev, sg_next(dev->sg_dst)); - if (err) { + if (err) s5p_aes_complete(dev, err); - return; - } - - s5p_set_dma_outdata(dev, dev->sg_dst); + else + ret = true; } else { s5p_aes_complete(dev, err); dev->busy = true; tasklet_schedule(&dev->tasklet); } + + return ret; } -static void s5p_aes_rx(struct s5p_aes_dev *dev) +/* + * Returns true if new receiving (input) data is ready and its + * address+length have to be written to device (by calling + * s5p_set_dma_indata()). False otherwise. + */ +static bool s5p_aes_rx(struct s5p_aes_dev *dev) { int err; + bool ret = false; s5p_unset_indata(dev); if (!sg_is_last(dev->sg_src)) { err = s5p_set_indata(dev, sg_next(dev->sg_src)); - if (err) { + if (err) s5p_aes_complete(dev, err); - return; - } - - s5p_set_dma_indata(dev, dev->sg_src); + else + ret = true; } + + return ret; } static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) @@ -358,19 +370,32 @@ static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) struct s5p_aes_dev *dev = platform_get_drvdata(pdev); uint32_t status; unsigned long flags; + bool set_dma_tx = false; + bool set_dma_rx = false; spin_lock_irqsave(&dev->lock, flags); if (irq == dev->irq_fc) { status = SSS_READ(dev, FCINTSTAT); if (status & SSS_FCINTSTAT_BRDMAINT) - s5p_aes_rx(dev); + set_dma_rx = s5p_aes_rx(dev); if (status & SSS_FCINTSTAT_BTDMAINT) - s5p_aes_tx(dev); + set_dma_tx = s5p_aes_tx(dev); SSS_WRITE(dev, FCINTPEND, status); } + /* + * Writing length of DMA block (either receiving or transmitting) + * will start the operation immediately, so this should be done + * at the end (even after clearing pending interrupts to not miss the + * interrupt). + */ + if (set_dma_tx) + s5p_set_dma_outdata(dev, dev->sg_dst); + if (set_dma_rx) + s5p_set_dma_indata(dev, dev->sg_src); + spin_unlock_irqrestore(&dev->lock, flags); return IRQ_HANDLED;