From patchwork Thu Oct 15 10:46:26 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Ogness X-Patchwork-Id: 7404801 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id C6B129F1D5 for ; Thu, 15 Oct 2015 10:48:21 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id DB1DC20851 for ; Thu, 15 Oct 2015 10:48:20 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id ED0D920850 for ; Thu, 15 Oct 2015 10:48:19 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Zmg3l-0001ZB-Ay; Thu, 15 Oct 2015 10:46:57 +0000 Received: from galois.linutronix.de ([2001:470:1f0b:db:abcd:42:0:1]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Zmg3h-0001Kn-88 for linux-arm-kernel@lists.infradead.org; Thu, 15 Oct 2015 10:46:54 +0000 Received: from localhost ([127.0.0.1] helo=vostro.local) by Galois.linutronix.de with esmtp (Exim 4.80) (envelope-from ) id 1Zmg3J-0007dW-Qb; Thu, 15 Oct 2015 12:46:29 +0200 From: John Ogness To: linux-kernel@vger.kernel.org Subject: [PATCH] ARM: edma: fix residue race for cyclic Date: Thu, 15 Oct 2015 12:46:26 +0200 Message-ID: <87io68s931.fsf@linutronix.de> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.4 (gnu/linux) MIME-Version: 1.0 X-Linutronix-Spam-Score: -1.0 X-Linutronix-Spam-Level: - X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required, ALL_TRUSTED=-1, SHORTCIRCUIT=-0.0001, URIBL_BLOCKED=0.001 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20151015_034653_466940_3D3F6983 X-CRM114-Status: GOOD ( 17.97 ) X-Spam-Score: -4.2 (----) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: dmaengine@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-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When retrieving the residue value for cyclic transfers, the DST field of the active PaRAM is read. However, the AM335x Technical Reference Manual states: 11.3.3.6 Parameter Set Updates After the TR is read from the PaRAM (and is in the process of being submitted to the EDMA3TC), the following fields are updated as needed: ... DST This means the DST is incremented even though the DMA transfer may not have started yet or is in progress. Thus if the reader of the residue accesses the DMA buffer too quickly, the CPU will read where data is not yet written. The CCSTAT.ACTV register is a boolean that is set if any TR is being processed by either the EMDA3CC or EDMA3TC. By polling this register it is possible to ensure that the residue value returned is valid for immediate processing. Signed-off-by: John Ogness --- arch/arm/common/edma.c | 17 +++++++++++++++++ drivers/dma/edma.c | 8 ++++++++ include/linux/platform_data/edma.h | 1 + 3 files changed, 26 insertions(+) diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c index 873dbfc..86ce980 100644 --- a/arch/arm/common/edma.c +++ b/arch/arm/common/edma.c @@ -995,6 +995,23 @@ void edma_set_dest(unsigned slot, dma_addr_t dest_port, } EXPORT_SYMBOL(edma_set_dest); +#define EDMA_CCSTAT_ACTV (1 << 4) + +/** + * edma_is_actv - report if any transfer requests are active + * @slot: parameter RAM slot being examined + * + * Returns true if any transfer requests are active on the slot + */ +bool edma_is_actv(unsigned slot) +{ + u32 ctlr = EDMA_CTLR(slot); + unsigned int ccstat; + + ccstat = edma_read(ctlr, EDMA_CCSTAT); + return (ccstat & EDMA_CCSTAT_ACTV); +} + /** * edma_get_position - returns the current transfer point * @slot: parameter RAM slot being examined diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 3e5d4f1..493c774 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -891,6 +891,14 @@ static u32 edma_residue(struct edma_desc *edesc) pos = edma_get_position(edesc->echan->slot[0], dst); /* + * "pos" may represent a transfer request that is still being + * processed by the EDMACC or EDMATC. Wait until all transfer + * requests on the active slot are finished before proceeding. + */ + while (edma_is_actv(edesc->echan->slot[0])) + cpu_relax(); + + /* * Cyclic is simple. Just subtract pset[0].addr from pos. * * We never update edesc->residue in the cyclic case, so we diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h index bdb2710..20c50e2 100644 --- a/include/linux/platform_data/edma.h +++ b/include/linux/platform_data/edma.h @@ -130,6 +130,7 @@ void edma_set_src(unsigned slot, dma_addr_t src_port, enum address_mode mode, enum fifo_width); void edma_set_dest(unsigned slot, dma_addr_t dest_port, enum address_mode mode, enum fifo_width); +bool edma_is_actv(unsigned slot); dma_addr_t edma_get_position(unsigned slot, bool dst); void edma_set_src_index(unsigned slot, s16 src_bidx, s16 src_cidx); void edma_set_dest_index(unsigned slot, s16 dest_bidx, s16 dest_cidx);