From patchwork Tue Apr 18 23:18:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Cvek X-Patchwork-Id: 9686691 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 D2A6C602C9 for ; Tue, 18 Apr 2017 23:33:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C3EC028113 for ; Tue, 18 Apr 2017 23:33:33 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B7B092787C; Tue, 18 Apr 2017 23:33:33 +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=-1.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 73E632787C for ; Tue, 18 Apr 2017 23:33:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:Date: Message-ID:References:To:Subject:From:Reply-To:Content-ID:Content-Description :Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=hrJoQUnsfewGVem2CeqhLXzYwcInue/ltbZ9W9AAuyQ=; b=SkaoZFsOu2e56c E35Z9UIOKc8ky6O3/SV8wBnstKqe/yZZw9j2VTzaX4p2LYOHkQVWAO18aHsR/f9MhcFI1VOjK0Lux VVSzhTxozmOHuu8QKTUfIu3MFlxO9rEiOyQynTTg0niIbqRHTB3HSNd6pw+n6MKL3TGwVmhUQJVFZ TbVqFdkqVc9AFDI4Nl5r05Hs3H7KBUvf4YWJA8hSWGkt/Ldq+xTXFtlzeH/1pnvNru8CTz+IRtg+Y E3rvXXmsGn/x2MbtQ2wciM5IJtY9TRmi0tZgR1KseS6YxS6lpKAZK4HV1I7y9yznlZhj7DxjqSU8+ s+5Vb7FPqDu3CmJ2c0bw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1d0ccm-0008Vx-98; Tue, 18 Apr 2017 23:33:32 +0000 Received: from bubo.tul.cz ([2001:718:1c01:16::aa]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1d0cNf-0000fY-Uo for linux-arm-kernel@lists.infradead.org; Tue, 18 Apr 2017 23:18:10 +0000 X-Virus-Scanned: amavisd-new at tul.cz Received: from [IPv6:2001:1ae9:ff1:f191:60c5:33b1:380e:2367] (unknown [IPv6:2001:1ae9:ff1:f191:60c5:33b1:380e:2367]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by bubo.tul.cz (Postfix) with ESMTPSA id 5D0DA18050A0B; Wed, 19 Apr 2017 01:17:30 +0200 (CEST) From: Petr Cvek Subject: [PATCH 4/4] mmc: pxamci: Fix race condition between pxamci_dma_irq() and pxamci_irq() To: ulf.hansson@linaro.org, robert.jarzmik@free.fr References: Message-ID: <31e332fa-f152-1eff-39fb-91f332b84757@tul.cz> Date: Wed, 19 Apr 2017 01:18:00 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.8.0 MIME-Version: 1.0 In-Reply-To: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170418_161756_506537_69D8E088 X-CRM114-Status: GOOD ( 13.66 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-mmc@vger.kernel.org, linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The data write requests may require an FIFO flush when the DMA transaction ends. This is handled by a DMA callback pxamci_dma_irq(). After flushing the FIFO the MCI controller generates the DATA_TRAN_DONE interrupt. Problem is the DATA_TRAN_DONE interrupt will be generated when the write data length is divisible by the FIFO size (no flush is required). And in this case the DMA callback can be called long time after the DATA_TRAN_DONE interrupt (as the DMA callback is realised by a tasklet, it can even stack). When the DMA callback is finally called there can already be a different type of the transaction (another data read or write request). The dmaengine_tx_status() will be called for a wrong DMA transaction and in some case it returns DMA_IN_PROGRESS, which the code recognize as an error and ends a running DMA and halts the MCI controller. The problem presents itself under heavy (interrupt) load with a high MCI traffic with this message: mmc0: DMA error on tx channel The fix must obey these situations: - Any command will erase the FIFO - Data writes divisible by the FIFO size will (probably) automatically generate a DATA_TRAN_DONE interrupt - Data writes with a nonzero FIFO remainder must be flushed and then MCI generates a DATA_TRAN_DONE interrupt - Data reads do not require a flush but they will generate a DATA_TRAN_DONE interrupt The fix changes the DATA_TRAN_DONE interrupt enable from read/write requests to read requests. The DATA_TRAN_DONE interrupt for a write request is enabled in the DMA callback, this assures a DATA_TRAN_DONE interrupt will be always called after a callback (with or without an FIFO flush). Signed-off-by: Petr Cvek --- drivers/mmc/host/pxamci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 570735a10127..08713bb6c716 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -335,7 +335,9 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) pxamci_disable_irq(host, END_CMD_RES); if (host->data && !cmd->error) { - pxamci_enable_irq(host, DATA_TRAN_DONE); + if (host->data->flags & MMC_DATA_READ) + pxamci_enable_irq(host, DATA_TRAN_DONE); + /* * workaround for erratum #91, if doing write * enable DMA late @@ -585,6 +587,9 @@ static void pxamci_dma_irq(void *param) if (likely(status == DMA_COMPLETE)) { writel(BUF_PART_FULL, host->base + MMC_PRTBUF); + + /* NOTICE pxamci_irq() is dependent on pxamci_dma_irq() */ + pxamci_enable_irq(host, DATA_TRAN_DONE); } else { pr_err("%s: Invalid DMA status %i\n", mmc_hostname(host->mmc), status);